From 07ea1c97ee891ea259020fe28fba317c20c3b03a Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 17 Oct 2026 20:17:27 -0400 Subject: [PATCH 1/9] process: fix bsd `spawn` --- lib/std/Io/Threaded.zig | 131 ++++++++++++++++++++++++---------------- lib/std/c.zig | 37 ++++++++---- test/src/Runner.zig | 11 ++-- 3 files changed, 110 insertions(+), 69 deletions(-) diff --git a/lib/std/Io/Threaded.zig b/lib/std/Io/Threaded.zig index c777c258127e4d72f38ff461f24c415d74b6e99b..44a716743d2a79ff675a4e39ccf630189acb1860 100644 --- a/lib/std/Io/Threaded.zig +++ b/lib/std/Io/Threaded.zig @@ -7191,9 +7191,9 @@ fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize { return n; }, .linux, .serenity, .illumos => { - var procfs_buf: ["/proc/self/path/-2147483648\x00".len]u8 = undefined; + var proc_buf: [std.fmt.count("/proc/self/path/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined; const template = if (native_os == .illumos) "/proc/self/path/{d}" else "/proc/self/fd/{d}"; - const proc_path = std.mem.printSentinel(&procfs_buf, template, .{fd}, 0) catch unreachable; + const proc_path = std.mem.printSentinel(&proc_buf, template, .{fd}, 0) catch unreachable; const syscall: Syscall = try .start(); while (true) { const rc = posix.system.readlink(proc_path, out_buffer.ptr, out_buffer.len); @@ -7266,27 +7266,32 @@ fn fileHardLink( new_sub_path: []const u8, options: File.HardLinkOptions, ) File.HardLinkError!void { - _ = userdata; - if (native_os != .linux) return error.OperationUnsupported; + const t: *Threaded = @ptrCast(@alignCast(userdata)); + _ = t; var new_path_buffer: [posix.PATH_MAX]u8 = undefined; const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer); - const flags: u32 = if (options.follow_symlinks) - posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH - else - posix.AT.EMPTY_PATH; + switch (native_os) { + else => return error.OperationUnsupported, + .freebsd, .linux => { + const flags: u32 = if (options.follow_symlinks) + posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH + else + posix.AT.EMPTY_PATH; - return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) { - error.FileNotFound => { - if (options.follow_symlinks) return error.FileNotFound; - var proc_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; - const proc_path = std.mem.printSentinel(&proc_buf, "/proc/self/fd/{d}", .{file.handle}, 0) catch - unreachable; - return linkat(posix.AT.FDCWD, proc_path, new_dir.handle, new_sub_path_posix, posix.AT.SYMLINK_FOLLOW); + return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) { + error.FileNotFound => {}, + else => |e| return e, + }; }, - else => |e| return e, - }; + .netbsd, .openbsd => {}, + } + + if (options.follow_symlinks) return error.FileNotFound; + var dev_buf: [std.fmt.count("/dev/fd/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined; + const dev_path = std.mem.printSentinel(&dev_buf, "/dev/fd/{d}", .{file.handle}, 0) catch unreachable; + return linkat(posix.AT.FDCWD, dev_path, new_dir.handle, new_sub_path_posix, posix.AT.SYMLINK_FOLLOW); } fn linkat( @@ -8732,12 +8737,12 @@ fn fchmodatFallback( ) Dir.SetFilePermissionsError!void { comptime assert(native_os == .linux); - // Fallback to changing permissions using procfs: + // Fallback to changing permissions using devfs: // // 1. Open `path` as a `PATH` descriptor. // 2. Stat the fd and check if it isn't a symbolic link. - // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`. - // 4. Pass the procfs path to `chmod` with the `mode`. + // 3. Generate the devfs reference to the fd via `/dev/fd/{fd}`. + // 4. Pass the devfs path to `chmod` with the `mode`. const path_fd: posix.fd_t = fd: { const syscall: Syscall = try .start(); while (true) { @@ -8808,11 +8813,11 @@ fn fchmodatFallback( if ((path_mode & posix.S.IFMT) == posix.S.IFLNK) return error.OperationUnsupported; - var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; - const proc_path = std.mem.printSentinel(&procfs_buf, "/proc/self/fd/{d}", .{path_fd}, 0) catch unreachable; + var dev_buf: [std.fmt.count("/dev/fd/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined; + const dev_path = std.mem.printSentinel(&dev_buf, "/dev/fd/{d}", .{path_fd}, 0) catch unreachable; const syscall: Syscall = try .start(); while (true) { - switch (posix.errno(posix.system.chmod(proc_path, mode))) { + switch (posix.errno(posix.system.chmod(dev_path, mode))) { .SUCCESS => return syscall.finish(), .INTR => { try syscall.checkCancel(); @@ -8821,7 +8826,7 @@ fn fchmodatFallback( else => |e| { syscall.finish(); switch (e) { - .NOENT => return error.OperationUnsupported, // procfs not mounted. + .NOENT => return error.OperationUnsupported, // devfs not mounted. .BADF => |err| return errnoBug(err), .FAULT => |err| return errnoBug(err), .INVAL => |err| return errnoBug(err), @@ -17446,9 +17451,6 @@ pub fn posixExecveat( ) process.ReplaceError { try Thread.checkCancel(); switch (err: { - if (path) |p| if (dir == posix.AT.FDCWD or Dir.path.isAbsoluteZ(p)) { - break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr)); - }; if (comptime native_os == .linux and (!builtin.link_libc or (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order( .{ .major = 2, .minor = 34, .patch = 0 }, @@ -17462,34 +17464,57 @@ pub fn posixExecveat( .NOSYS => {}, } } - var path_buffer: [posix.PATH_MAX]u8 = undefined; - var path_len = realPathPosix(dir, &path_buffer) catch |err| switch (err) { - else => |e| return e, - error.InputOutput, - error.FileTooBig, - error.NoSpaceLeft, - error.PathAlreadyExists, - error.SymLinkLoop, - error.NetworkNotFound, - error.PipeBusy, - error.AntivirusInterference, - => return error.FileNotFound, - error.DeviceBusy, - error.NoDevice, - error.UnrecognizedVolume, - => return error.FileSystem, + if (path) |p| if (dir == posix.AT.FDCWD or Dir.path.isAbsoluteZ(p)) { + break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr)); }; - if (path) |p| { - const path_slice = std.mem.span(p); - path_buffer[path_len] = Dir.path.sep; - path_len += 1; - @memcpy(path_buffer[path_len..][0..path_slice.len], path_slice); - path_len += path_slice.len; + const exe: posix.fd_t = if (path) |p| exe: { + var flags: posix.O = .{}; + if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true; + if (@hasField(posix.O, "LARGEFILE")) flags.LARGEFILE = true; + if (@hasField(posix.O, "NOCTTY")) flags.NOCTTY = true; + if (@hasField(posix.O, "PATH")) flags.PATH = true; + if (@hasField(posix.O, "EXEC")) flags.EXEC = true; + const rc = openat_sym(dir, p, flags, @as(posix.mode_t, 0)); + while (true) switch (posix.errno(rc)) { + .SUCCESS => break :exe @intCast(rc), + .INTR, .AGAIN => {}, + .FAULT => |err| return errnoBug(err), + .INVAL => return error.BadPathName, + .BADF => |err| return errnoBug(err), // File descriptor used after closed. + .ACCES => return error.AccessDenied, + .FBIG => return error.InvalidExe, + .OVERFLOW => return error.InvalidExe, + .ISDIR => return error.IsDir, + .LOOP => return error.InvalidExe, + .MFILE => return error.ProcessFdQuotaExceeded, + .NAMETOOLONG => return error.NameTooLong, + .NFILE => return error.SystemFdQuotaExceeded, + .NODEV => return error.FileSystem, + .NOENT => return error.FileNotFound, + .SRCH => return error.FileNotFound, // Linux when opening procfs files. + .NOMEM => return error.SystemResources, + .NOTDIR => return error.NotDir, + .PERM => return error.PermissionDenied, + .BUSY => return error.FileSystem, + .TXTBSY => return error.FileBusy, + .NXIO => return error.FileSystem, + .ILSEQ => return error.BadPathName, + else => |err| return posix.unexpectedErrno(err), + }; + } else dir; + defer closeFd(exe); + if (builtin.link_libc and @TypeOf(posix.system.fexecve) != void) { + break :err posix.errno(posix.system.fexecve(exe, argv, env_block.slice.ptr)); + } + switch (native_os) { + else => return error.OperationUnsupported, + .linux, .serenity, .illumos => { + var proc_buf: [std.fmt.count("/proc/self/path/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined; + const template = if (native_os == .illumos) "/proc/self/path/{d}" else "/proc/self/fd/{d}"; + const proc_path = std.mem.printSentinel(&proc_buf, template, .{exe}, 0) catch unreachable; + break :err posix.errno(posix.system.execve(proc_path, argv, env_block.slice.ptr)); + }, } - path_buffer[path_len] = 0; - break :err posix.errno( - posix.system.execve(path_buffer[0..path_len :0], argv, env_block.slice.ptr), - ); }) { .FAULT => |err| return errnoBug(err), // Bad pointer parameter. .@"2BIG" => return error.SystemResources, diff --git a/lib/std/c.zig b/lib/std/c.zig index 6969f4df8a4b1f3be8daf11923312c2f9a7c8a52..093cab3db16ad24142617d63aa02ad06c1a3e743 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -8387,6 +8387,8 @@ pub const AT = switch (native_os) { /// to determine the target of relative file paths in the openat() and /// similar syscalls. pub const FDCWD = -100; + /// Fail rename if target exists + pub const RENAME_NOREPLACE = 0x0001; /// Check access using effective user and group ID pub const EACCESS = 0x0100; /// Do not follow symbolic links @@ -8397,6 +8399,10 @@ pub const AT = switch (native_os) { pub const REMOVEDIR = 0x0800; /// Fail if not under dirfd pub const BENEATH = 0x1000; + /// Do not allow name resolution to walk out of dirfd + pub const RESOLVE_BENEATH = 0x2000; + /// Operate on dirfd if path is empty + pub const EMPTY_PATH = 0x4000; }, .netbsd => struct { /// Magic value that specify the use of the current working directory @@ -8552,7 +8558,11 @@ pub const O = switch (native_os) { DIRECTORY: bool = false, CLOEXEC: bool = false, SEARCH: bool = false, - _: u8 = 0, + NOSIGPIPE: bool = false, + REGULAR: bool = false, + EXEC: bool = false, + CLOFORK: bool = false, + _: u4 = 0, }, .openbsd => packed struct(u32) { ACCMODE: std.posix.ACCMODE = .RDONLY, @@ -10937,9 +10947,13 @@ pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: mode_t) c_int; pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int; pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; -pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; +pub extern "c" fn renameat(olddirfd: fd_t, oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int; pub extern "c" fn chdir(path: [*:0]const u8) c_int; pub extern "c" fn fchdir(fd: fd_t) c_int; +pub const fexecve = switch (native_os) { + else => {}, + .freebsd, .linux, .netbsd => private.fexecve, +}; pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; pub extern "c" fn execveat(dirfd: fd_t, path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8, flags: EXECVEAT) c_int; pub extern "c" fn dup(fd: fd_t) c_int; @@ -11791,34 +11805,35 @@ pub const setkeymap = serenity.setkeymap; /// External definitions shared by two or more operating systems. const private = struct { - pub extern "c" fn strdup(s: [*:0]const c_char) ?[*:0]c_char; - pub extern "c" fn _strdup(s: [*:0]const c_char) ?[*:0]c_char; - pub extern "c" fn wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t; - pub extern "c" fn _wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t; + extern "c" fn strdup(s: [*:0]const c_char) ?[*:0]c_char; + extern "c" fn _strdup(s: [*:0]const c_char) ?[*:0]c_char; + extern "c" fn wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t; + extern "c" fn _wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t; - pub extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void; - pub extern "c" fn _swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void; + extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void; + extern "c" fn _swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void; - extern "c" fn close(fd: fd_t) c_int; extern "c" fn clock_getres(clk_id: clockid_t, tp: *timespec) c_int; extern "c" fn clock_gettime(clk_id: clockid_t, tp: *timespec) c_int; + extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int; + extern "c" fn close(fd: fd_t) c_int; extern "c" fn copy_file_range(fd_in: fd_t, off_in: ?*i64, fd_out: fd_t, off_out: ?*i64, len: usize, flags: c_uint) isize; + extern "c" fn fexecve(fd: fd_t, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; extern "c" fn flock(fd: fd_t, operation: c_int) c_int; extern "c" fn fork() c_int; extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, buf: *Stat, flag: u32) c_int; extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) switch (native_os) { + else => c_int, .freebsd => isize, .illumos => usize, - else => c_int, }; extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int; - extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int; extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; extern "c" fn readdir(dir: *DIR) ?*dirent; extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8; diff --git a/test/src/Runner.zig b/test/src/Runner.zig index 0598fbaecd48053c1f8a166bc0eaefb516d4a435..66e204b4c5d1799ccbbd3ad956cfff1d72b635f6 100644 --- a/test/src/Runner.zig +++ b/test/src/Runner.zig @@ -822,7 +822,7 @@ fn handleCommand( .pic = pic, }; }) catch |err| switch (err) { - error.Canceled, error.OutOfMemory, error.AlreadyReported => |e| return e, + error.Canceled, error.OutOfMemory, error.AlreadyReported, error.SkipTest => |e| return e, error.ReadFailed => return error.ContentsReadFailed, }, .write => { @@ -1006,7 +1006,7 @@ fn spawnCompiler( output_mode: std.lang.OutputMode, args_r: *std.Io.Reader, target: Compiler.Target, -) (std.Io.Reader.ShortError || FailError)!void { +) (std.Io.Reader.ShortError || TestError)!void { const gpa = runner.gpa; const arena = runner.arena.allocator(); if (compiler.*) |*comp| { @@ -1118,6 +1118,7 @@ fn spawnCompiler( .stderr = .pipe, }) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, + error.OperationUnsupported => return error.SkipTest, else => |e| return runner.fail("unable to spawn compiler: {t}", .{e}), }; compiler.* = .{ @@ -1222,7 +1223,7 @@ const Compiler = struct { expected: []const u8, src_dir: std.Io.Dir, digest: *const std.Build.Cache.BinDigest, - ) FailError!void { + ) TestError!void { const runner = comp.runner; const gpa = runner.gpa; const arena = runner.arena.allocator(); @@ -1560,7 +1561,7 @@ const Compiler = struct { } } - fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) FailError![]const u8 { + fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) TestError![]const u8 { const runner = parent_comp.runner; const arena = runner.arena.allocator(); var compiler: ?Compiler = null; @@ -1577,7 +1578,7 @@ const Compiler = struct { .linker = .lld, .pic = parent_comp.target.pic, }) catch |err| switch (err) { - error.Canceled, error.OutOfMemory, error.AlreadyReported => |e| return e, + error.Canceled, error.OutOfMemory, error.AlreadyReported, error.SkipTest => |e| return e, error.ReadFailed => unreachable, // .fixed }; const comp = &compiler.?; -- 2.54.0 From baed9626d075628887b7d5400fb03efcb9910050 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 17 Oct 2026 00:30:53 -0400 Subject: [PATCH 2/9] Sema: check slice load for uninstantiable element type --- src/Sema.zig | 20 +++++++- test/behavior/slice.zig | 18 +++++++ .../load_uninstantiable_type.zig | 48 +++++++++++++++++++ .../iterate_slice_uninstantiable_enum.zig | 21 ++++++++ .../iterate_slice_uninstantiable_union.zig | 24 ++++++++++ ...zig => load_slice_uninstantiable_enum.zig} | 0 ...ig => load_slice_uninstantiable_union.zig} | 2 +- .../safety/load_uninstantiable_union.zig | 2 +- 8 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 test/cases/compile_errors/load_uninstantiable_type.zig create mode 100644 test/cases/safety/iterate_slice_uninstantiable_enum.zig create mode 100644 test/cases/safety/iterate_slice_uninstantiable_union.zig rename test/cases/safety/{load_uninstantiable_enum_from_slice.zig => load_slice_uninstantiable_enum.zig} (100%) rename test/cases/safety/{load_uninstantiable_union_from_slice.zig => load_slice_uninstantiable_union.zig} (93%) diff --git a/src/Sema.zig b/src/Sema.zig index 4904149cf0f1c47e59d0ee7e4d4c4e11307acf43..ca4ccd20c9652e741cfa7badfeafad4b8324338b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -27920,7 +27920,25 @@ fn elemValSlice( } } - if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); + switch (elem_ty.classify(zcu)) { + .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) { + .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(zcu)}), + else => { + // Loading an uninstantiable type always invokes Illegal Behavior. + if (block.isComptime()) { + return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(zcu)}); + } else if (block.wantSafety()) { + try sema.safetyPanic(block, src, .load_uninstantiable_type); + return .unreachable_value; + } else { + _ = try block.addNoOp(.unreach); + return .unreachable_value; + } + }, + }, + .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?), + .runtime, .partially_comptime, .fully_comptime => {}, + } try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src); try sema.validateRuntimeValue(block, slice_src, slice); diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index b1feb5433000f68a3d54c4e4555bb07cfa75f5dd..6f521a724349c176e5ff693c521394d0fca9d73b 100644 --- a/test/behavior/slice.zig +++ b/test/behavior/slice.zig @@ -1209,3 +1209,21 @@ test "modify slice through coerced array pointer" { assert(slice[2] == 0); } } + +test "iterate empty slice of uninstantiable types" { + const E = enum {}; + var slice_enum: []const E = undefined; + slice_enum = &.{}; + for (slice_enum) |elem| { + _ = elem; + return error.ReachedUnreachable; + } + + const U = union { foo: struct { a: u8, b: noreturn }, bar: E }; + var slice_union: []const U = undefined; + slice_union = &.{}; + for (slice_union) |elem| { + _ = elem; + return error.ReachedUnreachable; + } +} diff --git a/test/cases/compile_errors/load_uninstantiable_type.zig b/test/cases/compile_errors/load_uninstantiable_type.zig new file mode 100644 index 0000000000000000000000000000000000000000..7b68d2330c91356a1640a115ecfe53aad68a6762 --- /dev/null +++ b/test/cases/compile_errors/load_uninstantiable_type.zig @@ -0,0 +1,48 @@ +const E = enum {}; +const U = union { + foo: struct { a: u8, b: noreturn }, + bar: E, +}; +export fn loadSliceUninstantiableEnum() void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]E = @ptrCast(&bytes); + const slice: []const E = ptr; + _ = comptime slice[0]; + comptime unreachable; +} +export fn iterateSliceUninstantiableEnum() void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]E = @ptrCast(&bytes); + const slice: []const E = ptr; + comptime for (slice) |elem| { + _ = elem; + }; + comptime unreachable; +} +export fn loadSliceUninstantiableUnion() void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]U = @ptrCast(&bytes); + const slice: []const U = ptr; + _ = comptime slice[0]; + comptime unreachable; +} +export fn iterateSliceUninstantiableUnion() void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]U = @ptrCast(&bytes); + const slice: []const U = ptr; + comptime for (slice) |elem| { + _ = elem; + }; + comptime unreachable; +} + +// error +// +// :10:23: error: cannot load uninstantiable type 'tmp.E' +// :1:11: note: enum declared here +// :17:19: error: cannot load uninstantiable type 'tmp.E' +// :1:11: note: enum declared here +// :26:23: error: cannot load uninstantiable type 'tmp.U' +// :2:11: note: union declared here +// :33:19: error: cannot load uninstantiable type 'tmp.U' +// :2:11: note: union declared here diff --git a/test/cases/safety/iterate_slice_uninstantiable_enum.zig b/test/cases/safety/iterate_slice_uninstantiable_enum.zig new file mode 100644 index 0000000000000000000000000000000000000000..09093930e66113bfe3b51ab34633d59fcae74457 --- /dev/null +++ b/test/cases/safety/iterate_slice_uninstantiable_enum.zig @@ -0,0 +1,21 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const E = enum {}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]E = @ptrCast(&bytes); + const slice: []const E = ptr; + for (slice) |elem| _ = elem; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/iterate_slice_uninstantiable_union.zig b/test/cases/safety/iterate_slice_uninstantiable_union.zig new file mode 100644 index 0000000000000000000000000000000000000000..b6841dbc7005fbd15e73deb183228ad6850e8f4f --- /dev/null +++ b/test/cases/safety/iterate_slice_uninstantiable_union.zig @@ -0,0 +1,24 @@ +const std = @import("std"); + +pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn { + _ = stack_trace; + if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) { + std.process.exit(0); + } + std.process.exit(1); +} + +const U = union { + foo: struct { a: u8, b: noreturn }, + bar: enum {}, +}; +pub fn main() error{TestFailed}!void { + const bytes: [32]u8 = @splat(0); + const ptr: *const [1]U = @ptrCast(&bytes); + const slice: []const U = ptr; + for (slice) |elem| _ = elem; + return error.TestFailed; +} +// run +// backend=selfhosted,llvm +// target=x86_64-linux,aarch64-linux,wasm32-wasi diff --git a/test/cases/safety/load_uninstantiable_enum_from_slice.zig b/test/cases/safety/load_slice_uninstantiable_enum.zig similarity index 100% rename from test/cases/safety/load_uninstantiable_enum_from_slice.zig rename to test/cases/safety/load_slice_uninstantiable_enum.zig diff --git a/test/cases/safety/load_uninstantiable_union_from_slice.zig b/test/cases/safety/load_slice_uninstantiable_union.zig similarity index 93% rename from test/cases/safety/load_uninstantiable_union_from_slice.zig rename to test/cases/safety/load_slice_uninstantiable_union.zig index 844bfd0b7d766bfb9e5eb0f911061eda7bace0d6..1f7264526ed4518198a3c797110515971ac2dbc1 100644 --- a/test/cases/safety/load_uninstantiable_union_from_slice.zig +++ b/test/cases/safety/load_slice_uninstantiable_union.zig @@ -9,7 +9,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usi } const U = union { - foo: struct { a: u8, b: noreturn, }, + foo: struct { a: u8, b: noreturn }, bar: enum {}, }; pub fn main() error{TestFailed}!void { diff --git a/test/cases/safety/load_uninstantiable_union.zig b/test/cases/safety/load_uninstantiable_union.zig index 87f84e07c7f624104d797b94037fc6148491265b..9e673d3958bd8ec11c39033f0d5e3688ddaca79e 100644 --- a/test/cases/safety/load_uninstantiable_union.zig +++ b/test/cases/safety/load_uninstantiable_union.zig @@ -9,7 +9,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usi } const U = union { - foo: struct { a: u8, b: noreturn, }, + foo: struct { a: u8, b: noreturn }, bar: enum {}, }; pub fn main() error{TestFailed}!void { -- 2.54.0 From 77576c960388f0ad6712f1e15b97ca689892d708 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 16 Oct 2026 18:36:25 -0400 Subject: [PATCH 3/9] lldb/pretty_printers.py: support new `MultiArrayList.pointer_stability` Also fix unwrapped printing of reified union types. --- lib/lldb/pretty_printers.py | 149 ++++++++++++++++++++++++------------ src/InternPool.zig | 3 + 2 files changed, 102 insertions(+), 50 deletions(-) diff --git a/lib/lldb/pretty_printers.py b/lib/lldb/pretty_printers.py index 8246b583607273384aec2d5779dd500acc45da65..54c5e91327d5a3c04a26d9bae606d1b14cab76e4 100644 --- a/lib/lldb/pretty_printers.py +++ b/lib/lldb/pretty_printers.py @@ -13,34 +13,73 @@ page_size = 1 << 12 def log2_int(i): return i.bit_length() - 1 -def create_struct(parent, name, struct_type, inits): - struct_bytes, struct_data = bytearray(struct_type.size), lldb.SBData() - for field in struct_type.fields: - field_size = field.type.size - field_init = inits[field.name] - if isinstance(field_init, int): - match struct_data.byte_order: - case lldb.eByteOrderLittle: - byte_order = 'little' - case lldb.eByteOrderBig: - byte_order = 'big' - field_bytes = field_init.to_bytes(field_size, byte_order, signed=field.type.GetTypeFlags() & lldb.eTypeIsSigned != 0) - elif isinstance(field_init, lldb.SBValue): - field_bytes = field_init.data.uint8 - else: return - match struct_data.byte_order: +class ValueInit: + def __init__(self, value: lldb.SBValue): self.value = value + def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes: + return self.value.data.uint8 + def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue: + return self.value.Clone(name) + +class FromBytes(ValueInit): + def __init__(self, value_bytes: bytes): self.value_bytes = value_bytes + def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes: return self.value_bytes + def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue: + data = lldb.SBData() + error = lldb.SBError() + value_bytes = self.toBytes(parent, value_type); + target = parent.target + data.SetData(error, value_bytes, target.byte_order, target.addr_size) + return parent.CreateValueFromData(name, data, value_type) + +class IntLiteral(FromBytes): + def __init__(self, int_value: int): self.int_value = int_value + def toBytes(self, parent: lldb.SBValue, int_type: lldb.SBType) -> bytes: + int_flags = int_type.GetTypeFlags() + assert int_flags & lldb.eTypeIsInteger != 0 + int_is_signed = int_flags & lldb.eTypeIsSigned != 0 + match parent.target.byte_order: case lldb.eByteOrderLittle: - field_bytes = field_bytes[:field_size] - field_start = field.byte_offset - struct_bytes[field_start:field_start + len(field_bytes)] = field_bytes + byte_order = 'little' case lldb.eByteOrderBig: - field_bytes = field_bytes[-field_size:] - field_end = field.byte_offset + field_size - struct_bytes[field_end - len(field_bytes):field_end] = field_bytes - struct_data.SetData(lldb.SBError(), struct_bytes, struct_data.byte_order, struct_data.GetAddressByteSize()) - return parent.CreateValueFromData(name, struct_data, struct_type) + byte_order = 'big' + return self.int_value.to_bytes(int_type.size, byte_order, signed=int_is_signed) -# Define Zig Language +class FromBackingInt(FromBytes): + def __init__(self, field_value: int): self.field_value = field_value + def fieldValue(self, enum_type: lldb.SBType) -> int: return self.field_value + def toBytes(self, parent: lldb.SBValue, enum_type: lldb.SBType) -> bytes: + assert enum_type.type == lldb.eTypeClassEnumeration + backing_int = IntLiteral(self.fieldValue(enum_type)); + return backing_int.toBytes(parent, enum_type.GetEnumerationIntegerType()) + +class EnumField(FromBackingInt): + def __init__(self, field_index: int): self.field_index = field_index + def fieldIndex(self, enum_type: lldb.SBType) -> int: return self.field_index + def fieldValue(self, enum_type: lldb.SBType) -> int: + enum_is_signed = enum_type.GetEnumerationIntegerType().GetTypeFlags() & lldb.eTypeIsSigned != 0 + field = enum_type.enum_members[self.fieldIndex(enum_type)] + return field.signed if enum_is_signed else field.unsigned + +class EnumLiteral(EnumField): + def __init__(self, field_name: str): self.field_name = field_name + def fieldName(self, enum_type: lldb.SBType) -> str: return self.field_name + def fieldIndex(self, enum_type: lldb.SBType) -> int: + field_name = self.fieldName(enum_type) + return next(field_index for field_index, field in enumerate(enum_type.enum_members) + if field.name == field_name) + +class StructInit(FromBytes): + def __init__(self, field_inits: dict[str, ValueInit]): self.field_inits = field_inits + def toBytes(self, parent: lldb.SBValue, struct_type: lldb.SBType) -> bytes: + assert struct_type.type == lldb.eTypeClassStruct + struct_bytes = bytearray(struct_type.size) + for field in struct_type.fields: + field_bytes = self.field_inits[field.name].toBytes(parent, field.type) + assert len(field_bytes) == field.type.size + struct_bytes[field.byte_offset:field.byte_offset + len(field_bytes)] = field_bytes + return bytes(struct_bytes) + +# Define Zig Language (for programs compiled with the llvm backend) zig_keywords = { 'addrspace', @@ -204,7 +243,7 @@ class zig_TaggedUnion_SynthProvider: except: return -1 def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None -# Define Zig Standard Library +# Define Zig Standard Library (for programs compiled with the llvm backend) class std_MultiArrayList_SynthProvider: def __init__(self, value, _=None): self.value = value @@ -331,7 +370,7 @@ class std_Entry_SynthProvider: def get_child_index(self, name): return self.indices.get(name) def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None -# Define Zig Compiler +# Define Zig Compiler (compiled with the llvm backend) class TagAndPayload_SynthProvider: def __init__(self, value, _=None): self.value = value @@ -435,8 +474,9 @@ class InternPool_Index_SynthProvider: def __init__(self, value, _=None): self.value = value def update(self): try: + target = self.value.target index_type = self.value.type - for helper in self.value.target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull): + for helper in target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull): ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes() if ptr_self_type.GetPointeeType() == index_type: break else: return @@ -465,7 +505,7 @@ class InternPool_Index_SynthProvider: for trailing_field in encoding_field.type.fields: trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data) trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned - trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, trailing_data.GetAddressByteSize())) + trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, target.addr_size, target=target)) extra_index += trailing_len self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type) else: @@ -685,8 +725,18 @@ value_tag_handlers = { class root_InternPool_Local_List_SynthProvider: def __init__(self, value, _=None): self.value = value def update(self): - capacity = self.value.EvaluateExpression('@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity') - self.view = create_struct(self.value, '.view', self.value.type.FindDirectNestedType('View'), { 'bytes': self.value.GetChildMemberWithName('bytes'), 'len': capacity, 'capacity': capacity }).GetNonSyntheticValue() + capacity = IntLiteral(self.value.EvaluateExpression( + '@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity', + ).unsigned) + View = self.value.type.FindDirectNestedType('View') + self.view = StructInit({ + 'bytes': ValueInit(self.value.GetChildMemberWithName('bytes')), + 'len': capacity, + 'capacity': capacity, + 'pointer_stability': StructInit({ + 'state': EnumField(0), + }), + }).create(self.value, '.view', View).GetNonSyntheticValue() def has_children(self): return True def num_children(self): return 1 def get_child_index(self, name): @@ -719,7 +769,10 @@ class root_InternPool_Index_SynthProvider: unwrapped_type = self.value.type.FindDirectNestedType('Unwrapped') ip = self.value.CreateValueFromType(unwrapped_type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?') tid_shift_30 = ip.GetChildMemberWithName('tid_shift_30').unsigned - self.unwrapped = create_struct(self.value, '.unwrapped', unwrapped_type, { 'tid': wrapped >> tid_shift_30, 'index': wrapped & (1 << tid_shift_30) - 1 }) + self.unwrapped = StructInit({ + 'tid': FromBackingInt(wrapped >> tid_shift_30), + 'index': IntLiteral(wrapped & (1 << tid_shift_30) - 1), + }).create(self.value, '.unwrapped', unwrapped_type) def has_children(self): return True def num_children(self): return 0 def get_child_index(self, name): @@ -732,6 +785,7 @@ class root_InternPool_Index_SynthProvider: class root_InternPool_Index_Unwrapped_SynthProvider: def __init__(self, value, _=None): self.value = value def update(self): + target = self.value.target self.tag, self.index, self.data, self.payload, self.trailing = None, None, None, None, None index = self.value.GetChildMemberWithName('index') ip = self.value.CreateValueFromType(self.value.type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?') @@ -742,36 +796,34 @@ class root_InternPool_Index_Unwrapped_SynthProvider: encoding_index, encoding_data, encoding_payload, encoding_trailing, encoding_config = encoding.GetChildMemberWithName('index'), encoding.GetChildMemberWithName('data'), encoding.GetChildMemberWithName('payload'), encoding.GetChildMemberWithName('trailing'), encoding.GetChildMemberWithName('config') if encoding_index: index_type = encoding_index.GetValueAsType() - index_bytes, index_data = index.data.uint8, lldb.SBData() - match index_data.byte_order: + index_bytes = index.data.uint8 + match target.byte_order: case lldb.eByteOrderLittle: index_bytes = bytes(index_bytes[:index_type.size]) case lldb.eByteOrderBig: index_bytes = bytes(index_bytes[-index_type.size:]) - index_data.SetData(lldb.SBError(), index_bytes, index_data.byte_order, index_data.GetAddressByteSize()) - self.index = self.value.CreateValueFromData('.index', index_data, index_type) + self.index = FromBytes(index_bytes).create(self.value, '.index', index_type) elif encoding_data: data_type = encoding_data.GetValueAsType() - data_bytes, data_data = item_data.data.uint8, lldb.SBData() - match data_data.byte_order: + data_bytes = item_data.data.uint8 + match target.byte_order: case lldb.eByteOrderLittle: data_bytes = bytes(data_bytes[:data_type.size]) case lldb.eByteOrderBig: data_bytes = bytes(data_bytes[-data_type.size:]) - data_data.SetData(lldb.SBError(), data_bytes, data_data.byte_order, data_data.GetAddressByteSize()) - self.data = self.value.CreateValueFromData('.data', data_data, data_type) + self.data = FromBytes(data_bytes).create(self.value, '.data', data_type) elif encoding_payload: extra = shared.GetChildMemberWithName('extra').GetChildMemberWithName('view').GetChildMemberWithName('0') extra_index = item_data.unsigned payload_type = encoding_payload.GetValueAsType() payload_fields = dict() for payload_field in payload_type.fields: - payload_fields[payload_field.name] = extra.child[extra_index] + payload_fields[payload_field.name] = ValueInit(extra.child[extra_index]) extra_index += 1 - self.payload = create_struct(self.value, '.payload', payload_type, payload_fields) + self.payload = StructInit(payload_fields).create(self.value, '.payload', payload_type) if encoding_trailing and encoding_config: trailing_type = encoding_trailing.GetValueAsType() - trailing_bytes, trailing_data = bytearray(trailing_type.size), lldb.SBData() + trailing_bytes = bytearray(trailing_type.size) def eval_config(config_name): expr = encoding_config.GetChildMemberWithName(config_name).value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"') if 'payload.' in expr: @@ -780,13 +832,11 @@ class root_InternPool_Index_Unwrapped_SynthProvider: field_type, field_byte_offset = trailing_type, 0 expr_parts = expr.split('.') for expr_part in expr_parts[1:]: - field = next(filter(lambda field: field.name == expr_part, field_type.fields)) + field = next(field for field in field_type.fields if field.name == expr_part) field_type = field.type field_byte_offset += field.byte_offset - field_data = lldb.SBData() field_bytes = trailing_bytes[field_byte_offset:field_byte_offset + field_type.size] - field_data.SetData(lldb.SBError(), field_bytes, field_data.byte_order, field_data.GetAddressByteSize()) - return self.value.CreateValueFromData('.%s' % expr_parts[-1], field_data, field_type) + return FromBytes(field_bytes).create(self.value, '.%s' % expr_parts[-1], field_type) else: return self.value.frame.EvaluateExpression(expr) for trailing_field in trailing_type.fields: @@ -812,7 +862,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider: trailing_bytes[ptr_field_byte_offset:ptr_field_byte_offset + ptr_field.type.size] = extra.child[extra_index].address_of.data.uint8 len_field_value = eval_config('%s.len' % trailing_field_name) len_field_size = len_field.type.size - match trailing_data.byte_order: + match target.byte_order: case lldb.eByteOrderLittle: len_field_bytes = len_field_value.data.uint8[:len_field_size] trailing_bytes[len_field_byte_offset:len_field_byte_offset + len(len_field_bytes)] = len_field_bytes @@ -827,8 +877,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider: trailing_bytes[trailing_field_byte_offset + offset:trailing_field_byte_offset + offset + 4] = extra.child[extra_index].data.uint8 extra_index += 1 break - trailing_data.SetData(lldb.SBError(), trailing_bytes, trailing_data.byte_order, trailing_data.GetAddressByteSize()) - self.trailing = self.value.CreateValueFromData('.trailing', trailing_data, trailing_type) + self.trailing = FromBytes(trailing_bytes).create(self.value, '.trailing', trailing_type) def has_children(self): return True def num_children(self): return 1 + ((self.index or self.data or self.payload) is not None) + (self.trailing is not None) def get_child_index(self, name): diff --git a/src/InternPool.zig b/src/InternPool.zig index 88c454fc2f3b414710886a524c80f4ecc7b09134..ad7c65bff970b9dc7a5666c56949312fef15663e 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -5255,6 +5255,7 @@ pub const Tag = enum(u8) { type_hash: ?u64, captures_len: ?u32, captures: ?[]CaptureValue, + reified_field_name: ?[]NullTerminatedString, field_types: []Index, field_aligns: ?[]Alignment, }, @@ -5263,6 +5264,8 @@ pub const Tag = enum(u8) { .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true", .@"trailing.captures.?" = .@"payload.flags.any_captures == .true", .@"trailing.captures.?.len" = .@"trailing.captures_len.?", + .@"trailing.reified_field_name.?" = .@"payload.flags.any_captures == .reified", + .@"trailing.reified_field_name.?.len" = .@"payload.fields_len", .@"trailing.field_types.len" = .@"payload.fields_len", .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns", .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) & ~@as(u32, 3)", -- 2.54.0 From f08a8f0fc217914690a58035291da8bcc7a86e47 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 8 Oct 2026 01:49:12 -0400 Subject: [PATCH 4/9] main: reimplement compiler debug flags * Add `.llvmbc`/`.llvmir` to `ObjectFormat` for emitting unoptimized IR * Replace `--verbose-air`, `--verbose-intern-pool`, `--verbose-generic-instances`, `--verbose-llvm-ir`, and `--verbose-llvm-bc` with various `--debug-log` scopes * `--debug-log illegal-air`: pre-legalized Air * `--debug-log legal-air`: post-legalized Air * `--debug-log air`: final Air with liveness * `--debug-log ip-stats`: InternPool statistics * `--debug-log ip-values`: InternPool values * `--debug-log ip-generic-instances`: InternPool generic instances * `--debug-log llvm-ir`: pre-optimized LLVM IR * `--debug-log opt-llvm-ir`: post-optimized LLVM IR * Delete `--verbose-cimport` which does nothing * Delete `--verbose-llvm-cpu-features` which is equivalent to looking at the outputs of `--show-builtin` and `--debug-log llvm-ir` --- CMakeLists.txt | 2 +- bootstrap.c | 2 +- build.zig | 24 +++-- lib/compiler/Maker.zig | 4 - lib/compiler/Maker/Graph.zig | 3 - lib/compiler/Maker/ScannedConfig.zig | 8 +- lib/compiler/Maker/Step/Compile.zig | 5 +- lib/compiler/aro/aro/Driver.zig | 2 +- lib/std/Build/Configuration.zig | 2 + lib/std/Target.zig | 6 ++ lib/std/debug.zig | 2 +- lib/std/fmt.zig | 8 +- lib/std/zig.zig | 2 + lib/std/zig/llvm/Builder.zig | 21 +++-- src/Air.zig | 10 +-- src/Air/{print.zig => Print.zig} | 15 +++- src/Compilation.zig | 112 ++++++------------------ src/Compilation/Config.zig | 8 +- src/InternPool.zig | 60 +++++++------ src/Module.zig | 19 ++-- src/Sema.zig | 8 +- src/Zcu/PerThread.zig | 58 +++++-------- src/codegen/llvm.zig | 125 ++++++++++++++------------- src/codegen/llvm/bindings.zig | 5 +- src/codegen/riscv64/CodeGen.zig | 2 +- src/codegen/x86_64/CodeGen.zig | 2 +- src/dev.zig | 2 + src/libs/freebsd.zig | 4 - src/libs/glibc.zig | 4 - src/libs/libcxx.zig | 8 -- src/libs/libtsan.zig | 4 - src/libs/libunwind.zig | 4 - src/libs/musl.zig | 3 - src/libs/netbsd.zig | 4 - src/libs/openbsd.zig | 4 - src/link.zig | 39 ++++++++- src/link/Elf.zig | 4 +- src/link/Elf/ZigObject.zig | 2 +- src/link/Elf/gc.zig | 2 +- src/link/Elf/relocatable.zig | 14 +-- src/link/MachO.zig | 4 +- src/link/MachO/dead_strip.zig | 3 +- src/link/MachO/relocatable.zig | 12 +-- src/main.zig | 114 +++++++++--------------- src/target.zig | 2 + src/zig_llvm.cpp | 8 +- src/zig_llvm.h | 8 +- stage1/config.zig.in | 2 +- 48 files changed, 347 insertions(+), 419 deletions(-) rename src/Air/{print.zig => Print.zig} (98%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 48878a454f61f24ab78f47c56974240cefc61b54..fd8a347004186d9f6fd3ab9b16b5c2b438165556 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES src/Air/Legalize.zig src/Air/Liveness.zig src/Air/Liveness/Verify.zig - src/Air/print.zig + src/Air/Print.zig src/Builtin.zig src/Compilation.zig src/Compilation/Config.zig diff --git a/bootstrap.c b/bootstrap.c index 4e41d2ebdc8a0839182901b33e6214ad3f6ae3f4..eaa506c32fc6b76dcaedd5061c629ad32d2bd31b 100644 --- a/bootstrap.c +++ b/bootstrap.c @@ -179,7 +179,7 @@ int main(int argc, char **argv) { "pub const version: [:0]const u8 = \"%s\";\n" "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n" "pub const enable_debug_extensions = false;\n" - "pub const enable_logging = false;\n" + "pub const log_level: @import(\"std\").log.Level = .err;\n" "pub const enable_link_snapshots = false;\n" "pub const enable_tracy = false;\n" "pub const value_tracing = false;\n" diff --git a/build.zig b/build.zig index 39bb16c0a0b03001e30797a19f33be2e92e764d0..bcd0f50975e906c61a9e2649e933ac8350da5d43 100644 --- a/build.zig +++ b/build.zig @@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void { }, }); const optimize = b.standardOptimizeOption(.{}); + const is_debug = switch (optimize) { + .debug => true, + .safe, .fast, .small => false, + }; const flat = b.option(bool, "flat", "Put files into the installation prefix in a manner suited for upstream distribution rather than a posix file system hierarchy standard") orelse false; const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode"); @@ -205,9 +209,9 @@ pub fn build(b: *std.Build) !void { const value_tracing = b.option(bool, "value-tracing", "Enable extra state tracking to help troubleshoot bugs in the compiler (using the std.debug.Trace API)") orelse false; const mem_leak_frames: u32 = b.option(u32, "mem-leak-frames", "How many stack frames to print when a memory leak occurs. Tests get 2x this amount.") orelse blk: { - if (strip == true) break :blk @as(u32, 0); - if (optimize != .debug) break :blk 0; - break :blk 4; + if (strip == true) break :blk 0; + if (is_debug) break :blk 4; + break :blk 0; }; const exe = addCompilerStep(b, .{ @@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void { exe.root_module.link_libc = true; } - const is_debug = optimize == .debug; const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug; - const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug; + const log_level: std.log.Level = b.option(std.log.Level, "log", "Enable logs of the given or higher severity. Passing 'debug' still requires passing '--debug-log' to actually see any debug logs.") orelse switch (enable_debug_extensions) { + true => .debug, + false => switch (optimize) { + .debug => .debug, + .safe, .fast => .info, + .small => .err, + }, + }; const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); const version_slice = if (opt_version_string) |version| version else v: { @@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void { exe_options.addOption(std.SemanticVersion, "semver", semver); exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions); - exe_options.addOption(bool, "enable_logging", enable_logging); + exe_options.addOption(std.log.Level, "log_level", log_level); exe_options.addOption(bool, "enable_tracy", tracy != null); exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); @@ -837,7 +847,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { exe_options.addOption([:0]const u8, "version", version); exe_options.addOption(std.SemanticVersion, "semver", semver); exe_options.addOption(bool, "enable_debug_extensions", false); - exe_options.addOption(bool, "enable_logging", false); + exe_options.addOption(std.log.Level, "log_level", .err); exe_options.addOption(bool, "enable_tracy", false); exe_options.addOption(bool, "enable_tracy_callstack", false); exe_options.addOption(bool, "enable_tracy_allocation", false); diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index 149bf0a63f4bc135a8217527df64944d5edaa70e..e0ce8142628ad4aac0466293869eaa9f7bab225d 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void { } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) { // --glibc-runtimes was the old name of the flag; kept for compatibility for now. graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i); - } else if (mem.eql(u8, arg, "--verbose-air")) { - graph.verbose_air = true; } else if (mem.eql(u8, arg, "--verbose-cc")) { graph.verbose_cc = true; } else if (mem.eql(u8, arg, "--verbose-link")) { graph.verbose_link = true; - } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { - graph.verbose_llvm_ir = true; } else if (mem.eql(u8, arg, "--watch")) { watch_flag = true; } else if (mem.eql(u8, arg, "--time-report")) { diff --git a/lib/compiler/Maker/Graph.zig b/lib/compiler/Maker/Graph.zig index ec4159991a7bae901142726540bd9cfddd08688e..2ba152591230df002e64ca6eaa59255b0b0379ea 100644 --- a/lib/compiler/Maker/Graph.zig +++ b/lib/compiler/Maker/Graph.zig @@ -32,11 +32,8 @@ debug_compile_errors: bool = false, debug_incremental: bool = false, fuzzing: bool = false, verbose: bool = false, -verbose_air: bool = false, verbose_cc: bool = false, verbose_link: bool = false, -verbose_llvm_cpu_features: bool = false, -verbose_llvm_ir: bool = false, libc_file: ?[]const u8 = null, /// What does this do? Nobody bothered to document it, and I think it's a /// smelly option. So unless somebody deletes these passive aggressive comments diff --git a/lib/compiler/Maker/ScannedConfig.zig b/lib/compiler/Maker/ScannedConfig.zig index 4e83388ee9f094c98a36e79f504e76b37fb9f148..c516bfb00dcde9adba92d6b47a7cb8d136afdc1f 100644 --- a/lib/compiler/Maker/ScannedConfig.zig +++ b/lib/compiler/Maker/ScannedConfig.zig @@ -351,6 +351,8 @@ const general_usage = \\ preferred optimization mode: fast, safe, small \\ \\ --verbose Print commands before executing them + \\ --verbose-cc Print C compiler commands before executing them + \\ --verbose-link Print linker commands before executing them \\ --color [auto|off|on] Enable or disable colored error messages \\ --error-style [style] Control how build errors are printed \\ verbose (Default) Report errors with full context @@ -417,11 +419,5 @@ const general_usage = \\ none (default) No build ID \\ --debug-log [scope] Enable debugging the compiler \\ --debug-pkg-config Fail if unknown pkg-config flags encountered - \\ --verbose-link Enable compiler debug output for linking - \\ --verbose-air Enable compiler debug output for Zig AIR - \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR - \\ --verbose-cimport Enable compiler debug output for C imports - \\ --verbose-cc Enable compiler debug output for C compilation - \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features \\ ; diff --git a/lib/compiler/Maker/Step/Compile.zig b/lib/compiler/Maker/Step/Compile.zig index 1c8cdc9db4c94aae76542ef3e43d36f1fc6c190c..7e25860277b72a91cf62d23877325cd41ef85a09 100644 --- a/lib/compiler/Maker/Step/Compile.zig +++ b/lib/compiler/Maker/Step/Compile.zig @@ -608,11 +608,8 @@ fn lowerZigArgs( try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors); try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental); - try addBool(gpa, zig_args, "--verbose-air", graph.verbose_air); - try addBool(gpa, zig_args, "--verbose-llvm-ir", graph.verbose_llvm_ir); - try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link); try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc); - try addBool(gpa, zig_args, "--verbose-llvm-cpu-features", graph.verbose_llvm_cpu_features); + try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link); try addBool(gpa, zig_args, "--time-report", graph.time_report); if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin"); diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index 676f7397fd3a3560d86e11478a9de5b39ad10a1d..b41a7a191135c0ee0402b90ac2e54e631f641c3a 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -927,7 +927,7 @@ pub fn parseArgs( break :debug switch (d.comp.target.ofmt) { .elf, .macho, .wasm => .{ .dwarf = .@"32" }, .coff => .code_view, - .c => switch (d.comp.target.os.tag) { + .c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) { .windows, .uefi => .code_view, else => .{ .dwarf = .@"32" }, }, diff --git a/lib/std/Build/Configuration.zig b/lib/std/Build/Configuration.zig index e85e19cd1e7d7ba37128ab208de61e4e39690a3e..c22dd975a4d88c981455431c96df23950594fe02 100644 --- a/lib/std/Build/Configuration.zig +++ b/lib/std/Build/Configuration.zig @@ -2519,6 +2519,8 @@ pub const TargetQuery = struct { coff, elf, hex, + llvmbc, + llvmir, macho, plan9, raw, diff --git a/lib/std/Target.zig b/lib/std/Target.zig index bba3026b739c3dfd1da086be5ac6114513f83a01..cc75e0ab49dd714197dd8cb197dc0b9b3049b5dd 100644 --- a/lib/std/Target.zig +++ b/lib/std/Target.zig @@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum { elf, /// The Intel HEX format for storing binary code in ASCII text. hex, + /// LLVM binary intermediate representation. + llvmbc, + /// LLVM text intermediate representation. + llvmir, /// The Mach object format used by macOS and other Apple platforms. macho, /// The a.out format used by Plan 9 from Bell Labs. @@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum { .coff => ".obj", .elf, .macho, .wasm => ".o", .hex => ".ihex", + .llvmbc => ".bc", + .llvmir => ".ll", .plan9 => arch.plan9Ext(), .raw => ".bin", .spirv => ".spv", diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 37a3f0d7594c8190fd1fa27060a76f7512ac55d3..0822957bc98e790b17f8b00835661bf0ba7f6ba1 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type { }, .macho => @import("debug/SelfInfo/MachO.zig"), .plan9, .spirv, .wasm, .raw, .hex => void, - .c => unreachable, + .c, .llvmbc, .llvmir => unreachable, }; } diff --git a/lib/std/fmt.zig b/lib/std/fmt.zig index 1b90c2cff3e96e923e263884a200597251fe6298..a21a82d77883d18031b36735ca4ca3a42ee29972 100644 --- a/lib/std/fmt.zig +++ b/lib/std/fmt.zig @@ -285,7 +285,13 @@ pub fn Alt( pub fn alt( context: anytype, comptime func_name: @EnumLiteral(), -) Alt(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) { +) Alt(@TypeOf(context), @field(switch (@typeInfo(@TypeOf(context))) { + else => @TypeOf(context), + .pointer => |pointer| switch (pointer.size) { + else => @TypeOf(context), + .one => pointer.child, + }, +}, @tagName(func_name))) { return .{ .data = context }; } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index b1537b6c166e6cd73c57447d993f219c4274f22a..db8fa41d8c48651220bb676d1540838d67b80dba 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe }, .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}), }, + .llvmbc => return std.fmt.allocPrint(allocator, "{s}.bc", .{root_name}), + .llvmir => return std.fmt.allocPrint(allocator, "{s}.ll", .{root_name}), .macho => switch (options.output_mode) { .Exe => return allocator.dupe(u8, root_name), .Lib => { diff --git a/lib/std/zig/llvm/Builder.zig b/lib/std/zig/llvm/Builder.zig index 2722d5d62f0cbf7503aadda61ac5e23e28bd5967..16a4f283ce6ccf976af56428e5ac996c94138bdf 100644 --- a/lib/std/zig/llvm/Builder.zig +++ b/lib/std/zig/llvm/Builder.zig @@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va b.alignment_forward_references.items[index] = value; } -pub fn dump(b: *Builder, io: Io) void { - var buffer: [4000]u8 = undefined; - const stderr: Io.File = .stderr(); - b.printToFile(io, stderr, &buffer) catch {}; -} +pub const Print = struct { + name: []const u8, + builder: *Builder, + err: ?Allocator.Error, + + pub fn format(p: *Print, w: *Writer) Writer.Error!void { + try w.print("{q}", .{p.name}); + p.builder.print(w) catch |err| switch (err) { + error.WriteFailed => |e| return e, + error.OutOfMemory => |e| { + p.err = e; + return error.WriteFailed; + }, + }; + } +}; pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void { var buffer: [4000]u8 = undefined; diff --git a/src/Air.zig b/src/Air.zig index 3d6edeb5941bc82eae0ac30205b5dde64887a523..56d2e22b8c8f994cec690ce9d2661001dea16223 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig"); const Type = @import("Type.zig"); const Value = @import("Value.zig"); const Zcu = @import("Zcu.zig"); -const print = @import("Air/print.zig"); pub const Legalize = @import("Air/Legalize.zig"); pub const Liveness = @import("Air/Liveness.zig"); +pub const Print = @import("Air/Print.zig"); pub const Verify = @import("Air/Verify.zig"); instructions: std.MultiArrayList(Inst).Slice, @@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index } pub const legalize = Legalize.legalize; -pub const write = print.write; -pub const writeInst = print.writeInst; -pub const dump = print.dump; -pub const dumpInst = print.dumpInst; +pub const write = Print.write; +pub const writeInst = Print.writeInst; +pub const dump = Print.dump; +pub const dumpInst = Print.dumpInst; pub const CoveragePoint = enum(u1) { /// Indicates the block is not a place of interest corresponding to diff --git a/src/Air/print.zig b/src/Air/Print.zig similarity index 98% rename from src/Air/print.zig rename to src/Air/Print.zig index 6f43909740609da4d5ce53040307dadf3d386e1b..cf61419fa35acd0d56d1c2b86b9f892f2c683864 100644 --- a/src/Air/print.zig +++ b/src/Air/Print.zig @@ -8,9 +8,20 @@ const Value = @import("../Value.zig"); const Type = @import("../Type.zig"); const Air = @import("../Air.zig"); const InternPool = @import("../InternPool.zig"); +const Printer = @This(); + +zcu: *Zcu, +fqn: InternPool.NullTerminatedString, +air: *const Air, +liveness: *const ?Air.Liveness, + +pub fn format(p: *const Printer, w: *std.Io.Writer) std.Io.Writer.Error!void { + try w.print("{qf}:\n", .{p.fqn.fmt(&p.zcu.intern_pool)}); + try p.air.write(w, p.zcu, p.liveness.*); +} pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void { - comptime assert(build_options.enable_debug_extensions); + comptime assert(build_options.log_level == .debug); const instruction_bytes = air.instructions.len * // Here we don't use @sizeOf(Air.Inst.Data) because it would include // the debug safety tag but we want to measure release size. @@ -60,7 +71,7 @@ pub fn writeInst( zcu: *Zcu, liveness: ?Air.Liveness, ) void { - comptime assert(build_options.enable_debug_extensions); + comptime assert(build_options.log_level == .debug); var writer: Writer = .{ .zcu = zcu, .gpa = zcu.comp.gpa, diff --git a/src/Compilation.zig b/src/Compilation.zig index 38a905723bce8df08bcb2bf1850ecfd9bfe25870..cae0acc1ffafd1231f9cfd451041d5c0ae536498 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -20,6 +20,7 @@ const link = @import("link.zig"); const tracy = @import("tracy.zig"); const trace = tracy.trace; const build_options = @import("build_options"); +const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; const LibCInstallation = std.zig.LibCInstallation; const glibc = @import("libs/glibc.zig"); const musl = @import("libs/musl.zig"); @@ -161,12 +162,6 @@ clang_passthrough_mode: bool, clang_preprocessor_mode: ClangPreprocessorMode, /// Whether to print clang argvs to stdout. verbose_cc: bool, -verbose_air: bool, -verbose_intern_pool: bool, -verbose_generic_instances: bool, -verbose_llvm_ir: ?[]const u8, -verbose_llvm_bc: ?[]const u8, -verbose_llvm_cpu_features: bool, verbose_link: bool, link_depfile: ?[]const u8, disable_c_depfile: bool, @@ -1544,13 +1539,7 @@ pub const CreateOptions = struct { clang_passthrough_mode: bool = false, verbose_cc: bool = false, verbose_link: bool = false, - verbose_air: bool = false, - verbose_intern_pool: bool = false, - verbose_generic_instances: bool = false, - verbose_llvm_ir: ?[]const u8 = null, - verbose_llvm_bc: ?[]const u8 = null, link_depfile: ?[]const u8 = null, - verbose_llvm_cpu_features: bool = false, debug_compiler_runtime_libs: ?std.lang.Optimize = null, debug_compile_errors: bool = false, debug_incremental: bool = false, @@ -1932,21 +1921,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod); } - if (options.verbose_llvm_cpu_features) { - if (options.root_mod.resolved_target.llvm_cpu_features) |cf| { - const stderr = try io.lockStderr(&.{}, null); - defer io.unlockStderr(); - const w = &stderr.file_writer.interface; - printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) { - error.WriteFailed => switch (stderr.file_writer.err.?) { - error.Canceled => |e| return e, - else => {}, - }, - error.OutOfMemory => |e| return e, - }; - } - } - const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1); const main_mod = options.main_mod orelse options.root_mod; @@ -2111,14 +2085,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .clang_passthrough_mode = options.clang_passthrough_mode, .clang_preprocessor_mode = options.clang_preprocessor_mode, .verbose_cc = options.verbose_cc, - .verbose_air = options.verbose_air, - .verbose_intern_pool = options.verbose_intern_pool, - .verbose_generic_instances = options.verbose_generic_instances, - .verbose_llvm_ir = options.verbose_llvm_ir, - .verbose_llvm_bc = options.verbose_llvm_bc, - .link_depfile = options.link_depfile, - .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features, .verbose_link = options.verbose_link, + .link_depfile = options.link_depfile, .disable_c_depfile = options.disable_c_depfile, .reference_trace = options.reference_trace, .time_report = if (options.time_report) .init else null, @@ -2353,8 +2321,9 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, comp.emit_asm != null or comp.emit_llvm_ir != null or comp.emit_llvm_bc != null or - comp.verbose_llvm_ir != null or - comp.verbose_llvm_bc != null)) + log_llvm_ir: { + break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir"); + })) { if (opt_zcu) |zcu| { dev.check(.llvm_backend); @@ -2566,19 +2535,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, return comp; } -fn printVerboseLlvmCpuFeatures( - w: *Writer, - arena: Allocator, - root_name: []const u8, - target: *const std.Target, - cf: [*:0]const u8, -) (Writer.Error || Allocator.Error)!void { - try w.print("compilation: {s}\n", .{root_name}); - try w.print(" target: {s}\n", .{try target.zigTriple(arena)}); - try w.print(" cpu: {s}\n", .{target.cpu.model.name}); - try w.print(" features: {s}\n", .{cf}); -} - pub fn destroy(comp: *Compilation) void { const gpa = comp.gpa; const io = comp.io; @@ -2991,14 +2947,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE try pt.processExports(); } - if (build_options.enable_debug_extensions and comp.verbose_intern_pool) { - std.debug.print("intern pool stats for {q}:\n", .{comp.root_name}); - zcu.intern_pool.dump(); - } - - if (build_options.enable_debug_extensions and comp.verbose_generic_instances) { - std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) }); - zcu.intern_pool.dumpGenericInstances(gpa); + { + var d: InternPool.Dump = .{ + .name = comp.root_name, + .arena = arena, + .ip = &zcu.intern_pool, + .err = null, + }; + std.log.scoped(.@"ip-stats").debug("{f}", .{&d}); + if (d.err) |err| return err; + std.log.scoped(.@"ip-values").debug("{f}", .{std.fmt.alt(&d, .formatAll)}); + if (d.err) |err| return err; + std.log.scoped(.@"ip-generic-instances").debug("{f}", .{std.fmt.alt(&d, .formatGenericInstances)}); + if (d.err) |err| return err; } } @@ -3220,28 +3181,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error comp.time_report.?.stats.real_ns_llvm_emit = ns; }; - const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: { - break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename); - } else null; + const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) { + .llvmbc, .llvmir => null, + else => if (comp.bin_file != null) + try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename) + else + null, + }; const active = zcu.activate(tid); defer active.deactivate(); llvm_object.emit(active.pt, .{ - .pre_ir_path = comp.verbose_llvm_ir, - .pre_bc_path = comp.verbose_llvm_bc, - .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null, .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: { + .opt_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: { + .opt_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); @@ -3267,7 +3229,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error error.Canceled, error.OutOfMemory => |e| return e, error.AlreadyReported => return, }; - } + } else return; } } if (comp.bin_file) |lf| { @@ -4903,12 +4865,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU .emit_bin = .yes_cache, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_intern_pool = comp.verbose_intern_pool, - .verbose_generic_instances = comp.verbose_intern_pool, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .environ_map = comp.environ_map, }) catch |err| switch (err) { error.CreateFail => { @@ -7415,12 +7371,6 @@ fn buildOutputFromZig( .data_sections = true, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_intern_pool = comp.verbose_intern_pool, - .verbose_generic_instances = comp.verbose_intern_pool, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, .environ_map = comp.environ_map, @@ -7552,12 +7502,6 @@ pub fn build_crt_file( .c_source_files = c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_intern_pool = comp.verbose_intern_pool, - .verbose_generic_instances = comp.verbose_generic_instances, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, .environ_map = comp.environ_map, diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index fdfd8cfe741e1069aa886213940e8d50a88c7677..4ebe3137be59c9bf90f8cce48e072ff74b413a63 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config { // *If* the LLVM backend were to be selected, should Zig use the LLVM // library to build the LLVM module? const use_lib_llvm = b: { - if (!build_options.have_llvm) { + if (!build_options.have_llvm or target.ofmt == .llvmbc or target.ofmt == .llvmir) { if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable; break :b false; } @@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config { if (!options.have_zcu) break :b false; // If emitting to LLVM bitcode object format, must use LLVM backend. - if (options.emit_llvm_ir or options.emit_llvm_bc) { + if (target.ofmt == .llvmbc or target.ofmt == .llvmir or options.emit_llvm_bc or options.emit_llvm_ir) { if (options.use_llvm == false) return error.EmittingLlvmModuleRequiresLlvmBackend; if (!target_util.hasLlvmSupport(target, target.ofmt)) @@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config { const backend = target_util.zigBackend(target, use_llvm); if (options.emit_bin and options.have_zcu) { - if (!use_lib_llvm and use_llvm) { + if (target.ofmt != .llvmbc and target.ofmt != .llvmir and !use_lib_llvm and use_llvm) { // Explicit request to use LLVM to produce an object file, but without // using LLVM libraries. Impossible. return error.EmittingBinaryRequiresLlvmLibrary; @@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config { break :b switch (target.ofmt) { .elf, .macho, .wasm => .{ .dwarf = .@"32" }, .coff => .code_view, - .c => switch (target.os.tag) { + .c, .llvmbc, .llvmir => switch (target.os.tag) { .windows, .uefi => .code_view, else => .{ .dwarf = .@"32" }, }, diff --git a/src/InternPool.zig b/src/InternPool.zig index ad7c65bff970b9dc7a5666c56949312fef15663e..77bf96a5f0a46a67a56e1d445d3a9d9e3ff4e5d7 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -10591,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index { return ip.indexToKey(ty).error_union_type.payload_type; } -pub fn dump(ip: *const InternPool) void { - var buffer: [4096]u8 = undefined; - const stderr = std.debug.lockStderr(&buffer); - defer std.debug.unlockStderr(); - const w = &stderr.file_writer.interface; - dumpDependencyStatsFallible(ip, w) catch return; - dumpStatsFallible(ip, w, std.heap.page_allocator) catch return; - dumpAllFallible(ip, w) catch return; -} - -fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { +pub const Dump = struct { + name: []const u8, + arena: std.mem.Allocator, + ip: *const InternPool, + err: ?Allocator.Error, + + pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void { + try w.print("{q}:\n", .{d.name}); + try d.ip.dumpDependencyStatsFallible(w); + d.ip.dumpStatsFallible(d.arena, w) catch |err| switch (err) { + error.WriteFailed => |e| return e, + error.OutOfMemory => |e| { + d.err = e; + return error.WriteFailed; + }, + }; + } + + pub fn formatAll(d: *Dump, w: *Io.Writer) Io.Writer.Error!void { + try w.print("{q}:\n", .{d.name}); + try d.ip.dumpAllFallible(w); + } + + pub fn formatGenericInstances(d: *Dump, w: *Io.Writer) Io.Writer.Error!void { + try w.print("{q}:\n", .{d.name}); + d.ip.dumpGenericInstancesFallible(d.arena, w) catch return; + } +}; + +fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void { const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len; const src_hash_deps_len = ip.src_hash_deps.count(); const nav_val_deps_len = ip.nav_val_deps.count(); @@ -10668,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void { }); } -fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void { +fn dumpStatsFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) (Allocator.Error || Io.Writer.Error)!void { var items_len: usize = 0; var extra_len: usize = 0; var limbs_len: usize = 0; @@ -10968,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo } } -fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { +fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void { for (ip.locals, 0..) |*local, tid| { // Early check for length 0, because `view()` is invalid if capacity is 0 if (local.mutate.items.len == 0) continue; @@ -11071,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { } } -pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) void { - var buffer: [4096]u8 = undefined; - const stderr = std.debug.lockStderr(&buffer); - defer std.debug.unlockStderr(); - const w = &stderr.file_writer.interface; - ip.dumpGenericInstancesFallible(allocator, w) catch return; -} - -pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, w: *Io.Writer) !void { - var arena_allocator = std.heap.ArenaAllocator.init(allocator); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - +pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void { var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty; for (ip.locals, 0..) |*local, tid| { + if (local.mutate.items.len == 0) continue; const items = local.shared.items.view().slice(); const extra_list = local.shared.extra; for ( diff --git a/src/Module.zig b/src/Module.zig index 5154b853641c4ed2af01fd0aed1b8c1f911204a6..02df432d5ef580021369e4e2ea74b24d17d6be13 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -26,6 +26,7 @@ fully_qualified_name: []const u8, deps: Deps = .{}, resolved_target: ResolvedTarget, +llvm_cpu_features: ?[:0]const u8, optimize_mode: std.lang.Optimize, code_model: std.lang.CodeModel, single_threaded: bool, @@ -94,7 +95,6 @@ pub const ResolvedTarget = struct { is_native_os: bool, is_native_abi: bool, is_explicit_dynamic_linker: bool, - llvm_cpu_features: ?[*:0]const u8 = null, }; pub const CreateError = error{ @@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { break :b 0; }; - const llvm_cpu_features: ?[*:0]const u8 = b: { - if (resolved_target.llvm_cpu_features) |x| break :b x; + const llvm_cpu_features: ?[:0]const u8 = b: { if (!options.global.use_llvm) break :b null; + if (options.inherited.resolved_target == null) break :b options.parent.?.llvm_cpu_features; + // Append disabled features after enabled ones, so that their effects aren't overwritten. var buf = std.array_list.Managed(u8).init(arena); var disabled_features = std.array_list.Managed(u8).init(arena); - defer disabled_features.deinit(); - - // Append disabled features after enabled ones, so that their effects aren't overwritten. for (target.cpu.arch.allFeaturesList()) |feature| { if (feature.llvm_name) |llvm_name| { // Ignore these until we figure out how to handle the concept of omitting features. @@ -401,10 +399,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { try buf.appendSlice(disabled_features.items); if (buf.items.len == 0) break :b ""; - assert(std.mem.endsWith(u8, buf.items, ",")); + assert(buf.items[buf.items.len - 1] == ','); buf.items[buf.items.len - 1] = 0; - buf.shrinkAndFree(buf.items.len); - break :b buf.items[0 .. buf.items.len - 1 :0].ptr; + break :b buf.items[0 .. buf.items.len - 1 :0]; }; const mod = try arena.create(Module); @@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { .is_native_os = resolved_target.is_native_os, .is_native_abi = resolved_target.is_native_abi, .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker, - .llvm_cpu_features = llvm_cpu_features, }, + .llvm_cpu_features = llvm_cpu_features, .optimize_mode = optimize_mode, .single_threaded = single_threaded, .error_tracing = error_tracing, @@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories) .is_native_os = false, .is_native_abi = false, .is_explicit_dynamic_linker = false, - .llvm_cpu_features = null, }, + .llvm_cpu_features = null, .optimize_mode = opts.optimize_mode, .single_threaded = opts.single_threaded, .error_tracing = opts.error_tracing, diff --git a/src/Sema.zig b/src/Sema.zig index ca4ccd20c9652e741cfa7badfeafad4b8324338b..e5ee288187f627f9438a64f3d91eac833268ed9c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1126,6 +1126,8 @@ fn analyzeBodyInner( crash_info.push(sema, block, body); defer crash_info.pop(); + const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path; + // We use a while (true) loop here to avoid a redundant way of breaking out of // the loop. The only way to break out of the loop is with a `noreturn` // instruction. @@ -1134,11 +1136,7 @@ fn analyzeBodyInner( crash_info.setBodyIndex(i); const inst = body[i]; - // This log is a bit expensive, and LLVM fails to optimize it away. - if (build_options.enable_logging) { - const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path; - std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst }); - } + std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst }); const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) { // zig fmt: off diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index ec764ddfdefc972b4ff9bfbc3d8a920cdabe9762..bb09f50cf02be848121d63c01e679232a6324ad7 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig"); const AnalUnit = InternPool.AnalUnit; const Module = @import("../Module.zig"); const Sema = @import("../Sema.zig"); +const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled; const target_util = @import("../target.zig"); const tracy = @import("../tracy.zig"); const trace = tracy.trace; @@ -2303,10 +2304,9 @@ fn analyzeFuncBody( const comp = zcu.comp; - const dump_air = build_options.enable_debug_extensions and comp.verbose_air; - const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); - - if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) { + if (comp.bin_file != null or zcu.llvm_object != null or log_air: { + break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air"); + }) { zcu.codegen_prog_node.increaseEstimatedTotalItems(1); comp.link_prog_node.increaseEstimatedTotalItems(1); @@ -4522,32 +4522,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e tracy_trace.addText(fqn.toSlice(ip)); tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); - Air.Verify.run(pt, func_index, air); + var liveness: ?Air.Liveness = null; + defer if (liveness) |*l| l.deinit(gpa); + + const ap: Air.Print = .{ + .zcu = zcu, + .fqn = fqn, + .air = air, + .liveness = &liveness, + }; + std.log.scoped(.@"illegal-air").debug("{f}", .{&ap}); if (codegen.legalizeFeatures(pt, nav)) |features| { - try air.legalize(pt, features); - // Verify the AIR again post-legalization. + // Verify the AIR again pre-legalization. Air.Verify.run(pt, func_index, air); + try air.legalize(pt, features); } - var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav)) - try .analyze(zcu, air.*, ip) - else - null; - defer if (liveness) |*l| l.deinit(gpa); - - if (build_options.enable_debug_extensions and comp.verbose_air) p: { - const io = comp.io; - const stderr = try io.lockStderr(&.{}, null); - defer io.unlockStderr(); - printVerboseAir(pt, liveness, fqn, air, &stderr.file_writer.interface) catch |err| switch (err) { - error.WriteFailed => switch (stderr.file_writer.err.?) { - error.Canceled => |e| return e, - else => break :p, - }, - }; - } + std.log.scoped(.@"legal-air").debug("{f}", .{&ap}); + Air.Verify.run(pt, func_index, air); + if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip); + std.log.scoped(.air).debug("{f}", .{&ap}); if (std.debug.runtime_safety) verify_liveness: { var verify: Air.Liveness.Verify = .{ .gpa = gpa, @@ -4577,17 +4573,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e return codegen.generateFunction(lf, pt, func_index, air, &liveness); } - -fn printVerboseAir( - pt: Zcu.PerThread, - liveness: ?Air.Liveness, - fqn: InternPool.NullTerminatedString, - air: *const Air, - w: *Io.Writer, -) Io.Writer.Error!void { - const zcu = pt.zcu; - const ip = &zcu.intern_pool; - try w.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)}); - try air.write(w, zcu, liveness); - try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)}); -} diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index f4198c2db8da81c76fcb743e8e5dd972ede77bef..279979085b12c4da65da09f2868676ca567af7e0 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10,6 +10,7 @@ const build_options = @import("build_options"); const Air = @import("../Air.zig"); const codegen = @import("../codegen.zig"); const Compilation = @import("../Compilation.zig"); +const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled; const InternPool = @import("../InternPool.zig"); const link = @import("../link.zig"); const Module = @import("../Module.zig"); @@ -331,12 +332,10 @@ pub const Object = struct { } pub const EmitOptions = struct { - pre_ir_path: ?[]const u8, - pre_bc_path: ?[]const u8, bin_path: ?[:0]const u8, asm_path: ?[:0]const u8, - post_ir_path: ?[:0]const u8, - post_bc_path: ?[:0]const u8, + opt_ir_path: ?[:0]const u8, + opt_bc_path: ?[:0]const u8, is_debug: bool, is_small: bool, @@ -351,6 +350,7 @@ pub const Object = struct { const comp = zcu.comp; const io = comp.io; const diags = &comp.link_diags; + const target = &comp.root_mod.resolved_target.result; { if (o.errors_len_variable != .none) { @@ -403,7 +403,7 @@ pub const Object = struct { const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7)); const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8)); - if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| { + if (target_util.llvmMachineAbi(target)) |abi| { module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{ behavior_error, (try o.builder.metadataString("target-abi")).toMetadata(), @@ -411,7 +411,7 @@ pub const Object = struct { })); } - const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result); + const pic_level = target_util.picLevel(target); if (comp.root_mod.pic) { module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{ behavior_min, @@ -434,7 +434,7 @@ pub const Object = struct { (try o.builder.metadataString("Code Model")).toMetadata(), try o.builder.metadataConstant(try o.builder.intConst(.i32, @as( i32, - switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) { + switch (codeModel(comp.root_mod.code_model, target)) { .default => unreachable, .tiny => 0, .small => 1, @@ -480,7 +480,6 @@ pub const Object = struct { } } - const target = &comp.root_mod.resolved_target.result; if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) { // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall // v4, which is essentially a requirement on Windows. See corresponding logic in @@ -515,21 +514,26 @@ pub const Object = struct { const emit_asm_msg = options.asm_path orelse "(none)"; const emit_bin_msg = options.bin_path orelse "(none)"; - const post_llvm_ir_msg = options.post_ir_path orelse "(none)"; - const post_llvm_bc_msg = options.post_bc_path orelse "(none)"; + const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)"; + const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)"; log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{ - emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, + emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg, }); + const log_opt_llvm_ir = debugLogScopeEnabled("opt-llvm-ir"); const context, const module = emit: { - if (options.pre_ir_path) |path| { - if (std.mem.eql(u8, path, "-")) { - o.builder.dump(io); - } else { - o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| { - log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err }); - }; - } + { + var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null }; + std.log.scoped(.@"llvm-ir").debug("{f}", .{&p}); + if (p.err) |err| return err; + } + + if (target.ofmt == .llvmir) { + const path = comp.bin_file.?.emit; + o.builder.printToFilePath(io, path.root_dir.handle, path.sub_path) catch |err| { + return diags.fail("failed emitting LLVM module to {qf}: {t}", .{ path, err }); + }; + return; } const bitcode = try o.builder.toBitcode(o.gpa, .{ @@ -538,23 +542,26 @@ pub const Object = struct { }); defer o.gpa.free(bitcode); - if (options.pre_bc_path) |path| { - var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err| - return diags.fail("failed to create '{s}': {t}", .{ path, err }); + if (target.ofmt == .llvmbc) { + const path = comp.bin_file.?.emit; + var file = path.root_dir.handle.createFile(io, path.sub_path, .{}) catch |err| + return diags.fail("failed to create {qf}: {t}", .{ path, err }); defer file.close(io); file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err| - return diags.fail("failed to write to '{s}': {t}", .{ path, err }); + return diags.fail("failed to write to {qf}: {t}", .{ path, err }); + return; } if (options.asm_path == null and options.bin_path == null and - options.post_ir_path == null and options.post_bc_path == null) return; + options.opt_ir_path == null and options.opt_bc_path == null and + !log_opt_llvm_ir) return; if (!build_options.have_llvm or !comp.config.use_lib_llvm) { return diags.fail("emitting without libllvm not implemented", .{}); } - initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch); + initializeLLVMTarget(io, target.cpu.arch); const context: *bindings.Context = .create(); errdefer context.dispose(); @@ -577,9 +584,9 @@ pub const Object = struct { }; defer context.dispose(); - var target: *bindings.Target = undefined; + var llvm_target: *bindings.Target = undefined; var error_message: [*:0]const u8 = undefined; - if (bindings.Target.getFromTriple(target_triple_sentinel, &target, &error_message).toBool()) { + if (bindings.Target.getFromTriple(target_triple_sentinel, &llvm_target, &error_message).toBool()) { defer bindings.disposeMessage(error_message); return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message }); } @@ -598,7 +605,7 @@ pub const Object = struct { else .Static; - const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) { + const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, target)) { .default => .Default, .tiny => .Tiny, .small => .Small, @@ -607,24 +614,22 @@ pub const Object = struct { .large => .Large, }; - const float_abi: bindings.TargetMachine.FloatABI = if (comp.root_mod.resolved_target.result.abi.float() == .hard) - .Hard - else - .Soft; - var target_machine = bindings.TargetMachine.create( - target, + llvm_target, target_triple_sentinel, - if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null, - comp.root_mod.resolved_target.llvm_cpu_features.?, + if (target.cpu.model.llvm_name) |s| s.ptr else null, + comp.root_mod.llvm_cpu_features.?, opt_level, reloc_mode, code_model, comp.function_sections, comp.data_sections, - float_abi, - if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null, - target_util.useEmulatedTls(&comp.root_mod.resolved_target.result), + switch (target.abi.float()) { + .hard => .Hard, + .soft => .Soft, + }, + if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, + target_util.useEmulatedTls(target), ); errdefer target_machine.dispose(); @@ -634,7 +639,10 @@ pub const Object = struct { // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. // So we call the entire pipeline multiple times if this is requested. - // var error_message: [*:0]const u8 = undefined; + var time_report_c_str: ?[*:0]u8 = null; + defer if (time_report_c_str) |time_report| bindings.disposeMessage(time_report); + var llvm_ir_c_str: ?[*:0]u8 = null; + defer if (llvm_ir_c_str) |llvm_ir| bindings.disposeMessage(llvm_ir); var lowered_options: bindings.TargetMachine.EmitOptions = .{ .is_debug = options.is_debug, .is_small = options.is_small, @@ -648,11 +656,12 @@ pub const Object = struct { .allow_fast_isel = true, // LLVM's RISC-V backend for some reason enables the machine outliner by default even // though it's clearly not ready and produces multiple miscompilations in our std tests. - .allow_machine_outliner = !comp.root_mod.resolved_target.result.cpu.arch.isRISCV(), + .allow_machine_outliner = !target.cpu.arch.isRISCV(), .asm_filename = null, .bin_filename = if (options.bin_path) |x| x.ptr else null, - .llvm_ir_filename = if (options.post_ir_path) |x| x.ptr else null, - .bitcode_filename = if (options.post_bc_path) |x| x.ptr else null, + .llvm_ir_filename = if (options.opt_ir_path) |x| x.ptr else null, + .bitcode_filename = if (options.opt_bc_path) |x| x.ptr else null, + .llvm_ir_out = if (log_opt_llvm_ir) &llvm_ir_c_str else null, // `.coverage` value is only used when `.sancov` is enabled. .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard, @@ -684,33 +693,31 @@ pub const Object = struct { }; if (options.asm_path != null and options.bin_path != null) { if (target_machine.emitToFile(module, &error_message, &lowered_options)) { - defer bindings.disposeMessage(error_message); return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{ - emit_bin_msg, post_llvm_ir_msg, error_message, + emit_bin_msg, opt_llvm_ir_msg, error_message, }); } lowered_options.bin_filename = null; lowered_options.llvm_ir_filename = null; lowered_options.bitcode_filename = null; + lowered_options.llvm_ir_out = null; } - - var time_report_c_str: [*:0]u8 = undefined; - if (options.time_report != null) { - lowered_options.time_report_out = &time_report_c_str; - } - + if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str; lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null; if (target_machine.emitToFile(module, &error_message, &lowered_options)) { defer bindings.disposeMessage(error_message); return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{ - emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message, + emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg, error_message, }); } - if (options.time_report) |tr| { - defer std.c.free(time_report_c_str); - const time_report_data = std.mem.span(time_report_c_str); - assert(tr.llvm_pass_timings.len == 0); - tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data); + if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{ + llvm_ir_c_str orelse return error.OutOfMemory, + }); + if (options.time_report) |time_report| { + assert(time_report.llvm_pass_timings.len == 0); + time_report.llvm_pass_timings = try comp.gpa.dupe(u8, std.mem.span( + time_report_c_str orelse return error.OutOfMemory, + )); } } @@ -2184,10 +2191,10 @@ pub const Object = struct { .value = try o.builder.string(s), } }, &o.builder); } - if (owner_mod.resolved_target.llvm_cpu_features) |s| { + if (owner_mod.llvm_cpu_features) |s| { try attributes.addFnAttr(.{ .string = .{ .kind = try o.builder.string("target-features"), - .value = try o.builder.string(std.mem.span(s)), + .value = try o.builder.string(s), } }, &o.builder); } diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index a312285db3310ba0fc69dffe55d56e484c293e50..7ee71c237c9a07763b80d844e4c559cc88bf1934 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -51,7 +51,7 @@ pub const Module = opaque { }; pub const disposeMessage = LLVMDisposeMessage; -extern fn LLVMDisposeMessage(Message: [*:0]const u8) void; +extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void; pub const TargetMachine = opaque { pub const FloatABI = enum(c_int) { @@ -85,7 +85,7 @@ pub const TargetMachine = opaque { pub const EmitOptions = extern struct { is_debug: bool, is_small: bool, - time_report_out: ?*[*:0]u8, + time_report_out: ?*?[*:0]u8, tsan: bool, sancov: bool, lto: LtoPhase, @@ -95,6 +95,7 @@ pub const TargetMachine = opaque { bin_filename: ?[*:0]const u8, llvm_ir_filename: ?[*:0]const u8, bitcode_filename: ?[*:0]const u8, + llvm_ir_out: ?*?[*:0]u8, coverage: Coverage, pub const LtoPhase = enum(c_int) { diff --git a/src/codegen/riscv64/CodeGen.zig b/src/codegen/riscv64/CodeGen.zig index 55a1e138d1ab01c5744f1ff7cb3f3c8181b8c715..c01390c2d9ec26d2da3f227eafc7ed7b98b30ba2 100644 --- a/src/codegen/riscv64/CodeGen.zig +++ b/src/codegen/riscv64/CodeGen.zig @@ -27,7 +27,7 @@ const Target = std.Target; const log = std.log.scoped(.riscv_codegen); const tracking_log = std.log.scoped(.tracking); const verbose_tracking_log = std.log.scoped(.verbose_tracking); -const wip_mir_log = std.log.scoped(.wip_mir); +const wip_mir_log = std.log.scoped(.@"wip-mir"); const Alignment = InternPool.Alignment; const bits = @import("bits.zig"); diff --git a/src/codegen/x86_64/CodeGen.zig b/src/codegen/x86_64/CodeGen.zig index 4f9b9ef0b0a2c6d3df51f642256e83b7cdda8a24..e3cfed33b33300e71e703147362bf501873df1d6 100644 --- a/src/codegen/x86_64/CodeGen.zig +++ b/src/codegen/x86_64/CodeGen.zig @@ -5,7 +5,7 @@ const link = @import("../../link.zig"); const log = std.log.scoped(.codegen); const tracking_log = std.log.scoped(.tracking); const verbose_tracking_log = std.log.scoped(.verbose_tracking); -const wip_mir_log = std.log.scoped(.wip_mir); +const wip_mir_log = std.log.scoped(.@"wip-mir"); const Writer = std.Io.Writer; const Air = @import("../../Air.zig"); diff --git a/src/dev.zig b/src/dev.zig index b9e448ef7e53668bfac8044f6dfd3cabf6ead9bd..aaed1c88140240a0794a8b4e94f73e5e219452cf 100644 --- a/src/dev.zig +++ b/src/dev.zig @@ -112,6 +112,7 @@ pub const Env = enum { .loongarch_backend, .spork8_backend, .lld_linker, + .llvm_linker, .coff_linker, .elf_linker, .elf2_linker, @@ -333,6 +334,7 @@ pub const Feature = enum { spork8_backend, lld_linker, + llvm_linker, coff_linker, elf_linker, elf2_linker, diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 584a6b63b69adae9e3427334567bd41357056543..8f07d8fb8a6d12cc1f54b4f656a9d269008a82c7 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -1120,10 +1120,6 @@ fn buildSharedLib( .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, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, .version_script = .{ diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index 024588644a8c69c12fc323c4c812468abff565d1..4da85e7df75ac5db630273b364d8ee675b94738d 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -1268,10 +1268,6 @@ fn buildSharedLib( .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, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, .version_script = .{ diff --git a/src/libs/libcxx.zig b/src/libs/libcxx.zig index 993f9ee2f8277acb627dd28ab918fab6a7703c64..376887fd9ecedeaf9c1eb1096a9637ae930745cd 100644 --- a/src/libs/libcxx.zig +++ b/src/libs/libcxx.zig @@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, .environ_map = comp.environ_map, @@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, .environ_map = comp.environ_map, diff --git a/src/libs/libtsan.zig b/src/libs/libtsan.zig index 7212a17e38e5dba06208c23feb698ad46527a20e..bc8cacd84cfb167591271a7ef0cd6753dd143923 100644 --- a/src/libs/libtsan.zig +++ b/src/libs/libtsan.zig @@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .c_source_files = c_source_files.items, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = skip_linker_dependencies, .linker_allow_shlib_undefined = linker_allow_shlib_undefined, diff --git a/src/libs/libunwind.zig b/src/libs/libunwind.zig index fb3b20684bc90117d10bebd2082ac97367124be1..d8d3456d1572b84d0d742dc27b5f22d8375909db 100644 --- a/src/libs/libunwind.zig +++ b/src/libs/libunwind.zig @@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr .c_source_files = &c_source_files, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .skip_linker_dependencies = true, .environ_map = comp.environ_map, diff --git a/src/libs/musl.zig b/src/libs/musl.zig index eca461940ce84ad1aa8d26dd406b6c4c3100dbb3..346563b4ce2f6886f53f8222ccd249a4686fabf0 100644 --- a/src/libs/musl.zig +++ b/src/libs/musl.zig @@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro .emit_bin = .yes_cache, .verbose_cc = comp.verbose_cc, .verbose_link = comp.verbose_link, - .verbose_air = comp.verbose_air, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .c_source_files = &.{ .{ diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index 46a34b96a55943f84a92914521a730c27d0d19a7..3a31b8f8d577cd6c6827c13bb3abe9e3f4244f93 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -771,10 +771,6 @@ fn buildSharedLib( .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, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .version = version, .soname = soname, diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index 4bea660a65eed944eb93d48f27c5cc70a0369a8d..b16c0189f8a8fca0713f220c6dd41aaaadb2f940 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -691,10 +691,6 @@ fn buildSharedLib( .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, - .verbose_llvm_ir = comp.verbose_llvm_ir, - .verbose_llvm_bc = comp.verbose_llvm_bc, - .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features, .clang_passthrough_mode = comp.clang_passthrough_mode, .soname = soname, .c_source_files = &c_source_files, diff --git a/src/link.zig b/src/link.zig index 5b1b0bbeb601c90013a603f4014b1c32254a8634..843cb395fa06130840298a7986d1ebf2653478e5 100644 --- a/src/link.zig +++ b/src/link.zig @@ -550,6 +550,7 @@ pub const File = struct { return &ptr.base; }, .lld => unreachable, // not known from ofmt + .llvm => |tag| return createDummy(arena, tag, comp, emit), } } @@ -573,9 +574,26 @@ pub const File = struct { return &ptr.base; }, .lld => unreachable, // not known from ofmt + .llvm => |tag| return createDummy(arena, tag, comp, emit), } } + fn createDummy(arena: Allocator, tag: Tag, comp: *Compilation, path: Path) Allocator.Error!*File { + const base = try arena.create(File); + base.* = .{ + .tag = tag, + .comp = comp, + .emit = path, + .file = null, + .gc_sections = false, + .print_gc_sections = false, + .build_id = .none, + .allow_shlib_undefined = false, + .stack_size = 0, + }; + return base; + } + pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn { return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null; } @@ -606,7 +624,7 @@ pub const File = struct { const gpa = comp.gpa; const io = comp.io; switch (base.tag) { - .lld => assert(base.file == null), + .lld, .llvm => assert(base.file == null), .elf, .macho, .wasm => { dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker }); if (base.file != null) return; @@ -706,7 +724,7 @@ pub const File = struct { if (!base.canMakeExecutable()) return; switch (base.tag) { - .lld => assert(base.file == null), + .lld, .llvm => assert(base.file == null), .elf => if (base.file) |f| { dev.check(.elf_linker); f.close(io); @@ -827,6 +845,7 @@ pub const File = struct { switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -862,6 +881,7 @@ pub const File = struct { assert(pt.zcu.llvm_object == null); switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -897,6 +917,7 @@ pub const File = struct { } switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .plan9 => unreachable, .spirv => {}, .coff => {}, @@ -941,6 +962,7 @@ pub const File = struct { base.releaseLock(); if (base.file) |f| f.close(io); switch (base.tag) { + .llvm => {}, .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -1003,6 +1025,7 @@ pub const File = struct { } assert(base.post_prelink); switch (base.tag) { + .llvm => {}, .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -1030,6 +1053,7 @@ pub const File = struct { switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .plan9 => unreachable, inline else => |tag| { dev.check(tag.devFeature()); @@ -1056,6 +1080,7 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -1078,6 +1103,7 @@ pub const File = struct { assert(pt.zcu.llvm_object == null); switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -1095,6 +1121,7 @@ pub const File = struct { assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .lld => unreachable, + .llvm => unreachable, .c => unreachable, .spirv => unreachable, .wasm => unreachable, @@ -1124,6 +1151,7 @@ pub const File = struct { .spirv, .plan9, .lld, + .llvm, .spork8, => return .unimplemented, inline else => |tag| { @@ -1240,7 +1268,7 @@ pub const File = struct { dev.check(tag.devFeature()); return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input); }, - .c, .spork8, .plan9, .lld => {}, + .c, .spork8, .plan9, .lld, .llvm => {}, } } @@ -1352,6 +1380,7 @@ pub const File = struct { coff, elf, elf2, + llvm, macho, macho2, c, @@ -1366,13 +1395,14 @@ pub const File = struct { .coff => Coff, .elf => Elf, .elf2 => Elf2, + .llvm => File, .macho => MachO, .macho2 => MachO2, .c => C, .wasm => Wasm, .spirv => Spirv, .lld => Lld, - .plan9 => comptime unreachable, + .plan9 => unreachable, .spork8 => Spork8, }; } @@ -1381,6 +1411,7 @@ pub const File = struct { return switch (ofmt) { .coff => .coff, .elf => if (use_new_linker) .elf2 else .elf, + .llvmbc, .llvmir => .llvm, .macho => if (use_new_linker) .macho2 else .macho, .wasm => .wasm, .plan9 => .plan9, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 828f707582aa3753709e623e1662641fd505358b..1067b9a50a525a99213d7a02fd988fb187561b5b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { // Dump the state for easy debugging. // State can be dumped via `--debug-log link_state`. - if (build_options.enable_logging) { - state_log.debug("{f}", .{self.dumpState()}); - } + state_log.debug("{f}", .{self.dumpState()}); // Beyond this point, everything has been allocated a virtual address and we can resolve // the relocations, and commit objects to file. diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index b0a9c43db2de32654acb8e52407103b766e54a11..08ba32f95e93d7a5c267137a9323187b7f12924b 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; } - if (build_options.enable_logging) { + if (build_options.enable_debug_extensions) { const active = elf_file.base.comp.zcu.?.activate(tid); defer active.deactivate(); for (self.navs.keys(), self.navs.values()) |nav_index, meta| { diff --git a/src/link/Elf/gc.zig b/src/link/Elf/gc.zig index 29bdaae801109683381a5b3bbc18f05d7fb43a56..98941b5d73ff68f9e4220301c3246166f7c33414 100644 --- a/src/link/Elf/gc.zig +++ b/src/link/Elf/gc.zig @@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool { } fn markLive(atom: *Atom, elf_file: *Elf) void { - if (@import("build_options").enable_logging) track_live_level.incr(); + if (@import("build_options").enable_debug_extensions) track_live_level.incr(); assert(atom.visited); const file = atom.file(elf_file).?; diff --git a/src/link/Elf/relocatable.zig b/src/link/Elf/relocatable.zig index e5a5e55b29f0edd8d4733e7f0fafede1e0da201c..d45995054da762491085cdff360bb32ac63f7a52 100644 --- a/src/link/Elf/relocatable.zig +++ b/src/link/Elf/relocatable.zig @@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { try allocateAllocSections(elf_file); try elf_file.allocateNonAllocSections(); - if (build_options.enable_logging) { - state_log.debug("{f}", .{elf_file.dumpState()}); - } + state_log.debug("{f}", .{elf_file.dumpState()}); try elf_file.writeMergeSections(); try writeSyntheticSections(elf_file); @@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { break :blk pos; }; - if (build_options.enable_logging) { - state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)}); - state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); - } + state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)}); + state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); const buffer = try gpa.alloc(u8, total_size); defer gpa.free(buffer); @@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void { try allocateAllocSections(elf_file); try elf_file.allocateNonAllocSections(); - if (build_options.enable_logging) { - state_log.debug("{f}", .{elf_file.dumpState()}); - } + state_log.debug("{f}", .{elf_file.dumpState()}); try writeAtoms(elf_file); try elf_file.writeMergeSections(); diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3f5f7951bf101c768beea37c920f216ccbd84daf..c1b76db1b10be51d584e54a48767a9b9d84d727f 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -456,9 +456,7 @@ pub fn flush( self.allocateSegments(); self.allocateSyntheticSymbols(); - if (build_options.enable_logging) { - state_log.debug("{f}", .{self.dumpState()}); - } + state_log.debug("{f}", .{self.dumpState()}); // Beyond this point, everything has been allocated a virtual address and we can resolve // the relocations, and commit objects to file. diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index 3c17ead455821921e85cd5cbfd4d6e14828f8bba..f5091220876875394740038ee46f2e80e9fde370 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void { atom.getName(macho_file), }); - if (build_options.enable_logging) + if (build_options.enable_debug_extensions) { track_live_level.incr(); + } for (atom.getRelocs(macho_file)) |rel| { const target_atom = switch (rel.tag) { diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index cd1231bebfa1cb97b082eacb705203afe8435daf..bf7080e31ea681a47ea35ef075f17f9ef8470645 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void { }; allocateSegment(macho_file); - if (build_options.enable_logging) { - state_log.debug("{f}", .{macho_file.dumpState()}); - } + state_log.debug("{f}", .{macho_file.dumpState()}); try writeSections(macho_file); sortRelocs(macho_file); @@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { return diags.fail("failed to allocate sections: {s}", .{@errorName(err)}); allocateSegment(macho_file); - if (build_options.enable_logging) { - state_log.debug("{f}", .{macho_file.dumpState()}); - } + state_log.debug("{f}", .{macho_file.dumpState()}); try writeSections(macho_file); sortRelocs(macho_file); @@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { break :blk pos; }; - if (build_options.enable_logging) { - state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); - } + state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); const buffer = try gpa.alloc(u8, total_size); defer gpa.free(buffer); diff --git a/src/main.zig b/src/main.zig index 607cd7b643a5a94d06d710dc25feea16c55568c7..541504cdb218af539235a5e1f6abca83d30b7234 100644 --- a/src/main.zig +++ b/src/main.zig @@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20; pub const std_options: std.Options = .{ .logFn = log, - - .log_level = switch (builtin.mode) { - .debug => .debug, - .safe, .fast => .info, - .small => .err, + .log_level = switch (build_options.log_level) { + inline else => |log_level| @field(std.log.Level, @tagName(log_level)), }, }; pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null; @@ -104,7 +101,7 @@ const normal_usage = \\ help Print this help and exit \\ cache-cat Print a zig-cache manifest file as zon \\ std View standard library documentation in a browser - \\ libc Display native libc paths file or validate one + \\ libc Print native libc paths file or validate one \\ targets List available compilation targets \\ version Print version number and exit \\ zen Print Zen of Zig and exit @@ -126,7 +123,15 @@ const debug_usage = normal_usage ++ const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage; -var log_scopes: std.ArrayList([]const u8) = .empty; +var log_scopes: std.array_hash_map.String(void) = .empty; + +pub fn debugLogScopeEnabled(scope: []const u8) bool { + switch (build_options.log_level) { + else => {}, + .debug => if (log_scopes.contains(scope)) return true, + } + return false; +} pub fn log( comptime level: std.log.Level, @@ -135,18 +140,11 @@ pub fn log( args: anytype, ) void { // Hide debug messages unless: - // * logging enabled with `-Dlog`. + // * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`. // * the --debug-log arg for the scope has been provided - if (@backingInt(level) > @backingInt(std.options.log_level) or - @backingInt(level) > @backingInt(std.log.Level.info)) - { - if (!build_options.enable_logging) return; - - const scope_name = @tagName(scope); - for (log_scopes.items) |log_scope| { - if (mem.eql(u8, log_scope, scope_name)) - break; - } else return; + switch (level) { + else => {}, + .debug => if (!debugLogScopeEnabled(@tagName(scope))) return, } // Otherwise, use the default implementation. @@ -557,11 +555,14 @@ const compile_usage = \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL - \\ --show-builtin Output the source of @import("builtin") then exit \\ --cache-dir [path] Override the local cache directory \\ --global-cache-dir [path] Override the global cache directory \\ --zig-lib-dir [path] Override path to Zig installation lib directory \\ --build-root [path] Override path to project source files + \\ --show-builtin Output the source of @import("builtin") then exit + \\ --time-report Send timing diagnostics to '--listen' clients + \\ --verbose-cc Print C compiler commands before executing them + \\ --verbose-link Print linker commands before executing them \\ \\Global Compile Options: \\ --name [name] Compilation unit name (not a file path) @@ -593,7 +594,6 @@ const compile_usage = \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues \\ -mexec-model=[value] (WASI) Execution model \\ -municode (Windows) Use wmain/wWinMain as entry point - \\ --time-report Send timing diagnostics to '--listen' clients \\ \\Per-Module Compile Options: \\ --dep [[import=]name] Add an entry to the next module's import table @@ -604,13 +604,15 @@ const compile_usage = \\ safe Enable both safety checks and machine code optimizations \\ small Prioritize small binary size. Safety checks off. \\ -ofmt=[fmt] Override target object format - \\ elf Executable and Linking Format \\ c C source code - \\ wasm WebAssembly \\ coff Common Object File Format (Windows) + \\ elf Executable and Linking Format + \\ llvmir LLVM text intermediate representation + \\ llvmbc LLVM binary intermediate representation \\ macho macOS relocatables - \\ spirv Standard, Portable Intermediate Representation V (SPIR-V) \\ plan9 Plan 9 from Bell Labs object format + \\ spirv Standard, Portable Intermediate Representation V (SPIR-V) + \\ wasm WebAssembly \\ hex (planned feature) Intel IHEX \\ raw (planned feature) Dump machine code directly \\ -mcpu [cpu] Specify target CPU and feature set @@ -791,15 +793,6 @@ const compile_usage = \\Debug Options (Zig Compiler Development): \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes \\ -fstack-report Print stack size diagnostics - \\ --verbose-link Display linker invocations - \\ --verbose-cc Display C compiler invocations - \\ --verbose-air Enable compiler debug output for Zig AIR - \\ --verbose-intern-pool Enable compiler debug output for InternPool - \\ --verbose-generic-instances Enable compiler debug output for generic instance generation - \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR - \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC - \\ --verbose-cimport Enable compiler debug output for C imports - \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features \\ --debug-log [scope] Enable printing debug/info log messages for scope \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting @@ -933,17 +926,11 @@ fn buildOutputType( var listen: Listen = .none; var debug_compile_errors = false; var debug_incremental = false; - var verbose_link = (native_os != .wasi or builtin.link_libc) and - EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map); var verbose_cc = (native_os != .wasi or builtin.link_libc) and EnvVar.ZIG_VERBOSE_CC.isSet(environ_map); - var verbose_air = false; - var verbose_intern_pool = false; - var verbose_generic_instances = false; - var verbose_llvm_ir: ?[]const u8 = null; - var verbose_llvm_bc: ?[]const u8 = null; + var verbose_link = (native_os != .wasi or builtin.link_libc) and + EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map); var link_depfile: ?[]const u8 = null; - var verbose_llvm_cpu_features = false; var time_report = false; var stack_report = false; var show_builtin = false; @@ -1809,24 +1796,10 @@ fn buildOutputType( } else { warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{}); } - } else if (mem.eql(u8, arg, "--verbose-link")) { - verbose_link = true; } else if (mem.eql(u8, arg, "--verbose-cc")) { verbose_cc = true; - } else if (mem.eql(u8, arg, "--verbose-air")) { - verbose_air = true; - } else if (mem.eql(u8, arg, "--verbose-intern-pool")) { - verbose_intern_pool = true; - } else if (mem.eql(u8, arg, "--verbose-generic-instances")) { - verbose_generic_instances = true; - } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { - verbose_llvm_ir = "-"; - } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| { - verbose_llvm_ir = rest; - } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| { - verbose_llvm_bc = rest; - } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) { - verbose_llvm_cpu_features = true; + } else if (mem.eql(u8, arg, "--verbose-link")) { + verbose_link = true; } else if (mem.cutPrefix(u8, arg, "-T")) |rest| { linker_script = rest; } else if (mem.cutPrefix(u8, arg, "-L")) |rest| { @@ -3729,13 +3702,7 @@ fn buildOutputType( .libc_installation = if (create_module.libc_installation) |*lci| lci else null, .verbose_cc = verbose_cc, .verbose_link = verbose_link, - .verbose_air = verbose_air, - .verbose_intern_pool = verbose_intern_pool, - .verbose_generic_instances = verbose_generic_instances, - .verbose_llvm_ir = verbose_llvm_ir, - .verbose_llvm_bc = verbose_llvm_bc, .link_depfile = link_depfile, - .verbose_llvm_cpu_features = verbose_llvm_cpu_features, .time_report = time_report, .stack_report = stack_report, .build_id = build_id, @@ -3956,10 +3923,10 @@ fn buildOutputType( }); } - try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); - for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); - if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); + try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); + for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); + if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); } try runOrTest( @@ -5627,17 +5594,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: } } - const display_path = zig_source_path orelse ""; + const print_path = zig_source_path orelse ""; const source: [:0]const u8 = s: { var f = if (zig_source_path) |p| file: { break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| { - fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err }); + fatal("unable to open file {q} for ast-check: {t}", .{ print_path, err }); }; } else Io.File.stdin(); defer if (zig_source_path != null) f.close(io); var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| { - fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err }); + fatal("unable to load file {q} for ast-check: {t}", .{ print_path, err }); }; }; @@ -5661,7 +5628,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: if (zir.hasCompileErrors()) { var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena); - try wip_errors.addZirErrorMessages(zir, tree, source, display_path); + try wip_errors.addZirErrorMessages(zir, tree, source, print_path); var error_bundle = try wip_errors.toOwnedBundle(""); try error_bundle.renderToStderr(io, .{}, color); if (zir.loweringFailed()) { @@ -5731,7 +5698,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: const zoir = try ZonGen.generate(arena, tree, .{}); if (zoir.hasCompileErrors()) { var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena); - try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path); + try wip_errors.addZoirErrorMessages(zoir, tree, source, print_path); var error_bundle = try wip_errors.toOwnedBundle(""); error_bundle.renderToStderr(io, .{}, color) catch {}; process.exit(1); @@ -6254,9 +6221,8 @@ fn randInt(io: Io, comptime T: type) T { } fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void { - if (!build_options.enable_logging) { - warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}); - } else { - try log_scopes.append(arena, scope_name); + switch (build_options.log_level) { + else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}), + .debug => try log_scopes.put(arena, try arena.dupe(u8, scope_name), {}), } } diff --git a/src/target.zig b/src/target.zig index f3fe06954f6789aec3a18bb1d91f2fb1ef6642b2..3f6edf8c63673c36abcbbf2b0faf41397df5cfd2 100644 --- a/src/target.zig +++ b/src/target.zig @@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat) .coff, .elf, .hex, + .llvmbc, + .llvmir, .macho, .spirv, .raw, diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index aeb838d10f1040998696fc624b3222685ae6d834..56875833b3ff992cd058062b53bf2421a416aa25 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi // Code generation phase codegen_pm.run(llvm_module); + if (options->llvm_ir_out != nullptr) { + *options->llvm_ir_out = LLVMPrintModuleToString(module_ref); + } + if (options->llvm_ir_filename) { if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) { return true; @@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi auto os = raw_string_ostream(out_str); TimerGroup::printAll(os); TimerGroup::clearAll(); - auto c_str = (char *)malloc(out_str.length() + 1); - strcpy(c_str, out_str.c_str()); - *options->time_report_out = c_str; + *options->time_report_out = LLVMCreateMessage(out_str.c_str()); } return false; } diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 79ba0272df2f73743705ac832f5d508b5099542d..c5e9492b8c244b0444fbf409d4be3f6c84149b18 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions { bool is_debug; bool is_small; // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this - // `char *` will be populated with a `malloc`-allocated string containing the serialized (as - // JSON) time report data. The caller is responsible for freeing that memory. + // `char *` will be populated with the serialized (as JSON) time report data. The caller is + // responsible for freeing that memory with `disposeMessage`. char **time_report_out; bool tsan; bool sancov; @@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions { const char *bin_filename; const char *llvm_ir_filename; const char *bitcode_filename; + // If not null and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this + // `char *` will be populated with the optimized LLVM IR. The caller is responsible for freeing + // this memory with `disposeMessage`. + char **llvm_ir_out; ZigLLVMCoverageOptions coverage; }; diff --git a/stage1/config.zig.in b/stage1/config.zig.in index d975f286a0fd52360326971d73f3b4a294169df1..d75edde720b9336f7786ba814fa50dbcfbb59ad5 100644 --- a/stage1/config.zig.in +++ b/stage1/config.zig.in @@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false; pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@"; pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable; pub const enable_debug_extensions = false; -pub const enable_logging = false; +pub const log_level: @import("std").log.Level = .err; pub const enable_link_snapshots = false; pub const enable_tracy = false; pub const value_tracing = false; -- 2.54.0 From 203bbaee07dfd8e67ea102dbb29afb75be246e53 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 14 Oct 2026 10:21:20 -0400 Subject: [PATCH 5/9] main: support multiple non-incremental protocol update messages --- src/Compilation.zig | 317 ++++++++++++++++++--------------- src/Zcu.zig | 406 ++++++++++++++++++++++++++---------------- src/Zcu/PerThread.zig | 90 +++++----- src/main.zig | 5 +- test/src/Cases.zig | 1 - 5 files changed, 475 insertions(+), 344 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index cae0acc1ffafd1231f9cfd451041d5c0ae536498..94dad2b74fa251bafaa9dd8246d52d8e45fdf0e1 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -20,7 +20,6 @@ const link = @import("link.zig"); const tracy = @import("tracy.zig"); const trace = tracy.trace; const build_options = @import("build_options"); -const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; const LibCInstallation = std.zig.LibCInstallation; const glibc = @import("libs/glibc.zig"); const musl = @import("libs/musl.zig"); @@ -148,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma pub fn values(_: @This()) [0]void { return .{}; } + pub fn clearRetainingCapacity(_: @This()) void {} pub fn deinit(_: @This(), _: Allocator) void {} } = .{}, @@ -238,8 +238,6 @@ reference_trace: ?u32 = null, /// This mutex guards all `Compilation` mutable state. mutex: std.Io.Mutex = .init, -test_filters: []const []const u8, - link_prog_node: std.Progress.Node = .none, llvm_opt_bisect_limit: c_int, @@ -1635,28 +1633,11 @@ pub const CreateOptions = struct { }; }; -fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void { - assert(zcu.module_roots.count() != 0); // module_roots is populated - - for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| { - if (mod == zcu.std_mod) continue; // redundant - if (opt_mod_root_file.unwrap()) |mod_root_file| { - if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant - } - cache_helpers.addModule(hash, mod); - hash.add(mod.root.root); - hash.addBytes(mod.root.sub_path); - hash.addBytes(mod.root_src_path); - hash.addListOfBytes(mod.deps.keys()); - } -} - const RtStrat = enum { none, lib, obj, zcu }; pub const CreateDiagnostic = union(enum) { export_table_import_table_conflict, emit_h_without_zcu, - illegal_zig_import, cross_libc_unavailable, find_native_libc: std.zig.LibCInstallation.FindError, libc_installation_missing_cc_dir, @@ -1672,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) { switch (diag) { .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"), .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"), - .illegal_zig_import => try w.writeAll("this compiler implementation does not support importing the root source file of a provided module"), .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"), .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}), .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"), @@ -1720,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, const use_llvm = options.config.use_llvm; const target = &options.root_mod.resolved_target.result; - const comp: *Compilation = comp: { + const comp = comp: { // We put the `Compilation` itself in the arena. Freeing the arena will free the module. // It's initialized later after we prepare the initialization options. const root_name = try arena.dupeSentinel(u8, options.root_name, 0); @@ -1988,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, // TODO audit this and make sure everything is in it const comp = try arena.create(Compilation); - const opt_zcu: ?*Zcu = if (have_zcu) blk: { + const opt_zcu = if (have_zcu) blk: { // Pre-open the directory handles for cached ZIR code so that it does not need // to redundantly happen for each AstGen operation. const zir_sub_dir = "z"; @@ -2041,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, zcu.* = .{ .gpa = gpa, .comp = comp, - .main_mod = main_mod, + .llvm_object = null, + .root_mod = options.root_mod, + .main_mod = main_mod, .std_mod = std_mod, + .sema_prog_node = .none, + .codegen_prog_node = .none, + .pending_codegen_jobs = .init(0), + + .cur_sema_prog_node = .none, + .global_zir_cache = global_zir_cache, .local_zir_cache = local_zir_cache, + + .all_exports = .empty, + .free_exports = .empty, + .single_exports = .empty, + .multi_exports = .empty, + + .module_roots = .empty, + .builtin_modules = .empty, + + .import_table = .empty, + .alive_files = .empty, + .embed_table = .empty, + + .intern_pool = .empty, + + .compile_logs = .empty, + .compile_log_lines = .empty, + .free_compile_log_lines = .empty, + + .illegal_module_root = null, + .multi_module_err = null, + .failed_imports = .empty, + .failed_files = .empty, + .skip_analysis_this_update = false, + .analysis_in_progress = .empty, + .failed_analysis = .empty, + .transitive_failed_analysis = .empty, + .dependency_loops = .empty, + .dependency_loop_nodes = .empty, + .failed_codegen = .empty, + .failed_types = .empty, + .failed_exports = .empty, + .error_limit = error_limit, - .llvm_object = null, + + .outdated_lock = if (std.debug.runtime_safety) .init, + .potentially_outdated = .empty, + .outdated = .empty, + .outdated_ready = .{ + .funcs = .empty, + .other = .empty, + }, + .retryable_failures = .empty, + .analysis_roots_buffer = undefined, .analysis_roots_len = 0, + .resolved_references = null, + + .test_filters = options.test_filters, + .test_functions = .empty, + + .global_assembly = .empty, + + .reference_table = .empty, + .all_references = .empty, + .free_references = .empty, + + .inline_reference_frames = .empty, + .free_inline_reference_frames = .empty, + + .type_reference_table = .empty, + .all_type_references = .empty, + .free_type_references = .empty, + + .std_lang_decl_values = .initFill(.none), + + .incremental_debug_state = if (build_options.enable_debug_extensions) .init, + + .cur_analysis_timer = null, + .codegen_task_pool = try .init(arena), + + .generation = 0, + .anon_name_counter = 0, }; - try zcu.init(gpa, io, options.thread_limit); break :blk zcu; } else blk: { if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu); @@ -2091,7 +2147,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, .reference_trace = options.reference_trace, .time_report = if (options.time_report) .init else null, .stack_report = options.stack_report, - .test_filters = options.test_filters, .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, .debug_compile_errors = options.debug_compile_errors, .debug_incremental = options.debug_incremental, @@ -2143,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, comp.config.any_sanitize_c = any_sanitize_c; comp.config.any_fuzz = any_fuzz; - if (opt_zcu) |zcu| { - // Finish initializing the `zcu` after the fields on `comp` have been initialized. - zcu.initAfterCompilation(); - - // Populate `zcu.module_roots`. - const active = zcu.acquire(); - defer active.release(); - active.pt.populateModuleRootTable() catch |err| switch (err) { - error.OutOfMemory => |e| return e, - error.IllegalZigImport => return diag.fail(.illegal_zig_import), - }; - } + // Initialize the `zcu` after the fields on `comp` have been initialized. + if (opt_zcu) |zcu| zcu.init(); const lf_open_opts: link.File.OpenOptions = .{ .linker_script = options.linker_script, @@ -2250,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, hash.add(options.config.is_test); hash.addListOfBytes(options.test_filters); hash.add(options.skip_linker_dependencies); - hash.add(options.emit_h != .no); + //hash.add(options.emit_h != .no); hash.add(error_limit); - // Here we put the root source file path name, but *not* with addFile. - // We want the hash to be the same regardless of the contents of the - // source file, because incremental compilation will handle it, but we - // do want to namespace different source file names because they are - // likely different compilations and therefore this would be likely to - // cause cache hits. - if (comp.zcu) |zcu| { - try addModuleTableToCacheHash(zcu, &hash); - } else { - cache_helpers.addModule(&hash, options.root_mod); - } + try comp.addModuleTableToCacheHash(&hash); // In the case of incremental cache mode, this `artifact_directory` // is computed based on a hash of non-linker inputs, and it is where all @@ -2315,22 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, comp.cache_use = .{ .whole = whole }; }, } - - if (use_llvm and - (comp.emit_bin != null or - comp.emit_asm != null or - comp.emit_llvm_ir != null or - comp.emit_llvm_bc != null or - log_llvm_ir: { - break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir"); - })) - { - if (opt_zcu) |zcu| { - dev.check(.llvm_backend); - zcu.llvm_object = try LlvmObject.create(arena, zcu); - } - } - break :comp comp; }; errdefer comp.destroy(); @@ -2599,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void { } comp.win32_resources.deinit(gpa); - for (comp.failed_win32_resources.values()) |*value| { - value.deinit(gpa); + for (comp.failed_win32_resources.values()) |*bundle| { + bundle.deinit(gpa); } comp.failed_win32_resources.deinit(gpa); @@ -2624,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void { comp.misc_failures = .{}; } -pub fn getTarget(self: *const Compilation) *const Target { - return &self.root_mod.resolved_target.result; +pub fn getTarget(comp: *const Compilation) *const Target { + return &comp.root_mod.resolved_target.result; } /// Only legal to call when cache mode is incremental and a link file is present. @@ -2644,6 +2663,18 @@ pub fn hotCodeSwap( fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { const io = comp.io; + if (comp.bin_file) |lf| { + lf.endProgress(); + comp.link_prog_node.end(); + comp.link_prog_node = .none; + switch (comp.cache_use) { + .none, .whole => { + lf.destroy(); + comp.bin_file = null; + }, + .incremental => {}, + } + } switch (comp.cache_use) { .none => |none| { if (none.tmp_artifact_directory) |*tmp_dir| { @@ -2660,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { // replicated in the output binary (the output instead contains a reference to that // file which debug tooling can look through). So, in that particular case, we need // to keep this directory around so that the output binary can be debugged. - if (comp.bin_file != null and comp.getTarget().ofmt == .macho and comp.config.debug_format != .strip) { - // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU - // object file must remain on-disk for its debug info. - return; + if (comp.bin_file == null or comp.getTarget().ofmt != .macho or comp.config.debug_format == .strip) { + const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); + comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { + log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ + comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, + }); + }; } - const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); - comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { - log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{ - comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err, - }); - }; } }, .incremental => return, @@ -2679,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { man.deinit(); whole.cache_manifest = null; } - if (comp.bin_file) |lf| { - lf.destroy(); - comp.bin_file = null; - } if (whole.tmp_artifact_directory) |*tmp_dir| { tmp_dir.handle.close(io); whole.tmp_artifact_directory = null; @@ -2695,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { } }, } + assert(!comp.config.incremental); // always uses incremental cache mode + if (comp.zcu) |zcu| { + if (zcu.llvm_object) |llvm_object| { + llvm_object.deinit(); + zcu.llvm_object = null; + } + } } pub const UpdateError = error{ @@ -2716,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - comp.clearMiscFailures(); - comp.last_update_was_cache_hit = false; - if (comp.time_report) |*tr| { - tr.deinit(gpa); // this is information about an old update - tr.* = .init; + reset: { + comp.clearMiscFailures(); + comp.last_update_was_cache_hit = false; + if (comp.time_report) |*tr| { + tr.deinit(comp.gpa); + tr.* = .init; + } + if (comp.file_system_inputs) |file_system_inputs| file_system_inputs.clearRetainingCapacity(); + + if (comp.zcu) |zcu| { + zcu.skip_analysis_this_update = false; + if (zcu.generation > 0) break :reset; + try zcu.reset(arena); + } + for (comp.failed_c_objects.values()) |bundle| bundle.destroy(comp.gpa); + comp.failed_c_objects.clearRetainingCapacity(); + for (comp.failed_win32_resources.values()) |*bundle| bundle.deinit(comp.gpa); + comp.failed_win32_resources.clearRetainingCapacity(); } var tmp_dir_rand_int: u64 = undefined; @@ -2865,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE if (comp.zcu) |zcu| { assert(zcu.cur_analysis_timer == null); - zcu.skip_analysis_this_update = false; - // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! for (zcu.embed_table.keys()) |embed_file| { try comp.appendFileSystemInput(embed_file.path); } - - zcu.analysis_roots_len = 0; - - zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; - zcu.analysis_roots_len += 1; - - // Normally we rely on importing std to in turn import the root source file in the start code. - // However, the main module is distinct from the root module in tests, so that won't happen there. - if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { - zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; - zcu.analysis_roots_len += 1; - } - - if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { - zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; - zcu.analysis_roots_len += 1; - } - - if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { - zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; - zcu.analysis_roots_len += 1; - } - - if (zcu.root_mod.deps.get("zigc")) |zigc_mod| { - zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod; - zcu.analysis_roots_len += 1; - } } // The linker progress node is set up here instead of in `performAllTheWork`, because @@ -2919,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); lf.startProgress(comp.link_prog_node); } - defer if (comp.bin_file) |lf| { - lf.endProgress(); - comp.link_prog_node.end(); - comp.link_prog_node = .none; - }; try comp.performAllTheWork(main_progress_node, arena); @@ -2969,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); }; - if (anyErrors(comp)) { + if (comp.anyErrors()) { // Skip flushing and keep source files loaded for error reporting. return; } @@ -2983,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE } switch (comp.cache_use) { - .none, .incremental => try flush(comp, arena), + .none, .incremental => try comp.flush(arena), .whole => |whole| { if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); if (comp.parent_whole_cache) |pwc| { @@ -3064,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE }; } - try flush(comp, arena); + try comp.flush(arena); // Calling `flush` may have produced errors, in which case the // cache manifest must not be written. - if (anyErrors(comp)) return; + if (comp.anyErrors()) return; // Release the lock and close the file before writing the manifest. // This avoids the potential of another process getting a cache hit and @@ -3168,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error defer tid.release(io); 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); @@ -3303,23 +3312,42 @@ fn renameTmpIntoCache( /// anything from the link cache manifest. pub const link_hash_implementation_version = 14; -fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { - comptime assert(link_hash_implementation_version == 14); +fn addModuleTableToCacheHash(comp: *Compilation, hash: *Cache.HashHelper) Allocator.Error!void { + const gpa = comp.gpa; + var mods: std.array_hash_map.Auto(*Module, void) = .empty; + defer mods.deinit(gpa); + + try mods.putNoClobber(gpa, comp.root_mod, {}); + if (comp.zcu) |zcu| try mods.put(gpa, zcu.main_mod, {}); + + var mod_index: usize = 0; + while (mod_index < mods.count()) : (mod_index += 1) { + const mod = mods.keys()[mod_index]; - if (comp.zcu) |zcu| { // No need to hash the actual file contents here because it is // redundant with the logic in `PerThread.update` which iterates over // `zcu.alive_files` and adds those files discovered via `@import` to // the whole cache manifest. - try addModuleTableToCacheHash(zcu, &man.hash); + cache_helpers.addModule(hash, mod); + hash.add(mod.root.root); + hash.addBytes(mod.root.sub_path); + hash.addBytes(mod.root_src_path); + hash.addListOfBytes(mod.deps.keys()); + for (mod.deps.values()) |dep_mod| try mods.put(gpa, dep_mod, {}); + } +} + +fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { + comptime assert(link_hash_implementation_version == 14); + + try comp.addModuleTableToCacheHash(&man.hash); + + if (comp.zcu) |zcu| { // Synchronize with other matching comments: ZigOnlyHashStuff - man.hash.addListOfBytes(comp.test_filters); - man.hash.add(comp.skip_linker_dependencies); + man.hash.addListOfBytes(zcu.test_filters); //man.hash.add(zcu.emit_h != .no); man.hash.add(zcu.error_limit); - } else { - cache_helpers.addModule(&man.hash, comp.root_mod); } try link.hashInputs(man, comp.link_inputs); @@ -3788,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void { } /// This function is temporally single-threaded. -pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { +pub fn getAllErrorsAlloc(comp: *Compilation) Allocator.Error!ErrorBundle { const gpa = comp.gpa; const io = comp.io; @@ -3831,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { } if (comp.zcu) |zcu| zcu_errors: { + if (zcu.illegal_module_root) |mod| { + try bundle.addRootErrorMessage(.{ + .msg = try bundle.printString( + "this compiler implementation does not support using '{f}/{s}' as the root of module '{s}'", + .{ mod.root.fmt(comp), mod.root_src_path, mod.fully_qualified_name }, + ), + .notes_len = 0, + }); + } if (zcu.multi_module_err != null) { try zcu.addFileInMultipleModulesError(&bundle); break :zcu_errors; @@ -4359,7 +4396,9 @@ fn performAllTheWork( defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); if (comp.zcu) |zcu| { // Regardless of errors, `comp.zcu` needs to update its generation number. - defer zcu.generation += 1; + defer if (comp.config.incremental) { + zcu.generation += 1; + }; const active = zcu.acquire(); defer active.release(); try active.pt.update(main_progress_node, &decl_work_timer); diff --git a/src/Zcu.zig b/src/Zcu.zig index 01b136b01514721616febf43f65827b36d0ced4f..fdae0d840a69e6bc19ebddb32788b1598fef9865 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit; const BuiltinFn = std.zig.BuiltinFn; const codegen = @import("codegen.zig"); const LlvmObject = @import("codegen/llvm.zig").Object; +const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; const dev = @import("dev.zig"); const Zoir = std.zig.Zoir; const ZonGen = std.zig.ZonGen; @@ -69,18 +70,18 @@ root_mod: *Module, /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests. main_mod: *Module, std_mod: *Module, -sema_prog_node: std.Progress.Node = .none, -codegen_prog_node: std.Progress.Node = .none, +sema_prog_node: std.Progress.Node, +codegen_prog_node: std.Progress.Node, /// 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), +pending_codegen_jobs: std.atomic.Value(u32), /// 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, +cur_sema_prog_node: std.Progress.Node, /// Used by AstGen worker to load and store ZIR cache. global_zir_cache: Cache.Directory, @@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory, /// This is where all `Export` values are stored. Not all values here are necessarily valid exports; /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted. -all_exports: std.ArrayList(Export) = .empty, +all_exports: std.ArrayList(Export), /// This is a list of free indices in `all_exports`. These indices may be reused by exports from /// future semantic analysis. -free_exports: std.ArrayList(Export.Index) = .empty, +free_exports: std.ArrayList(Export.Index), /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` /// whose analysis triggered the export. -single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty, +single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index), /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. /// The exports are `all_exports.items[index..][0..len]`. multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct { index: u32, len: u32, -}) = .empty, - -/// Key is the digest returned by `Builtin.hash`; value is the corresponding module. -builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module) = .empty, +}), /// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones. /// Modules whose root file is not a Zig or ZON file have the value `.none`. -module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional) = .empty, +module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional), +/// Key is the digest returned by `Builtin.hash`; value is the corresponding module. +builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module), /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in /// order to iterate over it and check which source files have been modified on @@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom( pub const eql = @compileError("all accesses should be through ImportTableAdapter"); }, true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 -) = .empty, - +), /// The set of all files in `import_table` which are "alive" this update, meaning /// they are reachable by traversing imports starting from an analysis root. This /// is usually all files in `import_table`, but some could be omitted if an incremental /// update removes an import, or if a module specified on the CLI is never imported. /// Reconstructed on every update, after AstGen and before Sema. /// Value is why the file is alive. -alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty, - -/// If this is populated, a "file exists in multiple modules" error should be emitted. -/// This causes file errors to not be shown, because we don't really know which files -/// should be alive (because the user has messed up their imports somewhere!). -/// Cleared and recomputed every update, after AstGen and before Sema. -multi_module_err: ?struct { - file: File.Index, - modules: [2]*Module, - refs: [2]File.Reference, -} = null, - +alive_files: std.array_hash_map.Auto(File.Index, File.Reference), /// The set of all the files which have been loaded with `@embedFile` in the Module. /// We keep track of this in order to iterate over it and check which files have been /// modified on the file system when an update is requested, as well as to cache @@ -162,49 +150,19 @@ multi_module_err: ?struct { /// /// This table owns all of the `*EmbedFile` memory, which is allocated into gpa. embed_table: std.array_hash_map.Custom( - *EmbedFile, + EmbedFile, void, struct { pub const hash = @compileError("all accesses should be through EmbedTableAdapter"); pub const eql = @compileError("all accesses should be through EmbedTableAdapter"); }, true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 -) = .empty, +), /// Stores all Type and Value objects. /// The idea is that this will be periodically garbage-collected, but such logic /// is not yet implemented. -intern_pool: InternPool = .empty, - -/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis -/// (index 0), and non-`null` for all others. -analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason) = .empty, -/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. -failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty, -/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. -transitive_failed_analysis: std.array_hash_map.Auto( - AnalUnit, - if (build_options.enable_debug_extensions) TransitiveFailureReason else void, -) = .empty, -/// 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.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty, -failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg) = .empty, - -/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one -/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible -/// between compilations. So, instead of (for instance) defining where the dependency loop "starts", -/// this map simply exists to allow easily iterating all dependency loops exactly once. -dependency_loops: std.array_hash_map.Auto(AnalUnit, void) = .empty, -/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so. -/// All units in here form loops. To iterate loops, see `dependency_loops`. -dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { - unit: AnalUnit, - reason: DependencyReason, -}) = .empty, +intern_pool: InternPool, /// Keep track of `@compileLog`s per `AnalUnit`. /// We track the source location of the first `@compileLog` call, and all logged lines as a linked list. @@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct { .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset), }; } -}) = .empty, -compile_log_lines: std.ArrayList(CompileLogLine) = .empty, -free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty, -/// This tracks files which triggered errors when generating AST/ZIR/ZOIR. -/// If not `null`, the value is a retryable error (the file status is guaranteed -/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` -/// or `.success`, and there are ZIR/ZOIR errors which should be printed. -/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source -/// location is always the entire file. The `[]u8` memory is owned by the map -/// and allocated into `gpa`. -failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty, +}), +compile_log_lines: std.ArrayList(CompileLogLine), +free_compile_log_lines: std.ArrayList(CompileLogLine.Index), + +illegal_module_root: ?*Module, +/// If this is populated, a "file exists in multiple modules" error should be emitted. +/// This causes file errors to not be shown, because we don't really know which files +/// should be alive (because the user has messed up their imports somewhere!). +/// Cleared and recomputed every update, after AstGen and before Sema. +multi_module_err: ?struct { + file: File.Index, + modules: [2]*Module, + refs: [2]File.Reference, +}, /// AstGen is not aware of modules, and so cannot determine whether an import /// string makes sense. That is the job of a traversal after AstGen. /// @@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct { import_string: Zir.NullTerminatedString, import_token: Ast.TokenIndex, kind: enum { file_outside_module_root, illegal_zig_import }, -}) = .empty, -failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty, -/// If analysis failed due to a cimport error, the corresponding Clang errors -/// are stored here. -cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty, +}), +/// This tracks files which triggered errors when generating AST/ZIR/ZOIR. +/// If not `null`, the value is a retryable error (the file status is guaranteed +/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` +/// or `.success`, and there are ZIR/ZOIR errors which should be printed. +/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source +/// location is always the entire file. The `[]u8` memory is owned by the map +/// and allocated into `gpa`. +failed_files: std.array_hash_map.Auto(File.Index, ?[]u8), +/// If `true`, then semantic analysis must not occur on this update due to AstGen errors. +/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. +/// Reset to `false` at the start of each update in `Compilation.update`. +skip_analysis_this_update: bool, +/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis +/// (index 0), and non-`null` for all others. +analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason), +/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator. +failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg), +/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. +transitive_failed_analysis: std.array_hash_map.Auto( + AnalUnit, + if (build_options.enable_debug_extensions) TransitiveFailureReason else void, +), +/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one +/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible +/// between compilations. So, instead of (for instance) defining where the dependency loop "starts", +/// this map simply exists to allow easily iterating all dependency loops exactly once. +dependency_loops: std.array_hash_map.Auto(AnalUnit, void), +/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so. +/// All units in here form loops. To iterate loops, see `dependency_loops`. +dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { + unit: AnalUnit, + reason: DependencyReason, +}), +/// 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.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg), +failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg), +failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg), /// Maximum amount of distinct error values, set by --error-limit error_limit: ErrorInt, @@ -269,14 +267,14 @@ error_limit: ErrorInt, /// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock /// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the /// lock is not needed and is compiled out. -outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init, +outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void, /// Value is the number of PO dependencies of this AnalUnit. /// This value will decrease as we perform semantic analysis to learn what is outdated. /// If any of these PO deps is outdated, this value will be moved to `outdated`. -potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, +potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32), /// Value is the number of PO dependencies of this AnalUnit. /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. -outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, +outdated: std.array_hash_map.Auto(AnalUnit, u32), /// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0. /// Such `AnalUnit`s are ready for immediate re-analysis. /// See `findOutdatedToAnalyze` for details. @@ -286,69 +284,64 @@ outdated_ready: struct { funcs: std.array_hash_map.Auto(InternPool.Index, void), /// Does not contain `.func` units. other: std.array_hash_map.Auto(AnalUnit, void), -} = .{ .funcs = .empty, .other = .empty }, +}, /// This contains a list of AnalUnit whose analysis or codegen failed, but the /// failure was something like running out of disk space, and trying again may /// succeed. On the next update, we will flush this list, marking all members of /// it as outdated. -retryable_failures: std.ArrayList(AnalUnit) = .empty, +retryable_failures: std.ArrayList(AnalUnit), /// These are the modules which we initially queue for analysis in `Compilation.update`. /// `resolveReferences` will use these as the root of its reachability traversal. analysis_roots_buffer: [5]*Module, -analysis_roots_len: usize = 0, +analysis_roots_len: usize, /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and /// reset to `null` when any semantic analysis occurs (since this invalidates the data). /// Allocated into `gpa`. -resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null, +resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference), -/// If `true`, then semantic analysis must not occur on this update due to AstGen errors. -/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped. -/// Reset to `false` at the start of each update in `Compilation.update`. -skip_analysis_this_update: bool = false, +test_filters: []const []const u8, +test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void), -test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, - -global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty, +global_assembly: std.array_hash_map.Auto(AnalUnit, []u8), /// Key is the `AnalUnit` *performing* the reference. This representation allows /// incremental updates to quickly delete references caused by a specific `AnalUnit`. /// Value is index into `all_references` of the first reference triggered by the unit. /// The `next` field on the `Reference` forms a linked list of all references /// triggered by the key `AnalUnit`. -reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, -all_references: std.ArrayList(Reference) = .empty, +reference_table: std.array_hash_map.Auto(AnalUnit, u32), +all_references: std.ArrayList(Reference), /// Freelist of indices in `all_references`. -free_references: std.ArrayList(u32) = .empty, +free_references: std.ArrayList(u32), -inline_reference_frames: std.ArrayList(InlineReferenceFrame) = .empty, -free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty, +inline_reference_frames: std.ArrayList(InlineReferenceFrame), +free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index), /// Key is the `AnalUnit` *performing* the reference. This representation allows /// incremental updates to quickly delete references caused by a specific `AnalUnit`. /// Value is index into `all_type_reference` of the first reference triggered by the unit. /// The `next` field on the `TypeReference` forms a linked list of all type references /// triggered by the key `AnalUnit`. -type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, -all_type_references: std.ArrayList(TypeReference) = .empty, +type_reference_table: std.array_hash_map.Auto(AnalUnit, u32), +all_type_references: std.ArrayList(TypeReference), /// Freelist of indices in `all_type_references`. -free_type_references: std.ArrayList(u32) = .empty, +free_type_references: std.ArrayList(u32), /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element. -std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none), +std_lang_decl_values: StdLangDecl.Memoized, -incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void = - if (build_options.enable_debug_extensions) .init else {}, +incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void, /// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit, /// this timer must be temporarily paused and resumed later. -cur_analysis_timer: ?Compilation.Timer = null, +cur_analysis_timer: ?Compilation.Timer, codegen_task_pool: CodegenTaskPool, -generation: u32 = 0, +generation: u32, -/// Only access from the Sema thread. +/// Only accessed from the Sema thread. anon_name_counter: u32, pub const DependencyReason = struct { @@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct { _ = ctx; return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path)); } - pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool { + pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: EmbedFile, b_index: usize) bool { _ = ctx; _ = b_index; const b_path = b_file.path; @@ -1250,10 +1243,15 @@ pub const EmbedFile = struct { pub const Index = enum(u32) { _, - pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile { - return zcu.embed_table.keys()[@backingInt(idx)]; + pub fn get(idx: Index, zcu: *const Zcu) *const EmbedFile { + return &zcu.embed_table.keys()[@backingInt(idx)]; } }; + + pub fn deinit(ef: *EmbedFile, gpa: Allocator) void { + ef.path.deinit(gpa); + ef.* = undefined; + } }; /// This struct holds data necessary to construct API-facing `AllErrors.Message`. @@ -2894,16 +2892,130 @@ pub const CompileError = error{ ComptimeBreak, }; -pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { - try zcu.intern_pool.init(gpa, io, thread_count); -} - /// It is valid to not call this function before `deinit` in error paths. /// Requires the fields on `zcu.comp` to already be initialized. -pub fn initAfterCompilation(zcu: *Zcu) void { +pub fn init(zcu: *Zcu) void { zcu.initTracyPlots(); } +pub fn reset(zcu: *Zcu, arena: Allocator) Allocator.Error!void { + const comp = zcu.comp; + const gpa = comp.gpa; + const io = comp.io; + + zcu.all_exports.clearRetainingCapacity(); + zcu.free_exports.clearRetainingCapacity(); + zcu.single_exports.clearRetainingCapacity(); + zcu.multi_exports.clearRetainingCapacity(); + + zcu.module_roots.clearRetainingCapacity(); + // builtin modules can still be reused from a previous non-incremental update + + for (zcu.import_table.keys()) |file| zcu.destroyFile(file); + zcu.import_table.clearRetainingCapacity(); + zcu.alive_files.clearRetainingCapacity(); + for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa); + zcu.embed_table.clearRetainingCapacity(); + + zcu.compile_logs.clearRetainingCapacity(); + zcu.compile_log_lines.clearRetainingCapacity(); + zcu.free_compile_log_lines.clearRetainingCapacity(); + + zcu.illegal_module_root = null; + zcu.multi_module_err = null; + zcu.failed_imports.clearRetainingCapacity(); + for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg); + zcu.failed_files.clearRetainingCapacity(); + zcu.analysis_in_progress.clearRetainingCapacity(); + for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa); + zcu.failed_analysis.clearRetainingCapacity(); + zcu.transitive_failed_analysis.clearRetainingCapacity(); + zcu.dependency_loops.clearRetainingCapacity(); + zcu.dependency_loop_nodes.clearRetainingCapacity(); + for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa); + zcu.failed_codegen.clearRetainingCapacity(); + for (zcu.failed_types.values()) |msg| msg.destroy(gpa); + zcu.failed_types.clearRetainingCapacity(); + for (zcu.failed_exports.values()) |msg| msg.destroy(gpa); + zcu.failed_exports.clearRetainingCapacity(); + + assert(zcu.potentially_outdated.count() == 0); + assert(zcu.outdated.count() == 0); + assert(zcu.outdated_ready.funcs.count() == 0); + assert(zcu.outdated_ready.other.count() == 0); + zcu.retryable_failures.clearRetainingCapacity(); + + zcu.analysis_roots_len = 0; + zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod; + zcu.analysis_roots_len += 1; + // Normally we rely on importing std to in turn import the root source file in the start code. + // However, the main module is distinct from the root module in tests, so that won't happen there. + if (comp.config.is_test and zcu.main_mod != zcu.std_mod) { + zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod; + zcu.analysis_roots_len += 1; + } + if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| { + zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod; + zcu.analysis_roots_len += 1; + } + if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| { + zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod; + zcu.analysis_roots_len += 1; + } + if (zcu.root_mod.deps.get("zigc")) |zigc_mod| { + zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod; + zcu.analysis_roots_len += 1; + } + zcu.clearCachedResolvedReferences(); + + zcu.test_functions.clearRetainingCapacity(); + + zcu.global_assembly.clearRetainingCapacity(); + + zcu.reference_table.clearRetainingCapacity(); + zcu.all_references.clearRetainingCapacity(); + zcu.free_references.clearRetainingCapacity(); + + zcu.inline_reference_frames.clearRetainingCapacity(); + zcu.free_inline_reference_frames.clearRetainingCapacity(); + + zcu.type_reference_table.clearRetainingCapacity(); + zcu.all_type_references.clearRetainingCapacity(); + zcu.free_type_references.clearRetainingCapacity(); + + zcu.std_lang_decl_values = .initFill(.none); + + for (zcu.codegen_task_pool.task_funcs) |task_func| assert(task_func == .none); + + assert(zcu.generation == 0); + + zcu.anon_name_counter = 0; + + zcu.intern_pool.deinit(gpa, io); + zcu.intern_pool = .empty; + try zcu.intern_pool.init(gpa, io, comp.thread_limit); + + { + const active = zcu.acquire(); + defer active.release(); + try active.pt.populateModuleRootTable(); + } + + assert(zcu.llvm_object == null); + if (comp.config.use_llvm and + (comp.emit_bin != null or + comp.emit_asm != null or + comp.emit_llvm_ir != null or + comp.emit_llvm_bc != null or + log_llvm_ir: { + break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir"); + })) + { + dev.check(.llvm_backend); + zcu.llvm_object = try .create(if (comp.config.incremental) comp.arena else arena, zcu); + } +} + pub fn deinit(zcu: *Zcu) void { const comp = zcu.comp; const io = comp.io; @@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void { { if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); - zcu.builtin_modules.deinit(gpa); + zcu.global_zir_cache.handle.close(io); + zcu.local_zir_cache.handle.close(io); + + zcu.all_exports.deinit(gpa); + zcu.free_exports.deinit(gpa); + zcu.single_exports.deinit(gpa); + zcu.multi_exports.deinit(gpa); + zcu.module_roots.deinit(gpa); - for (zcu.import_table.keys()) |file_index| { - zcu.destroyFile(file_index); - } + zcu.builtin_modules.deinit(gpa); + + for (zcu.import_table.keys()) |file| zcu.destroyFile(file); zcu.import_table.deinit(gpa); zcu.alive_files.deinit(gpa); - - for (zcu.embed_table.keys()) |embed_file| { - embed_file.path.deinit(gpa); - gpa.destroy(embed_file); - } + for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa); zcu.embed_table.deinit(gpa); - zcu.local_zir_cache.handle.close(io); - zcu.global_zir_cache.handle.close(io); + zcu.compile_logs.deinit(gpa); + zcu.compile_log_lines.deinit(gpa); + zcu.free_compile_log_lines.deinit(gpa); - for (zcu.failed_analysis.values()) |value| value.destroy(gpa); - for (zcu.failed_codegen.values()) |value| value.destroy(gpa); - for (zcu.failed_types.values()) |value| value.destroy(gpa); + zcu.failed_imports.deinit(gpa); + for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg); + zcu.failed_files.deinit(gpa); zcu.analysis_in_progress.deinit(gpa); + for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa); zcu.failed_analysis.deinit(gpa); zcu.transitive_failed_analysis.deinit(gpa); zcu.dependency_loops.deinit(gpa); zcu.dependency_loop_nodes.deinit(gpa); + for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa); zcu.failed_codegen.deinit(gpa); + for (zcu.failed_types.values()) |msg| msg.destroy(gpa); zcu.failed_types.deinit(gpa); - - for (zcu.failed_files.values()) |value| { - if (value) |msg| gpa.free(msg); - } - zcu.failed_files.deinit(gpa); - zcu.failed_imports.deinit(gpa); - - for (zcu.failed_exports.values()) |value| { - value.destroy(gpa); - } + for (zcu.failed_exports.values()) |msg| msg.destroy(gpa); zcu.failed_exports.deinit(gpa); - for (zcu.cimport_errors.values()) |*errs| { - errs.deinit(gpa); - } - zcu.cimport_errors.deinit(gpa); - - zcu.compile_logs.deinit(gpa); - zcu.compile_log_lines.deinit(gpa); - zcu.free_compile_log_lines.deinit(gpa); - - zcu.all_exports.deinit(gpa); - zcu.free_exports.deinit(gpa); - zcu.single_exports.deinit(gpa); - zcu.multi_exports.deinit(gpa); - zcu.potentially_outdated.deinit(gpa); zcu.outdated.deinit(gpa); zcu.outdated_ready.funcs.deinit(gpa); zcu.outdated_ready.other.deinit(gpa); zcu.retryable_failures.deinit(gpa); + if (zcu.resolved_references) |*r| r.deinit(gpa); + zcu.test_functions.deinit(gpa); - for (zcu.global_assembly.values()) |s| { - gpa.free(s); - } + for (zcu.global_assembly.values()) |s| gpa.free(s); zcu.global_assembly.deinit(gpa); zcu.reference_table.deinit(gpa); @@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void { zcu.all_type_references.deinit(gpa); zcu.free_type_references.deinit(gpa); - if (zcu.resolved_references) |*r| r.deinit(gpa); - if (comp.debugIncremental()) { zcu.incremental_debug_state.deinit(gpa); } @@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana .unnamed_test => true, .@"test", .decltest => a: { const fqn_slice = nav.fqn.toSlice(ip); - if (comp.test_filters.len > 0) { - for (comp.test_filters) |test_filter| { + if (zcu.test_filters.len > 0) { + for (zcu.test_filters) |test_filter| { if (std.mem.find(u8, fqn_slice, test_filter) != null) break; } else break :a false; } diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index bb09f50cf02be848121d63c01e679232a6324ad7..8c789491b5b3121c3ddebd99451ff0f169d5b157 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -148,6 +148,12 @@ pub fn update( comp.link_queue.finishZcuQueue(comp); } + if (zcu.illegal_module_root) |_| { + // We cannot run AstGen because we failed to set up the module roots. We can return early + // because this is a guaranteed compile error. + return; + } + { const tracy_trace = traceNamed(@src(), "astgen"); defer tracy_trace.end(); @@ -203,11 +209,9 @@ pub fn update( // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one // `@embedFile` can't trigger analysis of a new `@embedFile`! - for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| { + for (0.., zcu.embed_table.keys()) |ef_index_usize, *ef| { const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize)); - astgen_group.async(io, workerUpdateEmbedFile, .{ - comp, ef_index, ef, - }); + astgen_group.async(io, workerUpdateEmbedFile, .{ comp, ef_index, ef }); } try astgen_group.await(io); @@ -219,8 +223,8 @@ pub fn update( // they belong to. const any_fatal_files = try pt.computeAliveFiles(); - // If the cache mode is `whole`, add every alive source file to the manifest. switch (comp.cache_use) { + .none => {}, .whole => |whole| if (whole.cache_manifest) |man| { for (zcu.alive_files.keys()) |file_index| { const file = zcu.fileByIndex(file_index); @@ -250,7 +254,11 @@ pub fn update( }; } }, - .none, .incremental => {}, + .incremental => { + // Do not include file contents in the cache manifest because we + // want the hash to be the same regardless of the contents of the + // source files so that incremental can do its thing. + }, } if (comp.time_report) |*tr| { @@ -2494,11 +2502,7 @@ pub fn doImport( } /// This is called once during `Compilation.create` and never again. "builtin" modules don't yet /// exist, so are not added to `module_roots` here. They must be added when they are created. -pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ - OutOfMemory, - /// One of the specified modules had its root source file at an illegal path. - IllegalZigImport, -}!void { +pub fn populateModuleRootTable(pt: Zcu.PerThread) Allocator.Error!void { const zcu = pt.zcu; const comp = zcu.comp; const gpa = comp.gpa; @@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ // We'll initially add [mod, undefined] pairs, and when we reach the pair while // iterating, rewrite the undefined value. const roots = &zcu.module_roots; - roots.clearRetainingCapacity(); + assert(roots.count() == 0); // Start with: // * `std_mod`, which is the main root of analysis @@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ errdefer path.deinit(gpa); if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) { - return error.IllegalZigImport; + // One of the specified modules had its root source file at an illegal path. + zcu.illegal_module_root = mod; + return; } const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu }); @@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct const gpa = comp.gpa; const io = comp.io; - const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); - if (gop.found_existing) return .{ // the `File` is up-to-date - .file = zcu.module_roots.get(gop.value_ptr.*).?.unwrap().?, - .module_root = gop.value_ptr.*, + const mod: *Module = mod: { + const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); + if (!gop.found_existing) { + errdefer _ = zcu.builtin_modules.pop(); + gop.value_ptr.* = try .createBuiltin(comp.arena, opts, comp.dirs); + } + const mod = gop.value_ptr.*; + assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin + break :mod mod; }; - errdefer _ = zcu.builtin_modules.pop(); - const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs); - assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin + if (zcu.module_roots.get(mod)) |file| { + // We have already loaded this builtin.zig before! + return .{ .file = file.unwrap().?, .module_root = mod }; + } const path = try mod.root.join(gpa, comp.dirs, "builtin.zig"); errdefer path.deinit(gpa); @@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct .root_type = .none, }); - gop.value_ptr.* = mod; file_gop.key_ptr.* = file_index; zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional()); try opts.populateFile(gpa, file); @@ -2883,22 +2894,19 @@ pub fn embedFile( return @fromBackingInt(@intCast(gop.index)); } errdefer _ = zcu.embed_table.pop(); - gop.key_ptr.* = try pt.newEmbedFile(path); + try pt.initEmbedFile(gop.key_ptr, path); return @fromBackingInt(@intCast(gop.index)); } - const embed_file: *Zcu.EmbedFile, const embed_file_idx: Zcu.EmbedFile.Index = ef: { + const embed_file, const embed_file_idx: Zcu.EmbedFile.Index = ef: { const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string); errdefer path.deinit(gpa); const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{}); - if (gop.found_existing) { - path.deinit(gpa); // we're not using this key - break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) }; - } else { + if (!gop.found_existing) { errdefer _ = zcu.embed_table.pop(); - gop.key_ptr.* = try pt.newEmbedFile(path); - break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) }; - } + try pt.initEmbedFile(gop.key_ptr, path); + } else path.deinit(gpa); // we're not using this key + break :ef .{ gop.key_ptr, @fromBackingInt(@intCast(gop.index)) }; }; switch (embed_file.path.isNested(cur_file.mod.?.root)) { @@ -2913,7 +2921,7 @@ pub fn updateEmbedFile( pt: Zcu.PerThread, ef: *Zcu.EmbedFile, /// If not `null`, the interned file data is stored here, if it was loaded. - /// `newEmbedFile` uses this to add the file to the `whole` cache manifest. + /// `initEmbedFile` uses this to add the file to the `whole` cache manifest. ip_str_out: ?*?InternPool.String, ) Allocator.Error!void { pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) { @@ -3000,17 +3008,13 @@ fn updateEmbedFileInner( } /// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success. -fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.EmbedFile { +fn initEmbedFile(pt: Zcu.PerThread, ef: *Zcu.EmbedFile, path: Compilation.Path) EmbedFileError!void { const zcu = pt.zcu; const comp = zcu.comp; const io = comp.io; - const gpa = comp.gpa; const ip = &zcu.intern_pool; - const new_file = try gpa.create(Zcu.EmbedFile); - errdefer gpa.destroy(new_file); - - new_file.* = .{ + ef.* = .{ .path = path, .val = .none, .err = null, @@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E }; var opt_ip_str: ?InternPool.String = null; - try pt.updateEmbedFile(new_file, &opt_ip_str); + try pt.updateEmbedFile(ef, &opt_ip_str); try comp.appendFileSystemInput(path); @@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E const man = whole.cache_manifest orelse break :cache; const ip_str = opt_ip_str orelse break :cache; // this will be a compile error - const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu); + const array_len = Value.fromInterned(ef.val).typeOf(zcu).childType(zcu).arrayLen(zcu); const contents = ip_str.toSlice(array_len, ip); try whole.cache_manifest_mutex.lock(io); defer whole.cache_manifest_mutex.unlock(io); - path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, new_file.stat) catch |err| switch (err) { + path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, ef.stat) catch |err| switch (err) { error.FileSystemFailure => unreachable, // contents and stat are both provided else => |e| return e, }; } - - return new_file; } pub fn scanNamespace( @@ -3242,9 +3244,9 @@ const ScanDeclIter = struct { // Perhaps we should add all test indiscriminately and filter at the end of the update. if (!comp.config.is_test) break :a false; if (file.mod != zcu.main_mod) break :a false; - if (is_named and comp.test_filters.len > 0) { + if (is_named and zcu.test_filters.len > 0) { const fqn_slice = fqn.toSlice(ip); - for (comp.test_filters) |test_filter| { + for (zcu.test_filters) |test_filter| { if (std.mem.find(u8, fqn_slice, test_filter) != null) break; } else break :a false; } diff --git a/src/main.zig b/src/main.zig index 541504cdb218af539235a5e1f6abca83d30b7234..77a53032b45b49d1ee726244866ca2f2f117a27a 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4413,13 +4413,12 @@ fn serve( switch (hdr.tag) { .exit => return cleanExit(io), .update => { - file_system_inputs.clearRetainingCapacity(); - if (arg_mode == .translate_c) { var arena_instance = std.heap.ArenaAllocator.init(gpa); defer arena_instance.deinit(); const arena = arena_instance.allocator(); var output: Compilation.TranslateCResult = undefined; + file_system_inputs.clearRetainingCapacity(); try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); defer output.deinit(gpa); @@ -4437,7 +4436,6 @@ fn serve( continue; } - try comp.makeBinFileWritable(); try comp.update(main_progress_node); try comp.makeBinFileExecutable(); @@ -4463,7 +4461,6 @@ fn serve( //); }, .hot_update => { - file_system_inputs.clearRetainingCapacity(); if (child_pid) |pid| { try comp.hotCodeSwap(main_progress_node, pid); try serveUpdateResults(&server, comp); diff --git a/test/src/Cases.zig b/test/src/Cases.zig index c6b3eb07d1ed6efdfd626952bac4ce484ca4efef..c6036823d92ffd09d752de600a25a354229a0de8 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -75,7 +75,6 @@ pub const Case = struct { emit_asm: bool = false, emit_bin: bool = true, - emit_h: bool = false, is_test: bool = false, expect_exact: bool = false, backend: Backend = .auto, -- 2.54.0 From 809fcd4910552b57e0a61567fd5706719315bb22 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Wed, 14 Oct 2026 11:11:03 -0400 Subject: [PATCH 6/9] test/Runner: support more syntax for command contents --- build.zig | 18 +- lib/compiler/Maker/Package/Manifest.zig | 92 +--- lib/std/zig/string_literal.zig | 18 +- test/{src => }/Runner.zig | 419 +++++++++++------- test/debugger/basic/manifest | 4 +- test/debugger/enums | 4 +- test/debugger/errors | 4 +- test/debugger/inline_call/manifest | 14 +- test/debugger/matrix.zon | 68 +++ test/debugger/multi_array_list/manifest | 4 +- test/debugger/step_single_stmt_loops/manifest | 4 +- test/debugger/unions | 4 +- test/incremental/add_decl | 15 +- test/incremental/add_decl_namespaced | 15 +- .../add_decls_around_bad_field_expr | 3 +- ..._field_and_nested_struct_uses_changed_decl | 9 +- .../add_remove_struct_fields/manifest | 17 +- .../add_remove_toplevel_fields/manifest | 17 +- .../analysis_error_and_syntax_error | 18 +- test/incremental/bad_import | 6 +- test/incremental/change_bitpack_backing_int | 9 +- test/incremental/change_container_kind | 24 +- test/incremental/change_embed_file | 15 +- .../incremental/change_enum_tag_type/manifest | 22 +- test/incremental/change_exports/manifest | 35 +- test/incremental/change_fn_type | 6 +- test/incremental/change_generic_line_number | 3 +- test/incremental/change_line_number | 3 +- test/incremental/change_module | 12 +- test/incremental/change_panic_handler | 6 +- .../change_panic_handler_explicit/manifest | 12 +- .../change_reify_struct_field_type | 9 +- test/incremental/change_shift_op | 3 +- test/incremental/change_struct_same_fields | 6 +- test/incremental/change_union_tag_type | 6 +- test/incremental/change_zon_file | 15 +- .../change_zon_file_no_result_type | 3 +- test/incremental/compile_error_then_log | 6 +- test/incremental/compile_log | 9 +- test/incremental/delete_comptime_decls | 3 +- .../dependency_on_type_of_inferred_global | 6 +- test/incremental/do_nothing | 13 +- test/incremental/fix_astgen_failure | 12 +- test/incremental/function_becomes_inline | 9 +- test/incremental/hello | 3 +- test/incremental/increase_array_field_length | 3 +- test/incremental/make_decl_pub | 3 +- test/incremental/matrix.zon | 61 +++ test/incremental/modify_inline_fn | 3 +- test/incremental/move_src | 3 +- .../pointer_to_decl_with_astgen_error | 12 +- .../recursive_function_becomes_non_recursive | 3 +- test/incremental/remove_enum_field | 3 +- .../remove_function_with_changed_callee | 9 +- .../remove_invalid_union_backing_enum | 6 +- .../struct_reification_becomes_anon_init | 3 +- test/incremental/tag_name | 15 +- ...porary_analysis_error_in_generic_signature | 6 +- test/incremental/temporary_parse_error | 12 +- test/incremental/type_becomes_comptime_only | 15 +- test/incremental/type_dependency_loop | 21 +- test/incremental/unreferenced_error | 9 +- test/tests.zig | 148 +------ 63 files changed, 607 insertions(+), 731 deletions(-) rename test/{src => }/Runner.zig (87%) create mode 100644 test/debugger/matrix.zon create mode 100644 test/incremental/matrix.zon diff --git a/build.zig b/build.zig index bcd0f50975e906c61a9e2649e933ac8350da5d43..f2b6c5c9b6d2a3a560b31c5605367bd776ec3f60 100644 --- a/build.zig +++ b/build.zig @@ -793,7 +793,7 @@ pub fn build(b: *std.Build) !void { const runner = b.addExecutable(.{ .name = "runner", .root_module = b.createModule(.{ - .root_source_file = b.path("test/src/Runner.zig"), + .root_source_file = b.path("test/Runner.zig"), .target = b.graph.host, }), }); @@ -813,17 +813,15 @@ pub fn build(b: *std.Build) !void { .lldb = b.option([]const u8, "lldb", "path to lldb binary"), }; - const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests"); - try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", tests.incremental_matrix, runner_opts); - test_step.dependOn(test_incremental_step); - const test_debugger_step = b.step("test-debugger", "Run the debugger tests"); - if (runner_opts.gdb == null and runner_opts.lldb == null) { - test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step); - } else { - try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", tests.debugger_matrix, runner_opts); + if (runner_opts.gdb != null or runner_opts.lldb != null) { + try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", @import("test/debugger/matrix.zon"), runner_opts); test_step.dependOn(test_debugger_step); - } + } else test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step); + + const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests"); + try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts); + test_step.dependOn(test_incremental_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/lib/compiler/Maker/Package/Manifest.zig b/lib/compiler/Maker/Package/Manifest.zig index 7dd507a20c8ce9836b04ba2d8e4822e569ef5e91..dd7fbd86f8c6d1ae3f4e003921a42fdf6e2a67dc 100644 --- a/lib/compiler/Maker/Package/Manifest.zig +++ b/lib/compiler/Maker/Package/Manifest.zig @@ -494,95 +494,9 @@ const Parse = struct { }; switch (result) { .success => {}, - .failure => |err| try p.appendStrLitError(err, token, bytes, offset), - } - } - - /// TODO: try to DRY this with AstGen.failWithStrLitError - fn appendStrLitError( - p: *Parse, - err: std.zig.string_literal.Error, - token: Ast.TokenIndex, - bytes: []const u8, - offset: u32, - ) Allocator.Error!void { - const raw_string = bytes[offset..]; - switch (err) { - .invalid_escape_character => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "invalid escape character: '{c}'", - .{raw_string[bad_index]}, - ); - }, - .expected_hex_digit => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "expected hex digit, found '{c}'", - .{raw_string[bad_index]}, - ); - }, - .empty_unicode_escape_sequence => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "empty unicode escape sequence", - .{}, - ); - }, - .expected_hex_digit_or_rbrace => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "expected hex digit or '}}', found '{c}'", - .{raw_string[bad_index]}, - ); - }, - .invalid_unicode_codepoint => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "unicode escape does not correspond to a unicode code point", - .{}, - ); - }, - .expected_lbrace => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "expected '{{', found '{c}", - .{raw_string[bad_index]}, - ); - }, - .expected_rbrace => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "expected '}}', found '{c}", - .{raw_string[bad_index]}, - ); - }, - .expected_single_quote => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "expected single quote ('), found '{c}", - .{raw_string[bad_index]}, - ); - }, - .invalid_character => |bad_index| { - try p.appendErrorOff( - token, - offset + @as(u32, @intCast(bad_index)), - "invalid byte in string or character literal: '{c}'", - .{raw_string[bad_index]}, - ); - }, - .empty_char_literal => { - try p.appendErrorOff(token, offset, "empty character literal", .{}); - }, + .failure => |err| try p.appendErrorOff(token, @intCast(offset + err.offset()), "{f}", .{ + err.fmt(bytes[offset..]), + }), } } diff --git a/lib/std/zig/string_literal.zig b/lib/std/zig/string_literal.zig index c51c2ab77c62faf84057d25f2739e37ece9fd0d6..95a293c2b86d68f3de2ee292b4df3d50666f9709 100644 --- a/lib/std/zig/string_literal.zig +++ b/lib/std/zig/string_literal.zig @@ -38,6 +38,11 @@ pub const Error = union(enum) { invalid_character: usize, /// `''`. Not returned for string literals. empty_char_literal, + /// The input ended before the end of the literal. + end_of_input: usize, + /// The literal ended before the end of the input. There was an otherwise successful + /// parse of a prefix of the input of length given by this payload written to the writer. + end_of_literal: usize, const FormatMessage = struct { err: Error, @@ -83,6 +88,12 @@ pub const Error = union(enum) { .empty_char_literal => try writer.writeAll( "empty character literal", ), + .end_of_input => try writer.writeAll( + "expected end of string literal", + ), + .end_of_literal => try writer.writeAll( + "unexpected end of string literal", + ), } } @@ -104,6 +115,8 @@ pub const Error = union(enum) { .expected_rbrace, .expected_single_quote, .invalid_character, + .end_of_input, + .end_of_literal, => |n| n, .empty_char_literal => 0, }; @@ -339,13 +352,16 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result { try writer.writeAll(buf[0..len]); } else { try writer.writeByte(@as(u8, @intCast(codepoint))); + if (index == bytes.len) return .{ .failure = .{ .end_of_input = index } }; } }, .failure => |err| return .{ .failure = err }, } }, '\n' => return .{ .failure = .{ .invalid_character = index } }, - '"' => return .success, + '"' => return if (index < bytes.len - 1) .{ + .failure = .{ .end_of_literal = index }, + } else .success, else => { try writer.writeByte(b); index += 1; diff --git a/test/src/Runner.zig b/test/Runner.zig similarity index 87% rename from test/src/Runner.zig rename to test/Runner.zig index 66e204b4c5d1799ccbbd3ad956cfff1d72b635f6..d614036096d5de25984438bc00314d696d1409b0 100644 --- a/test/src/Runner.zig +++ b/test/Runner.zig @@ -64,9 +64,7 @@ fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError { return runner.failString(try runner.eb_wip.printString(fmt, args)); } fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError { - try runner.eb_wip.addRootErrorMessage(.{ - .msg = msg, - }); + try runner.eb_wip.addRootErrorMessage(.{ .msg = msg }); return error.AlreadyReported; } @@ -505,33 +503,34 @@ pub const SourceReader = struct { src_loc: []const u8, msg: std.zig.ErrorBundle.String, ) FailError { + try s.eb_wip.addRootErrorMessage(.{ .msg = msg, .src_loc = try s.srcLoc(src_loc) }); + return error.AlreadyReported; + } + fn srcLoc( + s: *SourceReader, + src_loc: []const u8, + ) std.mem.Allocator.Error!std.zig.ErrorBundle.SourceLocationIndex { const line: u32, const column: u32, const source_line = src_loc: { - const pos = src_loc.ptr - s.interface.buffer.ptr; - const end = std.mem.findScalarPos(u8, s.interface.buffer, pos, '\n') orelse - s.interface.buffer.len; - const start = if (std.mem.findScalarLast(u8, s.interface.buffer[0..end], '\n')) |newline| - newline + 1 - else - 0; + const buffer = s.interface.buffer[0..s.interface.end]; + const pos = src_loc.ptr - buffer.ptr; + const end = std.mem.findScalarPos(u8, buffer, pos, '\n') orelse buffer.len; + const start = + if (std.mem.findScalarLast(u8, buffer[0..end], '\n')) |newline| newline + 1 else 0; break :src_loc .{ - @intCast(s.line + std.mem.countScalar(u8, s.interface.buffer[0..start], '\n')), + @intCast(s.line + std.mem.countScalar(u8, buffer[0..start], '\n')), @intCast(pos - start), - s.interface.buffer[start..end], + buffer[start..end], }; }; - try s.eb_wip.addRootErrorMessage(.{ - .msg = msg, - .src_loc = try s.eb_wip.addSourceLocation(.{ - .src_path = s.src_path, - .line = line, - .column = column, - .span_start = column, - .span_main = column, - .span_end = @intCast(column + src_loc.len), - .source_line = try s.eb_wip.addString(source_line), - }), + return s.eb_wip.addSourceLocation(.{ + .src_path = s.src_path, + .line = line, + .column = column, + .span_start = column, + .span_main = column, + .span_end = @intCast(column + src_loc.len), + .source_line = try s.eb_wip.addString(source_line), }); - return error.AlreadyReported; } }; pub const DelimitedReader = struct { @@ -585,10 +584,66 @@ const Update = struct { manifest_sr: SourceReader, compiler: ?Compiler, src_dir: std.Io.Dir, - prog_node: std.Progress.Node, - mtime: std.Io.Timestamp, + eb_wip: *std.zig.ErrorBundle.Wip, + cmd_src_loc: std.zig.ErrorBundle.SourceLocationIndex, + src_loc: ?std.zig.ErrorBundle.SourceLocationIndex, num: usize, + name: []const u8, + prog_node: std.Progress.Node, + mtime: std.Io.Timestamp, allow_skip: bool, + + fn checkMatches( + update: *const Update, + what: []const u8, + expected: []const u8, + actual: []const u8, + ) FailError!void { + var expected_match_it = std.mem.splitSequence(u8, expected, "#..."); + var pos: usize = 0; + while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) { + var context_len: usize = expected_match.len; + pos = while (true) : (context_len -= 1) break std.mem.findPos( + u8, + actual, + pos, + expected_match[0..context_len], + ) orelse continue; + const actual_match = actual[pos..]; + std.testing.expectEqualStrings( + expected_match, + actual_match[0..@min(actual_match.len, expected_match.len)], + ) catch |err| switch (err) { + error.TestExpectedEqual => { + std.testing.failPrint("\n=============== full output: =========\n", .{}); + std.testing.failPrintWithVisibleNewlines(actual_match); + std.testing.failPrint("\n======================================\n", .{}); + return update.fail("{s} did not match expected", .{what}); + }, + }; + } + } + + fn fail(update: *const Update, comptime fmt: []const u8, args: anytype) FailError { + return update.failString(try update.eb_wip.printString(fmt, args)); + } + fn failString(update: *const Update, msg: std.zig.ErrorBundle.String) FailError { + var notes_buffer: [1]std.zig.ErrorBundle.ErrorMessage = undefined; + var notes_len: u32 = 0; + if (update.src_loc) |src_loc| { + notes_buffer[notes_len] = .{ + .msg = try update.eb_wip.addString("after this update"), + .src_loc = src_loc, + }; + notes_len += 1; + } + try update.eb_wip.addRootErrorMessageWithNotes(.{ + .msg = msg, + .src_loc = update.cmd_src_loc, + .notes_len = 1, + }, notes_buffer[0..notes_len]); + return error.AlreadyReported; + } }; const TestError = error{ @@ -626,9 +681,13 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr error.Canceled => |e| return e, else => |e| return runner.fail("unable to create {q}: {t}", .{ target_query, e }), }, + .eb_wip = &runner.eb_wip, + .cmd_src_loc = undefined, + .src_loc = null, + .num = 0, + .name = undefined, .prog_node = .none, .mtime = .now(runner.io, .real), - .num = 0, .allow_skip = true, }; defer { @@ -654,6 +713,7 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr return update.manifest_sr.fail(unexpected, "unexpected argument {q}", .{unexpected}); continue; } + update.cmd_src_loc = try update.manifest_sr.srcLoc(cmd_src_loc); const cmd = std.meta.stringToEnum(Command, std.mem.cutPrefix(u8, cmd_src_loc, "#") orelse return update.manifest_sr.fail(cmd_src_loc, "expected command", .{})) orelse return update.manifest_sr.fail(cmd_src_loc, "unknown command", .{}); @@ -666,7 +726,7 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr defer if (contents_file) |file| file.close(runner.io); var contents_buffer: [512]u8 = undefined; var contents_impl: union(enum) { - ending: std.Io.Reader, + r: std.Io.Reader, dr: DelimitedReader, fr: std.Io.File.Reader, } = undefined; @@ -678,42 +738,75 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr "unexpected argument {q}", .{unexpected}, ); - contents_impl = .{ .ending = .ending_instance }; - break :contents_r &contents_impl.ending; + contents_impl = .{ .r = .ending_instance }; + break :contents_r &contents_impl.r; }, else => { - const contents_path = line_it.rest(); - if (contents_path.len == 0) { - contents_impl = .{ .ending = .ending_instance }; - break :contents_r &contents_impl.ending; + const contents = line_it.rest(); + if (contents.len == 0) { + contents_impl = .{ .r = .ending_instance }; + break :contents_r &contents_impl.r; } + contents: switch (contents[0]) { + else => return update.manifest_sr.fail(contents, "invalid contents syntax", .{}), + '"' => { + if (contents.len < 2 or contents[contents.len - 1] != '"') continue :contents 0; + var contents_fw: std.Io.Writer = .fixed(&contents_buffer); + switch (std.zig.string_literal.parseWrite( + &contents_fw, + contents, + ) catch |err| switch (err) { + error.WriteFailed => return update.manifest_sr.fail( + contents, + "contents string too long, use inline or file syntax instead", + .{}, + ), + }) { + .success => { + contents_impl = .{ .r = .fixed(contents_fw.buffered()) }; + break :contents_r &contents_impl.r; + }, + .failure => |err| return update.manifest_sr.fail( + contents[err.offset()..][0..0], + "{f}", + .{err.fmt(contents)}, + ), + } + }, + '{' => { + if (contents.len != 1) continue :contents 0; - if (std.mem.eql(u8, contents_path, "{")) { - contents_impl = .{ - .dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer), - }; - skip_delimiter = true; - break :contents_r &contents_impl.dr.interface; - } - - const args_test = runner.args.@"test" orelse return update.manifest_sr.fail( - contents_path, - "contents file requires directory test", - .{}, - ); - try runner.discoverInput(args_test.input_dir, contents_path); + contents_impl = .{ + .dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer), + }; + skip_delimiter = true; + break :contents_r &contents_impl.dr.interface; + }, + '@' => { + const args_test = runner.args.@"test" orelse return update.manifest_sr.fail( + contents, + "contents file requires directory test", + .{}, + ); + const contents_path = contents[1..]; + try runner.discoverInput(args_test.input_dir, contents_path); - contents_file = - args_test.dir.openFile(runner.io, contents_path, .{}) catch |err| switch (err) { - error.Canceled => |e| return e, - else => |e| return update.manifest_sr.fail( + contents_file = args_test.dir.openFile( + runner.io, contents_path, - "unable to open contents file: {t}", - .{e}, - ), - }; - contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) }; - break :contents_r &contents_impl.fr.interface; + .{}, + ) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return update.manifest_sr.fail( + contents_path, + "unable to open contents file: {t}", + .{e}, + ), + }; + contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) }; + break :contents_r &contents_impl.fr.interface; + }, + } }, }; @@ -724,28 +817,41 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr error.SkipTest, => |e| return e, error.ContentsReadFailed => switch (contents_impl) { - .ending => unreachable, + .r => unreachable, .dr => switch (manifest_fr.err orelse return error.OutOfMemory) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to read manifest: {t}", .{e}), + else => |e| return update.fail("unable to read manifest: {t}", .{e}), }, .fr => |fr| switch (fr.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to read contents file: {t}", .{e}), + else => |e| return update.fail("unable to read contents file: {t}", .{e}), }, }, }; } else |err| switch (err) { error.ReadFailed => switch (manifest_fr.err orelse return error.OutOfMemory) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to read manifest: {t}", .{e}), + else => |e| return update.fail("unable to read manifest: {t}", .{e}), }, error.StreamTooLong => unreachable, - error.EndOfStream => if (skip_delimiter) - return runner.fail("manifest missing \"#}}\" delimiter", .{}), + error.EndOfStream => { + const final_line = update.manifest_sr.interface.buffered(); + switch (final_line.len) { + 0 => if (skip_delimiter) return update.manifest_sr.fail( + final_line[0..0], + "missing \"#}}\" delimiter", + .{}, + ), + else => return update.manifest_sr.fail( + final_line[final_line.len..], + "missing trailing newline", + .{}, + ), + } + }, } if (update.compiler) |*comp| { - if (comp.state != .idle) return runner.fail("missing \"#check\"", .{}); + if (comp.state != .idle) return update.fail("missing \"#check\"", .{}); try comp.exit(); } } @@ -781,21 +887,27 @@ fn handleCommand( }, contents_r, target: { var component_it = std.mem.splitBackwardsScalar(u8, update.target_query, '-'); const pic_str = component_it.next() orelse - return runner.fail("target {q} missing pic", .{update.target_query}); + return update.fail("target {q} missing pic", .{update.target_query}); const pic = std.meta.stringToEnum(Compiler.Target.Pic, pic_str) orelse - return runner.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str }); + return update.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str }); const linker_str = component_it.next() orelse - return runner.fail("target {q} missing linker", .{update.target_query}); + return update.fail("target {q} missing linker", .{update.target_query}); const linker = std.meta.stringToEnum(Compiler.Target.Linker, linker_str) orelse - return runner.fail("target {q} unknown linker {q}", .{ update.target_query, linker_str }); + return update.fail("target {q} unknown linker {q}", .{ + update.target_query, linker_str, + }); const backend_str = component_it.next() orelse - return runner.fail("target {q} missing backend", .{update.target_query}); + return update.fail("target {q} missing backend", .{update.target_query}); const backend = std.meta.stringToEnum(Compiler.Target.Backend, backend_str) orelse - return runner.fail("target {q} unknown backend {q}", .{ update.target_query, backend_str }); + return update.fail("target {q} unknown backend {q}", .{ + update.target_query, backend_str, + }); const cache_mode_str = component_it.next() orelse - return runner.fail("target {q} missing cache mode", .{update.target_query}); + return update.fail("target {q} missing cache mode", .{update.target_query}); const cache_mode = std.meta.stringToEnum(Compiler.Target.CacheMode, cache_mode_str) orelse - return runner.fail("target {q} unknown cache mode {q}", .{ update.target_query, cache_mode_str }); + return update.fail("target {q} unknown cache mode {q}", .{ + update.target_query, cache_mode_str, + }); const triple = component_it.rest(); break :target .{ .triple = triple, @@ -808,13 +920,13 @@ fn handleCommand( .cbe => "c", }, }) catch |err| switch (err) { - error.ParseFailed => return runner.fail("unable to parse triple {q}", .{ + error.ParseFailed => return update.fail("unable to parse triple {q}", .{ triple, }), }, ) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to resolve target {q}: {t}", .{ triple, e }), + else => |e| return update.fail("unable to resolve target {q}: {t}", .{ triple, e }), }, .cache_mode = cache_mode, .backend = backend, @@ -868,25 +980,24 @@ fn handleCommand( else => |e| return update.manifest_sr.fail(arg.?, "unable to delete file: {t}", .{e}), }, .update => { + update.src_loc = update.cmd_src_loc; const comp = &(update.compiler orelse return update.manifest_sr.fail( cmd_src_loc, "missing \"#exe\", \"#lib\", or \"#obj\"", .{}, )); update.prog_node.end(); - update.prog_node = runner.prog_node.start( - switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) { - error.ReadFailed => return error.ContentsReadFailed, - }) { - 0 => switch (update.num) { - 0 => "initial update", - else => |num| std.mem.print(&name_buffer, "update {d}", .{num}) catch - &name_buffer, - }, - else => |name_len| name_buffer[0..name_len], + const arena = runner.arena.allocator(); + update.name = switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) { + error.ReadFailed => return error.ContentsReadFailed, + }) { + 0 => switch (update.num) { + 0 => "initial update", + else => |num| try arena.print("update {d}", .{num}), }, - 0, - ); + else => |name_len| try arena.dupe(u8, name_buffer[0..name_len]), + }; + update.prog_node = runner.prog_node.start(update.name, 0); _ = contents_r.discardRemaining() catch |err| switch (err) { error.ReadFailed => return error.ContentsReadFailed, }; @@ -895,7 +1006,7 @@ fn handleCommand( comp.client.serveBodylessMessage(.update) catch |err| switch (err) { error.WriteFailed => switch (comp.fw.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to send message to compiler: {t}", .{e}), + else => |e| return update.fail("unable to send message to compiler: {t}", .{e}), }, }; comp.state = .update; @@ -934,7 +1045,7 @@ fn handleCommand( unreachable; const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch unreachable; - try comp.checkSuccess(check, expected, update.src_dir, digest); + try comp.checkSuccess(update, check, expected, digest); }, .error_bundle => { const eb = std.zig.Server.allocErrorBundle( @@ -942,7 +1053,7 @@ fn handleCommand( message.body, ) catch |err| switch (err) { error.OutOfMemory => |e| return e, - error.EndOfStream => return runner.fail("error bundle truncated", .{}), + error.EndOfStream => return update.fail("error bundle truncated", .{}), }; switch (check) { .errors => { @@ -958,7 +1069,7 @@ fn handleCommand( const actual = error_aw.written(); std.mem.replaceScalar(u8, actual, '\\', '/'); std.testing.expectEqualStrings(expected, actual) catch |err| switch (err) { - error.TestExpectedEqual => return runner.fail( + error.TestExpectedEqual => return update.fail( "errors did not match expected", .{}, ), @@ -969,7 +1080,7 @@ fn handleCommand( error.Canceled => {}, else => {}, }; - return runner.fail("unexpected compile errors", .{}); + return update.fail("unexpected compile errors", .{}); }, } comp.state = .idle; @@ -977,17 +1088,15 @@ fn handleCommand( }, }; - const buffered_stderr = stderr.buffered(); - if (buffered_stderr.len > 0) { + const stderr_buffered = stderr.buffered(); + if (stderr_buffered.len > 0) { if (comp.allow_compiler_stderr) { - std.log.info("stderr:\n{s}", .{buffered_stderr}); - } else { - return runner.fail("unexpected stderr:\n{s}", .{buffered_stderr}); - } + std.log.info("#update {q} stderr:\n{s}", .{ update.name, stderr_buffered }); + } else return update.fail("unexpected stderr:\n{s}", .{stderr_buffered}); } try comp.exit(); - return runner.fail("compiler failed to send terminating error_bundle", .{}); + return update.fail("compiler failed to send terminating error_bundle", .{}); }, } assert(contents_r.discardRemaining() catch |err| switch (err) { @@ -1219,9 +1328,9 @@ const Compiler = struct { const Check = enum { errors, stdout, exit, gdb, lldb }; fn checkSuccess( comp: *Compiler, + update: *const Update, check: Check, expected: []const u8, - src_dir: std.Io.Dir, digest: *const std.Build.Cache.BinDigest, ) TestError!void { const runner = comp.runner; @@ -1238,9 +1347,9 @@ const Compiler = struct { const debug_success = 99; const tmp_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "tmp"; - src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) { + update.src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to create dir path {q}: {t}", .{ + else => |e| return update.fail("unable to create dir path {q}: {t}", .{ tmp_dir_path, e, }), }; @@ -1256,12 +1365,13 @@ const Compiler = struct { .gdb => { const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb"; argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" }); - const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) { - error.Canceled => |e| return e, - else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{ - script_path, e, - }), - }; + const script_file = + update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return update.fail("unable to create debugger script {q}: {t}", .{ + script_path, e, + }), + }; errdefer script_file.close(io); var script_fw = script_file.writer(io, &script_buffer); script_fw.interface.writeAll( @@ -1271,7 +1381,9 @@ const Compiler = struct { ) catch |err| switch (err) { error.WriteFailed => switch (script_fw.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }), + else => |e| return update.fail("unable to write debugger script {q}: {t}", .{ + script_path, e, + }), }, }; break :script .{ script_path, script_file, script_fw }; @@ -1280,13 +1392,13 @@ const Compiler = struct { const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "lldb"; argv.appendSliceAssumeCapacity(&.{ "lldb", "--batch", "--source", script_path, "--" }); try environ_map.put("LANG", "C.UTF-8"); // affects output formatting - const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) { - error.Canceled => |e| return e, - else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{ - script_path, - e, - }), - }; + const script_file = + update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return update.fail("unable to create debugger script {q}: {t}", .{ + script_path, e, + }), + }; errdefer script_file.close(io); var script_fw = script_file.writer(io, &script_buffer); script_fw.interface.writeAll( @@ -1298,7 +1410,9 @@ const Compiler = struct { ) catch |err| switch (err) { error.WriteFailed => switch (script_fw.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }), + else => |e| return update.fail("unable to write debugger script {q}: {t}", .{ + script_path, e, + }), }, }; break :script .{ script_path, script_file, script_fw }; @@ -1312,7 +1426,7 @@ const Compiler = struct { const bin_path = switch (comp.target.backend.?) { .sema => return, .selfhosted, .llvm => out_path, - .cbe => try comp.compileC(src_dir, out_path), + .cbe => try comp.compileC(update.src_dir, out_path), }; const need_cross_libc = @@ -1347,7 +1461,7 @@ const Compiler = struct { &path_buffer, ) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to get libc runtimes path: {t}", .{e}), + else => |e| return update.fail("unable to get libc runtimes path: {t}", .{e}), }]; argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{ libc_runtimes_path, @@ -1386,7 +1500,10 @@ const Compiler = struct { if (!runner.args.quiet) std.log.info("{f}", .{std.zig.SubprocessCommand{ .argv = argv.items, .cwd = cwd_path: { - break :cwd_path path_buffer[0 .. src_dir.realPath(io, &path_buffer) catch |err| switch (err) { + break :cwd_path path_buffer[0 .. update.src_dir.realPath( + io, + &path_buffer, + ) catch |err| switch (err) { error.Canceled => |e| return e, else => break :cwd_path null, }]; @@ -1401,9 +1518,9 @@ const Compiler = struct { }) catch &name_buffer, 0); defer run_prog_node.end(); - const bin_file = src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) { + const bin_file = update.src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to open {q}: {t}", .{ bin_path, e }), + else => |e| return update.fail("unable to open {q}: {t}", .{ bin_path, e }), }; defer bin_file.close(io); const result = std.process.run(gpa, io, .{ @@ -1430,7 +1547,7 @@ const Compiler = struct { , .{cmd}) catch |err| switch (err) { error.WriteFailed => switch (script_fw.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ + else => |e| return update.fail("unable to write debugger script {q}: {t}", .{ script_path, e, }), }, @@ -1442,14 +1559,14 @@ const Compiler = struct { , .{debug_success}) catch |err| switch (err) { error.WriteFailed => switch (script_fw.err.?) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ + else => |e| return update.fail("unable to write debugger script {q}: {t}", .{ script_path, e, }), }, }; script_fw.flush() catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ + else => |e| return update.fail("unable to write debugger script {q}: {t}", .{ script_path, e, }), }; @@ -1467,7 +1584,7 @@ const Compiler = struct { }, }, .argv = argv.items, - .cwd = .{ .dir = src_dir }, + .cwd = .{ .dir = update.src_dir }, .environ_map = &environ_map, .progress_node = run_prog_node, }) catch |err| if (use_executor) { @@ -1477,7 +1594,7 @@ const Compiler = struct { .{ bin_path, comp.target.triple, err }, ); return; - } else return runner.fail("unable to run the generated executable {q}: {t}", .{ + } else return update.fail("unable to run the generated executable {q}: {t}", .{ bin_path, err, }); defer { @@ -1488,7 +1605,7 @@ const Compiler = struct { .exited => |code| switch (check) { .errors => unreachable, .stdout => { - if (code != 0) return runner.fail( + if (code != 0) return update.fail( "generated executable {q} failed with code {d}", .{ bin_path, code }, ); @@ -1496,67 +1613,49 @@ const Compiler = struct { expected, result.stdout, ) catch |err| switch (err) { - error.TestExpectedEqual => return runner.fail("stdout did not match expected", .{}), + error.TestExpectedEqual => return update.fail( + "stdout did not match expected", + .{}, + ), }; }, .exit => { - var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 = undefined; + var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 = + undefined; std.testing.expectEqualStrings( expected, std.mem.print(&actual_code_buffer, "{d}", .{code}) catch unreachable, ) catch |err| switch (err) { - error.TestExpectedEqual => return runner.fail( + error.TestExpectedEqual => return update.fail( "exit code did not match expected", .{}, ), }; }, .gdb, .lldb => { - if (code != debug_success) return runner.fail( + if (code != debug_success) return update.fail( "debugging {q} failed with code {d}", .{ bin_path, code }, ); - var expected_match_it = std.mem.splitSequence(u8, expected, "#..."); - var pos: usize = 0; - while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) { - var context_len: usize = expected_match.len; - pos = while (true) : (context_len -= 1) break std.mem.findPos( - u8, - result.stdout, - pos, - expected_match[0..context_len], - ) orelse continue; - const actual_match = result.stdout[pos..]; - std.testing.expectEqualStrings( - expected_match, - actual_match[0..@min(actual_match.len, expected_match.len)], - ) catch |err| switch (err) { - error.TestExpectedEqual => { - std.testing.failPrint("\n=============== full output: =========\n", .{}); - std.testing.failPrintWithVisibleNewlines(actual_match); - std.testing.failPrint("\n======================================\n", .{}); - return runner.fail("stdout did not match expected", .{}); - }, - }; - } + try update.checkMatches("stdout", expected, result.stdout); }, }, - .signal => |sig| return runner.fail( + .signal => |sig| return update.fail( "generated executable {q} terminated with signal {t}", .{ bin_path, sig }, ), - .stopped => |sig| return runner.fail( + .stopped => |sig| return update.fail( "generated executable {q} stopped with signal {t}", .{ bin_path, sig }, ), - .unknown => return runner.fail( + .unknown => return update.fail( "generated executable {q} terminated unexpectedly", .{bin_path}, ), } if (!use_executor and result.stderr.len > 0) { - std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{ - bin_path, result.stderr, + std.log.err("#update {q} generated executable {q} had unexpected stderr:\n{s}", .{ + update.name, bin_path, result.stderr, }); } } diff --git a/test/debugger/basic/manifest b/test/debugger/basic/manifest index bddaec73e0f6d7e5ab469b041e0b5f229937fefb..79beee569dc10bb57f7fd99675f8b33c29055a48 100644 --- a/test/debugger/basic/manifest +++ b/test/debugger/basic/manifest @@ -3,6 +3,6 @@ -Mroot=basic.zig #} -#write basic.zig basic.zig +#write basic.zig @basic.zig #update -#check lldb lldb +#check lldb @lldb diff --git a/test/debugger/enums b/test/debugger/enums index d6cbcf24334ee9ea2122cb88143139c22f59d701..dfd6375be0cdad75c30e4c0f41ba1ad9ce87adcb 100644 --- a/test/debugger/enums +++ b/test/debugger/enums @@ -1,6 +1,4 @@ -#todo { -passes, but prints errors -#} +#todo "passes, but prints errors" #skip x86_64-linux-none-whole-selfhosted-new-nopic #skip x86_64-linux-none-whole-selfhosted-new-pic #skip x86_64-linux-none-incremental-selfhosted-new-nopic diff --git a/test/debugger/errors b/test/debugger/errors index 156118c3addabd6b5ce13fe8bbdcb3a3dd580c92..8a8143330ac40d161c7c2f229a6deeb263c6bc66 100644 --- a/test/debugger/errors +++ b/test/debugger/errors @@ -1,6 +1,4 @@ -#todo { -passes, but prints errors -#} +#todo "passes, but prints errors" #skip x86_64-linux-none-whole-selfhosted-new-nopic #skip x86_64-linux-none-whole-selfhosted-new-pic #skip x86_64-linux-none-incremental-selfhosted-new-nopic diff --git a/test/debugger/inline_call/manifest b/test/debugger/inline_call/manifest index 77b906f21de307fc4e2219ec965df5f08d3b5a19..f23cf902c8e1da1a5b670744003ae295b4283a01 100644 --- a/test/debugger/inline_call/manifest +++ b/test/debugger/inline_call/manifest @@ -1,6 +1,4 @@ -#todo { -implement inline line info in lldb -#} +#todo "implement inline line info in lldb" #skip x86_64-linux-none-incremental-selfhosted-new-nopic #skip x86_64-linux-none-incremental-selfhosted-new-pic @@ -10,9 +8,9 @@ implement inline line info in lldb -Mmodule=mod0.zig #} -#write root0.zig root0.zig -#write root1.zig root1.zig -#write mod0.zig mod0.zig -#write mod1.zig mod1.zig +#write root0.zig @root0.zig +#write root1.zig @root1.zig +#write mod0.zig @mod0.zig +#write mod1.zig @mod1.zig #update -#check lldb lldb +#check lldb @lldb diff --git a/test/debugger/matrix.zon b/test/debugger/matrix.zon new file mode 100644 index 0000000000000000000000000000000000000000..a3b36d803468d510b7a6af7c64c90efb3e37060b --- /dev/null +++ b/test/debugger/matrix.zon @@ -0,0 +1,68 @@ +.{ + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .whole, + .backend = .selfhosted, + .linker = .old, + .pic = .nopic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .whole, + .backend = .selfhosted, + .linker = .old, + .pic = .pic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .whole, + .backend = .selfhosted, + .linker = .new, + .pic = .nopic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .whole, + .backend = .selfhosted, + .linker = .new, + .pic = .pic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .selfhosted, + .linker = .new, + .pic = .nopic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .selfhosted, + .linker = .new, + .pic = .pic, + }, +} diff --git a/test/debugger/multi_array_list/manifest b/test/debugger/multi_array_list/manifest index 2503522bee1531df3cd11ce44cfec94b2510def5..233cff5ffd14881cd2c1104ced977e0e8c05beb8 100644 --- a/test/debugger/multi_array_list/manifest +++ b/test/debugger/multi_array_list/manifest @@ -3,6 +3,6 @@ -Mroot=main.zig #} -#write main.zig main.zig +#write main.zig @main.zig #update -#check lldb lldb +#check lldb @lldb diff --git a/test/debugger/step_single_stmt_loops/manifest b/test/debugger/step_single_stmt_loops/manifest index d7284fe12466167a022443945763760b7655e352..abbda7d27e5fd6b8d34ac9da6922d5476a3bc4a7 100644 --- a/test/debugger/step_single_stmt_loops/manifest +++ b/test/debugger/step_single_stmt_loops/manifest @@ -3,6 +3,6 @@ -Mroot=step_single_stmt_loops.zig #} -#write step_single_stmt_loops.zig step_single_stmt_loops.zig +#write step_single_stmt_loops.zig @step_single_stmt_loops.zig #update -#check lldb lldb +#check lldb @lldb diff --git a/test/debugger/unions b/test/debugger/unions index 435b8ec7cf02c239392c7867d0489d8b7eb26e66..786ba275cbf92d418ac4db98301ed24c3214217b 100644 --- a/test/debugger/unions +++ b/test/debugger/unions @@ -1,6 +1,4 @@ -#todo { -passes, but prints errors -#} +#todo "passes, but prints errors" #skip x86_64-linux-none-whole-selfhosted-new-nopic #skip x86_64-linux-none-whole-selfhosted-new-pic #skip x86_64-linux-none-incremental-selfhosted-new-nopic diff --git a/test/incremental/add_decl b/test/incremental/add_decl index 5832015217c571a79a2bc5ca0ab45abf91d7a156..27a5e921dfccf9cd098f9aefee14ae7f6850ebfa 100644 --- a/test/incremental/add_decl +++ b/test/incremental/add_decl @@ -24,8 +24,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add new declaration#} +#update "add new declaration" #check stdout { good morning #} @@ -39,8 +38,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -reference new declaration#} +#update "reference new declaration" #check stdout { good evening #} @@ -54,8 +52,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -reference missing declaration#} +#update "reference missing declaration" #check errors { main.zig:3:52: error: use of undeclared identifier 'qux' #} @@ -70,8 +67,7 @@ const bar = "good evening\n"; const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add missing declaration#} +#update "add missing declaration" #check stdout { good night #} @@ -84,8 +80,7 @@ pub fn main() !void { const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove unused declarations#} +#update "remove unused declarations" #check stdout { good night #} diff --git a/test/incremental/add_decl_namespaced b/test/incremental/add_decl_namespaced index 30bf6a81e9abb3449ad1575a20022b7d6f0d279f..30314032b97331b5f6f3f7c362fb90a128f1a8ca 100644 --- a/test/incremental/add_decl_namespaced +++ b/test/incremental/add_decl_namespaced @@ -24,8 +24,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add new declaration#} +#update "add new declaration" #check stdout { good morning #} @@ -39,8 +38,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -reference new declaration#} +#update "reference new declaration" #check stdout { good evening #} @@ -54,8 +52,7 @@ const foo = "good morning\n"; const bar = "good evening\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -reference missing declaration#} +#update "reference missing declaration" #check errors { main.zig:3:59: error: root source file struct 'main' has no member named 'qux' main.zig:1:1: note: struct declared here @@ -71,8 +68,7 @@ const bar = "good evening\n"; const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add missing declaration#} +#update "add missing declaration" #check stdout { good night #} @@ -85,8 +81,7 @@ pub fn main() !void { const qux = "good night\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove unused declarations#} +#update "remove unused declarations" #check stdout { good night #} diff --git a/test/incremental/add_decls_around_bad_field_expr b/test/incremental/add_decls_around_bad_field_expr index b084be50e0df8e4ee192f39c658595baff996a4d..539ba9bf3dd1d4cd7d276184cc3ad499af1bfca3 100644 --- a/test/incremental/add_decls_around_bad_field_expr +++ b/test/incremental/add_decls_around_bad_field_expr @@ -32,8 +32,7 @@ pub fn main() void { _ = @as(@This(), undefined); } #} -#update { -add more decls around error#} +#update "add more decls around error" #check errors { main.zig:4:15: error: root source file struct 'main' has no member named 'does_not_exist' main.zig:1:1: note: struct declared here diff --git a/test/incremental/add_field_and_nested_struct_uses_changed_decl b/test/incremental/add_field_and_nested_struct_uses_changed_decl index 731d34837bc82b9b3ffac774943f53ffad77d468..acabf972c4e3ba0470e2f2be83f262a69a70041b 100644 --- a/test/incremental/add_field_and_nested_struct_uses_changed_decl +++ b/test/incremental/add_field_and_nested_struct_uses_changed_decl @@ -14,8 +14,7 @@ const S = struct { }; #} #update -#check stdout { -#} +#check stdout #write main.zig { pub fn main() void { @@ -29,7 +28,5 @@ const S = struct { bar: u32, }; #} -#update { -add field to outer struct, change decl used by inner struct#} -#check stdout { -#} +#update "add field to outer struct, change decl used by inner struct" +#check stdout diff --git a/test/incremental/add_remove_struct_fields/manifest b/test/incremental/add_remove_struct_fields/manifest index 2099e73cef2d89db7446cfe1c9f3a82057332248..b0b067f9c212b7de14af1b54031ed03a62eecb05 100644 --- a/test/incremental/add_remove_struct_fields/manifest +++ b/test/incremental/add_remove_struct_fields/manifest @@ -2,30 +2,27 @@ -Mroot=main.zig #} -#write main.zig 0/main.zig +#write main.zig @0/main.zig #update #check stdout { 1 100 #} -#write main.zig 1/main.zig -#update { -add a field#} +#write main.zig @1/main.zig +#update "add a field" #check stdout { 2 100 #} -#write main.zig 2/main.zig -#update { -remove all fields#} +#write main.zig @2/main.zig +#update "remove all fields" #check errors { main.zig:15:24: error: no field named 'x' in struct 'main.S' main.zig:1:11: note: struct declared here #} -#write main.zig 3/main.zig -#update { -remove reference to non-existent field#} +#write main.zig @3/main.zig +#update "remove reference to non-existent field" #check stdout { 0 #} diff --git a/test/incremental/add_remove_toplevel_fields/manifest b/test/incremental/add_remove_toplevel_fields/manifest index 569ee7527b51e75d6a214d260b4206b1c5dd2974..c991cd84b336d667312b14ed9c39783a1a97d10b 100644 --- a/test/incremental/add_remove_toplevel_fields/manifest +++ b/test/incremental/add_remove_toplevel_fields/manifest @@ -2,30 +2,27 @@ -Mroot=main.zig #} -#write main.zig 0/main.zig +#write main.zig @0/main.zig #update #check stdout { 1 100 #} -#write main.zig 1/main.zig -#update { -add a field#} +#write main.zig @1/main.zig +#update "add a field" #check stdout { 2 100 #} -#write main.zig 2/main.zig -#update { -remove all fields#} +#write main.zig @2/main.zig +#update "remove all fields" #check errors { main.zig:15:24: error: no field named 'x' in struct 'main' main.zig:1:1: note: struct declared here #} -#write main.zig 3/main.zig -#update { -remove reference to non-existent field#} +#write main.zig @3/main.zig +#update "remove reference to non-existent field" #check stdout { 0 #} diff --git a/test/incremental/analysis_error_and_syntax_error b/test/incremental/analysis_error_and_syntax_error index 5a2246ee8a8cbc2da6512e70830d8927a676d75b..5f2d849420ca99419966333cbf999b33653cfacc 100644 --- a/test/incremental/analysis_error_and_syntax_error +++ b/test/incremental/analysis_error_and_syntax_error @@ -16,8 +16,7 @@ main.zig:2:5: error: uh oh pub fn main() !void { @compileError("uh oh"); #} -#update { -add parse error#} +#update "add parse error" #check errors { main.zig:3:1: error: expected statement, found 'EOF' #} @@ -27,8 +26,7 @@ pub fn main() !void { @compileError("uh oh"); } #} -#update { -fix parse error#} +#update "fix parse error" #check errors { main.zig:2:5: error: uh oh #} @@ -37,8 +35,7 @@ main.zig:2:5: error: uh oh pub fn main() !void { @compileError("uh oh"); #} -#update { -add parse error again#} +#update "add parse error again" #check errors { main.zig:3:1: error: expected statement, found 'EOF' #} @@ -47,8 +44,7 @@ main.zig:3:1: error: expected statement, found 'EOF' pub fn main() !void { //@compileError("uh oh"); #} -#update { -comment @compileError call#} +#update "comment @compileError call" #check errors { main.zig:3:1: error: expected statement, found 'EOF' #} @@ -58,7 +54,5 @@ pub fn main() !void { //@compileError("uh oh"); } #} -#update { -fix parse error again#} -#check stdout { -#} +#update "fix parse error again" +#check stdout diff --git a/test/incremental/bad_import b/test/incremental/bad_import index d93a9ed6309f963c310a82f0813d0905a564cc10..dcf0bbccd81a23ebab163ae4f6b342a890727504 100644 --- a/test/incremental/bad_import +++ b/test/incremental/bad_import @@ -26,8 +26,7 @@ comptime { _ = @import("this_is/not_real.zig"); } #} -#update { -change bad import#} +#update "change bad import" #check errors { this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound foo.zig:2:17: note: file imported here @@ -41,8 +40,7 @@ pub fn main() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove import of 'foo.zig'#} +#update "remove import of 'foo.zig'" #check stdout { success #} diff --git a/test/incremental/change_bitpack_backing_int b/test/incremental/change_bitpack_backing_int index a5a2b81ce3c3df699043da2fdbd06e7718627ec8..6530ae9c66ae83e3b92085e5e9eca2d5cd3238fd 100644 --- a/test/incremental/change_bitpack_backing_int +++ b/test/incremental/change_bitpack_backing_int @@ -38,8 +38,7 @@ comptime { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -make backing types signed#} +#update "make backing types signed" #check errors { main.zig:5:5: error: found compile log statement main.zig:8:5: note: also here @@ -62,8 +61,7 @@ comptime { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -make backing types too small#} +#update "make backing types too small" #check errors { main.zig:1:20: error: backing integer bit width does not match total bit width of fields main.zig:1:27: note: backing integer 'i5' has bit width '5' @@ -87,8 +85,7 @@ comptime { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -make backing types too big#} +#update "make backing types too big" #check errors { main.zig:1:20: error: backing integer bit width does not match total bit width of fields main.zig:1:27: note: backing integer 'u10' has bit width '10' diff --git a/test/incremental/change_container_kind b/test/incremental/change_container_kind index b83abc6ed79414180e28bf393af94cb708bb377e..55b0f788db78ed1c470bca7020b4062da7f79a1b 100644 --- a/test/incremental/change_container_kind +++ b/test/incremental/change_container_kind @@ -12,8 +12,7 @@ pub fn main() void { #write foo.zig { pub const T = struct { x: u8 }; #} -#update { -T is struct#} +#update "T is struct" #check errors { main.zig:3:5: error: found compile log statement @@ -25,8 +24,7 @@ Compile Log Output: #write foo.zig { pub const T = union {}; #} -#update { -T is union#} +#update "T is union" #check errors { main.zig:3:5: error: found compile log statement @@ -38,8 +36,7 @@ Compile Log Output: #write foo.zig { pub const T = enum {}; #} -#update { -T is enum#} +#update "T is enum" #check errors { main.zig:3:5: error: found compile log statement @@ -51,8 +48,7 @@ Compile Log Output: #write foo.zig { pub const T = opaque {}; #} -#update { -T is opaque#} +#update "T is opaque" #check errors { main.zig:3:5: error: found compile log statement @@ -64,8 +60,7 @@ Compile Log Output: #write foo.zig { pub const T = packed struct {}; #} -#update { -T is packed struct#} +#update "T is packed struct" #check errors { main.zig:3:5: error: found compile log statement @@ -77,8 +72,7 @@ Compile Log Output: #write foo.zig { pub const T = packed union { x: void }; // packed unions need at least 1 field #} -#update { -T is packed union#} +#update "T is packed union" #check errors { main.zig:3:5: error: found compile log statement @@ -90,8 +84,7 @@ Compile Log Output: #write foo.zig { pub const T = extern struct {}; #} -#update { -T is extern struct#} +#update "T is extern struct" #check errors { main.zig:3:5: error: found compile log statement @@ -103,8 +96,7 @@ Compile Log Output: #write foo.zig { pub const T = extern union { x: void }; // extern unions need at least 1 field #} -#update { -T is extern union#} +#update "T is extern union" #check errors { main.zig:3:5: error: found compile log statement diff --git a/test/incremental/change_embed_file b/test/incremental/change_embed_file index d50101dc476973ab1974d4ae82fca3cebffed359..8ef936e7e6b96d8d967850c11e3748050628ccd4 100644 --- a/test/incremental/change_embed_file +++ b/test/incremental/change_embed_file @@ -21,15 +21,13 @@ Hello, World! #write string.txt { Hello again, World! #} -#update { -change file contents#} +#update "change file contents" #check stdout { Hello again, World! #} #delete string.txt -#update { -delete file#} +#update "delete file" #check errors { main.zig:2:27: error: failed opening "string.txt": FileNotFound #} @@ -42,8 +40,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove reference to file#} +#update "remove reference to file" #check stdout { a hardcoded string #} @@ -56,8 +53,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -re-introduce reference to file#} +#update "re-introduce reference to file" #check errors { main.zig:2:27: error: failed opening "string.txt": FileNotFound #} @@ -65,8 +61,7 @@ main.zig:2:27: error: failed opening "string.txt": FileNotFound #write string.txt { We're back, World! #} -#update { -recreate file#} +#update "recreate file" #check stdout { We're back, World! #} diff --git a/test/incremental/change_enum_tag_type/manifest b/test/incremental/change_enum_tag_type/manifest index 682c83a67ed4a3d9ced7ba413b3c8e2ddfab4559..e26e630b28561e1339b22813e0ea99e760c79d91 100644 --- a/test/incremental/change_enum_tag_type/manifest +++ b/test/incremental/change_enum_tag_type/manifest @@ -2,29 +2,26 @@ -Mroot=main.zig #} -#write main.zig 0/main.zig +#write main.zig @0/main.zig #update #check stdout { a #} -#write main.zig 1/main.zig -#update { -too many enum fields#} +#write main.zig @1/main.zig +#update "too many enum fields" #check errors { main.zig:7:5: error: enum tag value '4' too large for type 'u2' #} -#write main.zig 2/main.zig -#update { -increase tag size#} +#write main.zig @2/main.zig +#update "increase tag size" #check stdout { a #} -#write main.zig 3/main.zig -#update { -specify tag directly#} +#write main.zig @3/main.zig +#update "specify tag directly" #check errors { main.zig:9:5: error: found compile log statement @@ -32,9 +29,8 @@ Compile Log Output: @as(type, u3) #} -#write main.zig 4/main.zig -#update { -change directly-specified tag type#} +#write main.zig @4/main.zig +#update "change directly-specified tag type" #check errors { main.zig:9:5: error: found compile log statement diff --git a/test/incremental/change_exports/manifest b/test/incremental/change_exports/manifest index 41716cd32cadf13dca51971fbab9703bc1530ade..9d38a16b9d18a1a07c11f23b765a68eae510c7e0 100644 --- a/test/incremental/change_exports/manifest +++ b/test/incremental/change_exports/manifest @@ -2,50 +2,43 @@ -Mroot=main.zig #} -#write main.zig 0/main.zig +#write main.zig @0/main.zig #update #check stdout { 123 #} -#write main.zig 1/main.zig -#update { -add conflict#} +#write main.zig @1/main.zig +#update "add conflict" #check errors { main.zig:6:5: error: exported symbol collision: foo main.zig:1:1: note: other symbol here #} -#write main.zig 2/main.zig -#update { -resolve conflict#} +#write main.zig @2/main.zig +#update "resolve conflict" #check stdout { 123 456 #} -#write main.zig 3/main.zig -#update { -put exports in decl#} +#write main.zig @3/main.zig +#update "put exports in decl" #check stdout { 123 456 #} -#write main.zig 4/main.zig -#update { -remove reference to exporting decl#} -#check stdout { -#} +#write main.zig @4/main.zig +#update "remove reference to exporting decl" +#check stdout -#write main.zig 5/main.zig -#update { -mark consts as export#} +#write main.zig @5/main.zig +#update "mark consts as export" #check stdout { 123 456 #} -#write main.zig 6/main.zig -#update { -reintroduce reference to exporting decl, introducing conflict#} +#write main.zig @6/main.zig +#update "reintroduce reference to exporting decl, introducing conflict" #check errors { main.zig:5:5: error: exported symbol collision: bar main.zig:2:1: note: other symbol here diff --git a/test/incremental/change_fn_type b/test/incremental/change_fn_type index b16811fbc937aa183fd80bfe7b0eb59690e089b7..448050823cba202d0d4cc2b73f855472e7e53674 100644 --- a/test/incremental/change_fn_type +++ b/test/incremental/change_fn_type @@ -29,8 +29,7 @@ fn foo(x: i64) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change function type#} +#update "change function type" #check stdout { 123 #} @@ -46,8 +45,7 @@ fn foo(x: i64) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change function argument#} +#update "change function argument" #check stdout { -42 #} diff --git a/test/incremental/change_generic_line_number b/test/incremental/change_generic_line_number index cda09859f9c849649b5b40c66d9d16e94101cf34..561fc8b59cf326545a17288f8c96e59148d796f0 100644 --- a/test/incremental/change_generic_line_number +++ b/test/incremental/change_generic_line_number @@ -39,8 +39,7 @@ pub fn main() !void { try Printer("bar\n").print(); } #} -#update { -change line number#} +#update "change line number" #check stdout { foo bar diff --git a/test/incremental/change_line_number b/test/incremental/change_line_number index ed8e24b009356b452dd71d17d7ca510e0df285d2..a6ec89fb4f80da9697bf660fc65695abb31a7ad1 100644 --- a/test/incremental/change_line_number +++ b/test/incremental/change_line_number @@ -22,8 +22,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change line number#} +#update "change line number" #check stdout { foo #} diff --git a/test/incremental/change_module b/test/incremental/change_module index 4c24df6e4dd2c3f410d2d0a555e5a05a2d94d592..a1fc17b6777e5113d0f3bfbd169b9fb9b2627f01 100644 --- a/test/incremental/change_module +++ b/test/incremental/change_module @@ -41,8 +41,7 @@ comptime { //_ = @import("other.zig"); } #} -#update { -change module of other.zig#} +#update "change module of other.zig" #check errors { other.zig:2:5: error: found compile log statement @@ -61,8 +60,7 @@ comptime { _ = @import("other.zig"); } #} -#update { -put other.zig in both modules#} +#update "put other.zig in both modules" #check errors { other.zig:1:1: error: file exists in modules 'root' and 'foo' other.zig:1:1: note: files must belong to only one module @@ -81,7 +79,5 @@ comptime { //_ = @import("other.zig"); } #} -#update { -put other.zig in no modules#} -#check stdout { -#} +#update "put other.zig in no modules" +#check stdout diff --git a/test/incremental/change_panic_handler b/test/incremental/change_panic_handler index 3407de9bade926e20542b9342c91e2d223a019da..67abb5aac76dddfe33c6b6206107772227805f9d 100644 --- a/test/incremental/change_panic_handler +++ b/test/incremental/change_panic_handler @@ -39,8 +39,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change the panic handler body#} +#update "change the panic handler body" #check stdout { new panic message: integer overflow #} @@ -61,8 +60,7 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change the panic handler function value#} +#update "change the panic handler function value" #check stdout { third panic message: integer overflow #} diff --git a/test/incremental/change_panic_handler_explicit/manifest b/test/incremental/change_panic_handler_explicit/manifest index 3388f912ec3c0f6f111bf0750283c4c94a2b720f..201b78dc20cda57f266ddf66facd3bd359320d20 100644 --- a/test/incremental/change_panic_handler_explicit/manifest +++ b/test/incremental/change_panic_handler_explicit/manifest @@ -2,22 +2,20 @@ -Mroot=main.zig #} -#write main.zig 0/main.zig +#write main.zig @0/main.zig #update #check stdout { panic message: integer overflow #} -#write main.zig 1/main.zig -#update { -change the panic handler body#} +#write main.zig @1/main.zig +#update "change the panic handler body" #check stdout { new panic message: integer overflow #} -#write main.zig 2/main.zig -#update { -change the panic handler function value#} +#write main.zig @2/main.zig +#update "change the panic handler function value" #check stdout { third panic message: integer overflow #} diff --git a/test/incremental/change_reify_struct_field_type b/test/incremental/change_reify_struct_field_type index 92a41faee42808ef4b2338a1bdac241507e659fe..808fb39b701a603fb39d1c6f93f18585a51e1cf2 100644 --- a/test/incremental/change_reify_struct_field_type +++ b/test/incremental/change_reify_struct_field_type @@ -13,8 +13,7 @@ const Enum = enum { foo, bar }; const std = @import("std"); #} #update -#check stdout { -foo#} +#check stdout "foo" #write main.zig { fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum { @@ -26,7 +25,5 @@ pub fn main(init: std.process.Init) !void { const Enum = enum { foo, bar }; const std = @import("std"); #} -#update { -change field type#} -#check stdout { -bar#} +#update "change field type" +#check stdout "bar" diff --git a/test/incremental/change_shift_op b/test/incremental/change_shift_op index bcd0ff1d2f61b4aeb305a350bc64a8b64b76fbed..85160205dc368156fb1aa9860d7d03f1e6ce2038 100644 --- a/test/incremental/change_shift_op +++ b/test/incremental/change_shift_op @@ -29,8 +29,7 @@ fn foo(x: u16) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change to right shift#} +#update "change to right shift" #check stdout { 0x130 #} diff --git a/test/incremental/change_struct_same_fields b/test/incremental/change_struct_same_fields index 348a443dd555223482c96f6ae0ccd7ed5a48c459..a8a4533ef420b1922dbf12322ee6e62e238ea497 100644 --- a/test/incremental/change_struct_same_fields +++ b/test/incremental/change_struct_same_fields @@ -39,8 +39,7 @@ fn foo(val: *const S) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change struct layout#} +#update "change struct layout" #check stdout { 100 200 #} @@ -61,8 +60,7 @@ fn foo(val: *const S) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change values#} +#update "change values" #check stdout { 1234 5678 #} diff --git a/test/incremental/change_union_tag_type b/test/incremental/change_union_tag_type index dbbbc94c1e9bebbfdd1b98743de8a85763e725a5..8ec3714735fd783b31a3e1e4e70f47e169b7b129 100644 --- a/test/incremental/change_union_tag_type +++ b/test/incremental/change_union_tag_type @@ -29,8 +29,7 @@ pub fn main(init: std.process.Init) !void { } const std = @import("std"); #} -#update { -change tag type#} +#update "change tag type" #check errors { main.zig:3:24: error: no field named 'a' in enum 'main.B' main.zig:2:11: note: enum declared here @@ -47,8 +46,7 @@ pub fn main(init: std.process.Init) !void { } const std = @import("std"); #} -#update { -change field name to match new tag type#} +#update "change field name to match new tag type" #check stdout { b #} diff --git a/test/incremental/change_zon_file b/test/incremental/change_zon_file index 53b7c82c84703475b71d4495a716041858d27cee..5082d01e796df554957f7c280aba8d55d8913e0e 100644 --- a/test/incremental/change_zon_file +++ b/test/incremental/change_zon_file @@ -21,15 +21,13 @@ Hello, World! #write message.zon { "Hello again, World!\n" #} -#update { -change ZON file contents#} +#update "change ZON file contents" #check stdout { Hello again, World! #} #delete message.zon -#update { -delete file#} +#update "delete file" #check errors { message.zon:1:1: error: unable to load "message.zon": FileNotFound main.zig:2:37: note: file imported here @@ -43,8 +41,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove reference to ZON file#} +#update "remove reference to ZON file" #check errors { message.zon:1:1: error: unable to load "message.zon": FileNotFound main.zig:2:37: note: file imported here @@ -53,8 +50,7 @@ main.zig:2:37: note: file imported here #write message.zon { "We're back, World!\n" #} -#update { -recreate ZON file#} +#update "recreate ZON file" #check stdout { a hardcoded string #} @@ -67,8 +63,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -re-introduce reference to ZON file#} +#update "re-introduce reference to ZON file" #check stdout { We're back, World! #} diff --git a/test/incremental/change_zon_file_no_result_type b/test/incremental/change_zon_file_no_result_type index dd63226cbaa21d113d2ff5f7f43484d616a5d956..201c5dfbde118d39f731ae3b3127431bfa25d868 100644 --- a/test/incremental/change_zon_file_no_result_type +++ b/test/incremental/change_zon_file_no_result_type @@ -26,8 +26,7 @@ Hello, World! .b_number = 0, } #} -#update { -change ZON file#} +#update "change ZON file" #check stdout { Hello again, World! #} diff --git a/test/incremental/compile_error_then_log b/test/incremental/compile_error_then_log index 44dd98a1734dc9fdc2c5618fa58d8fdcceea8ce9..867ad231eb1c8ba756007266ccbd374eaa30940c 100644 --- a/test/incremental/compile_error_then_log +++ b/test/incremental/compile_error_then_log @@ -11,8 +11,7 @@ comptime { @compileLog("this is a log"); } #} -#update { -compile error#} +#update "compile error" #check errors { main.zig:3:5: error: this is an error @@ -29,8 +28,7 @@ comptime { @compileLog("this is a log"); } #} -#update { -remove the compile error#} +#update "remove the compile error" #check errors { main.zig:6:5: error: found compile log statement diff --git a/test/incremental/compile_log b/test/incremental/compile_log index d4445f3ca80aaac2262e70b94ec2f8acaf751603..ec2dd9e1065f437e5d3a1f31d9b2744a31b78e7d 100644 --- a/test/incremental/compile_log +++ b/test/incremental/compile_log @@ -9,8 +9,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -no compile log#} +#update "no compile log" #check stdout { Hello, World! #} @@ -23,8 +22,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add compile log#} +#update "add compile log" #check errors { main.zig:4:5: error: found compile log statement @@ -39,8 +37,7 @@ pub fn main() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove compile log#} +#update "remove compile log" #check stdout { Hello, World! #} diff --git a/test/incremental/delete_comptime_decls b/test/incremental/delete_comptime_decls index ffae08f3d8d7a26173aefdb4c398895eb26d420a..ff13f6c8a77146890361297218d155eeedc47b67 100644 --- a/test/incremental/delete_comptime_decls +++ b/test/incremental/delete_comptime_decls @@ -44,8 +44,7 @@ comptime { _ = y; } #} -#update { -delete and modify comptime decls#} +#update "delete and modify comptime decls" #check errors { main.zig:6:16: error: slice of null pointer #} diff --git a/test/incremental/dependency_on_type_of_inferred_global b/test/incremental/dependency_on_type_of_inferred_global index 73d36a7254759c0f98720617aaf3848cc8703070..517424ed02ba2b4ebb3571797f381d68a673a4f8 100644 --- a/test/incremental/dependency_on_type_of_inferred_global +++ b/test/incremental/dependency_on_type_of_inferred_global @@ -15,8 +15,7 @@ comptime { pub fn main() void {} #} #update -#check stdout { -#} +#check stdout #write main.zig { const foo = @as(u16, 123); @@ -30,8 +29,7 @@ comptime { } pub fn main() void {} #} -#update { -change the type#} +#update "change the type" #check errors { main.zig:8:37: error: reached unreachable code #} diff --git a/test/incremental/do_nothing b/test/incremental/do_nothing index 213f7f1892d8fa96dbb9313054d862513956ce66..ace818eacc418576e6fb787f736a29070ebf0967 100644 --- a/test/incremental/do_nothing +++ b/test/incremental/do_nothing @@ -1,6 +1,4 @@ -#todo { -it'd be great if we could actually check that no analysis happened! -#} +#todo "it'd be great if we could actually check that no analysis happened!" #exe { -Mroot=main.zig #} @@ -25,8 +23,7 @@ const O = opaque { }; #} #update -#check stdout { -#} +#check stdout #write main.zig { pub fn main() void { @@ -47,7 +44,5 @@ const O = opaque { } }; #} -#update { -do literally nothing#} -#check stdout { -#} +#update "do literally nothing" +#check stdout diff --git a/test/incremental/fix_astgen_failure b/test/incremental/fix_astgen_failure index feb078359a513becff249d9e5e89a88a2e243352..df25736b059af01381b17f12e8d9f6eceba3a163 100644 --- a/test/incremental/fix_astgen_failure +++ b/test/incremental/fix_astgen_failure @@ -12,8 +12,7 @@ pub fn hello() !void { try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); } #} -#update { -error#} +#update "error" #check errors { foo.zig:2:9: error: use of undeclared identifier 'std' #} @@ -25,8 +24,7 @@ pub fn hello() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -fix the error#} +#update "fix the error" #check stdout { Hello, World! #} @@ -38,8 +36,7 @@ pub fn hello() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add new error#} +#update "add new error" #check errors { foo.zig:3:52: error: use of undeclared identifier 'hello_str' #} @@ -52,8 +49,7 @@ pub fn hello() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -fix the new error#} +#update "fix the new error" #check stdout { Hello, World! Again! #} diff --git a/test/incremental/function_becomes_inline b/test/incremental/function_becomes_inline index 7d64be329579442c284c149e6342bcc0d3105c36..0a68a41407d4dd311b3b969bc4c157cdf90deaa3 100644 --- a/test/incremental/function_becomes_inline +++ b/test/incremental/function_becomes_inline @@ -12,8 +12,7 @@ fn foo() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -non-inline version#} +#update "non-inline version" #check stdout { Hello, World! #} @@ -28,8 +27,7 @@ inline fn foo() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -make function inline#} +#update "make function inline" #check stdout { Hello, World! #} @@ -44,8 +42,7 @@ inline fn foo() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change string#} +#update "change string" #check stdout { Hello, `inline` World! #} diff --git a/test/incremental/hello b/test/incremental/hello index 74a45d2a8b81afebe334968569949b6c82d4c397..8aab04829d520e382ed5bbbe156462a844a09585 100644 --- a/test/incremental/hello +++ b/test/incremental/hello @@ -21,8 +21,7 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n"); } #} -#update { -change the string#} +#update "change the string" #check stdout { おはようございます #} diff --git a/test/incremental/increase_array_field_length b/test/incremental/increase_array_field_length index 7b0eb9c165ff1a1b43206624569303b820d658ac..81d9d1ce8251658382c8c566241a84cc721f1e24 100644 --- a/test/incremental/increase_array_field_length +++ b/test/incremental/increase_array_field_length @@ -35,8 +35,7 @@ pub fn main(init: std.process.Init) !void { } const std = @import("std"); #} -#update { -increase array length#} +#update "increase array length" #check stdout { arr[999] = 234 #} diff --git a/test/incremental/make_decl_pub b/test/incremental/make_decl_pub index 59a54ece02b3850083fdd6c86c63d901cd346157..8055c5b7dfc9419740d46f19e50787c136eabc14 100644 --- a/test/incremental/make_decl_pub +++ b/test/incremental/make_decl_pub @@ -28,8 +28,7 @@ pub fn hello() !void { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -make hello pub#} +#update "make hello pub" #check stdout { Hello, World! #} diff --git a/test/incremental/matrix.zon b/test/incremental/matrix.zon new file mode 100644 index 0000000000000000000000000000000000000000..7c239ec719c4d5d5ccaf2b0e96cc305633f7d38f --- /dev/null +++ b/test/incremental/matrix.zon @@ -0,0 +1,61 @@ +.{ + // Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others + // to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang + // or LLVM). We just have a couple here to make sure that it works. + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .musl, + }, + .cache_mode = .incremental, + .backend = .cbe, + .linker = .old, + .pic = .nopic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .llvm, + .linker = .lld, + .pic = .nopic, + }, + + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .linux, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .selfhosted, + .linker = .new, + .pic = .nopic, + }, + .{ + .target = .{ + .cpu_arch = .x86_64, + .os_tag = .windows, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .selfhosted, + .linker = .old, + .pic = .pic, + }, + .{ + .target = .{ + .cpu_arch = .wasm32, + .os_tag = .wasi, + .abi = .none, + }, + .cache_mode = .incremental, + .backend = .selfhosted, + .linker = .old, + .pic = .nopic, + }, +} diff --git a/test/incremental/modify_inline_fn b/test/incremental/modify_inline_fn index 956a47a6da82a984edfb3cc9ebf788759c0c61a5..fba956d321e27b0d631e4473736c275f4e0f922c 100644 --- a/test/incremental/modify_inline_fn +++ b/test/incremental/modify_inline_fn @@ -29,8 +29,7 @@ inline fn getStr() []const u8 { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -change the string#} +#update "change the string" #check stdout { bar #} diff --git a/test/incremental/move_src b/test/incremental/move_src index b385a312dbb5d55b6f7605aee556abbda5f9ade4..1de952a6b9b31864ee273238aa3c5f177c30a4ef 100644 --- a/test/incremental/move_src +++ b/test/incremental/move_src @@ -36,8 +36,7 @@ fn bar() u32 { } const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -add newline#} +#update "add newline" #check stdout { 8 123 #} diff --git a/test/incremental/pointer_to_decl_with_astgen_error b/test/incremental/pointer_to_decl_with_astgen_error index 87d07ca1abe476a8bc0be5a2abfa2b127736127f..1ac7e90c460749db94e2e8e3209ee3921b75d20a 100644 --- a/test/incremental/pointer_to_decl_with_astgen_error +++ b/test/incremental/pointer_to_decl_with_astgen_error @@ -9,8 +9,7 @@ pub fn main() void { } #} #update -#check stdout { -#} +#check stdout #write main.zig { const foo = something; @@ -18,8 +17,7 @@ pub fn main() void { _ = &foo; } #} -#update { -introduce use of undeclared identifier#} +#update "introduce use of undeclared identifier" #check errors { main.zig:1:13: error: use of undeclared identifier 'something' #} @@ -30,7 +28,5 @@ pub fn main() void { _ = &foo; } #} -#update { -revert use of undeclared identifier#} -#check stdout { -#} +#update "revert use of undeclared identifier" +#check stdout diff --git a/test/incremental/recursive_function_becomes_non_recursive b/test/incremental/recursive_function_becomes_non_recursive index 442748a079c7bc0ca8a97fc726a661e86546acd1..df5bc83da9a5fd2a7376517f7a2737e51ae59d33 100644 --- a/test/incremental/recursive_function_becomes_non_recursive +++ b/test/incremental/recursive_function_becomes_non_recursive @@ -31,8 +31,7 @@ fn foo(recurse: bool) !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -eliminate recursion and change argument#} +#update "eliminate recursion and change argument" #check stdout { x==1 #} diff --git a/test/incremental/remove_enum_field b/test/incremental/remove_enum_field index 67b0db55b9d597270216eee728189fbd0a638833..049d98746163611f72e824f908016f466a5404b7 100644 --- a/test/incremental/remove_enum_field +++ b/test/incremental/remove_enum_field @@ -31,8 +31,7 @@ pub fn main() !void { const std = @import("std"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove enum field#} +#update "remove enum field" #check errors { main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo' main.zig:1:16: note: enum declared here diff --git a/test/incremental/remove_function_with_changed_callee b/test/incremental/remove_function_with_changed_callee index d0a04678922d9ef841393ad2903469baf6ed7ca6..3bfa9bca0705c4cbdfcad7690d08d81871a40c10 100644 --- a/test/incremental/remove_function_with_changed_callee +++ b/test/incremental/remove_function_with_changed_callee @@ -28,8 +28,7 @@ pub fn main() !void { } #} #update -#check stdout { -0#} +#check stdout "0" #write main.zig { //! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type. @@ -54,7 +53,5 @@ pub fn main() !void { try bar(.one); } #} -#update { -remove foo and change bar wasm function type#} -#check stdout { -1#} +#update "remove foo and change bar wasm function type" +#check stdout "1" diff --git a/test/incremental/remove_invalid_union_backing_enum b/test/incremental/remove_invalid_union_backing_enum index 8a2099afb4ebe92697ff76f773b53abb4eb8b871..f93c81b5b157b04e89d21506a6977cecfd44d0b1 100644 --- a/test/incremental/remove_invalid_union_backing_enum +++ b/test/incremental/remove_invalid_union_backing_enum @@ -33,7 +33,5 @@ pub fn main() void { _ = u; } #} -#update { -remove invalid backing enum#} -#check stdout { -#} +#update "remove invalid backing enum" +#check stdout diff --git a/test/incremental/struct_reification_becomes_anon_init b/test/incremental/struct_reification_becomes_anon_init index bd790cdeb9445aab9834c64f0a5fa683974b6d95..c317b0dd749874f22f175b79a7ce326067f21a6e 100644 --- a/test/incremental/struct_reification_becomes_anon_init +++ b/test/incremental/struct_reification_becomes_anon_init @@ -23,8 +23,7 @@ pub fn main(init: std.process.Init) !void { } const std = @import("std"); #} -#update { -change to `@TypeOf` anonymous init#} +#update "change to `@TypeOf` anonymous init" #check stdout { anon_field #} diff --git a/test/incremental/tag_name b/test/incremental/tag_name index 05991657cdbfd920ee24d094bb8db93ada706d17..d948d102f0ebdbec84de2460c29bea3d0f4f53e3 100644 --- a/test/incremental/tag_name +++ b/test/incremental/tag_name @@ -11,8 +11,7 @@ pub fn main() !void { } #} #update -#check stdout { -first#} +#check stdout "first" #write main.zig { const std = @import("std"); @@ -22,10 +21,8 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } #} -#update { -no change#} -#check stdout { -first#} +#update "no change" +#check stdout "first" #write main.zig { const std = @import("std"); @@ -35,7 +32,5 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); } #} -#update { -swap fields#} -#check stdout { -first#} +#update "swap fields" +#check stdout "first" diff --git a/test/incremental/temporary_analysis_error_in_generic_signature b/test/incremental/temporary_analysis_error_in_generic_signature index dbb3b6407eba276b9654775979353b53d9cea452..9b9292f4accc103d90dff97eaba552d8da9e522b 100644 --- a/test/incremental/temporary_analysis_error_in_generic_signature +++ b/test/incremental/temporary_analysis_error_in_generic_signature @@ -33,8 +33,7 @@ fn bar(comptime x: u8) @This().FooAlias { } const std = @import("std"); #} -#update { -change generic signature to use non-existent member#} +#update "change generic signature to use non-existent member" #check errors { main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias' main.zig:1:1: note: struct declared here @@ -54,8 +53,7 @@ fn bar(comptime x: u8) @This().FooAlias { } const std = @import("std"); #} -#update { -add that member, fixing the error#} +#update "add that member, fixing the error" #check stdout { Z #} diff --git a/test/incremental/temporary_parse_error b/test/incremental/temporary_parse_error index 9687ac4844b79133391f85addd09e71a44c8f6cd..033e5f581d207e24f12f000c4d35275368fbbca9 100644 --- a/test/incremental/temporary_parse_error +++ b/test/incremental/temporary_parse_error @@ -7,14 +7,12 @@ const std = @import("std"); pub fn main() !void {} #} #update -#check stdout { -#} +#check stdout #write main.zig { pub fn main() !void { #} -#update { -introduce parse error#} +#update "introduce parse error" #check errors { main.zig:2:1: error: expected statement, found 'EOF' #} @@ -22,7 +20,5 @@ main.zig:2:1: error: expected statement, found 'EOF' #write main.zig { pub fn main() !void {} #} -#update { -fix parse error#} -#check stdout { -#} +#update "fix parse error" +#check stdout diff --git a/test/incremental/type_becomes_comptime_only b/test/incremental/type_becomes_comptime_only index f174faacd788e3e5d4720c9badb1cb2e5f91c9ea..15a9d51176bca515225026f3ae85c0ef8197d6f6 100644 --- a/test/incremental/type_becomes_comptime_only +++ b/test/incremental/type_becomes_comptime_only @@ -14,8 +14,7 @@ pub fn main() void { } #} #update -#check stdout { -#} +#check stdout #write main.zig { const SomeType = comptime_int; @@ -28,10 +27,8 @@ pub fn main() void { s.foo(); } #} -#update { -make S comptime-only#} -#check stdout { -#} +#update "make S comptime-only" +#check stdout #write main.zig { const SomeType = u16; @@ -44,7 +41,5 @@ pub fn main() void { s.foo(); } #} -#update { -make S runtime again#} -#check stdout { -#} +#update "make S runtime again" +#check stdout diff --git a/test/incremental/type_dependency_loop b/test/incremental/type_dependency_loop index 85de8ae8391015b85194357423522046466cc042..1a5b1e2a49f467ebbea3420e3f8793db99628427 100644 --- a/test/incremental/type_dependency_loop +++ b/test/incremental/type_dependency_loop @@ -24,10 +24,8 @@ pub fn main() void { _ = B; } #} -#update { -remove reference to dependency loop#} -#check stdout { -#} +#update "remove reference to dependency loop" +#check stdout #write main.zig { pub const A = struct { b: B }; @@ -36,10 +34,8 @@ pub fn main() void { _ = B; } #} -#update { -change dependency loop without fixing it#} -#check stdout { -#} +#update "change dependency loop without fixing it" +#check stdout #write main.zig { pub const A = struct { b: B }; @@ -48,8 +44,7 @@ pub fn main() void { _ = @as(B, undefined); } #} -#update { -reference dependency loop again#} +#update "reference dependency loop again" #check errors { error: dependency loop with length 2 main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here @@ -64,7 +59,5 @@ pub fn main() void { _ = @as(B, undefined); } #} -#update { -fix dependency loop#} -#check stdout { -#} +#update "fix dependency loop" +#check stdout diff --git a/test/incremental/unreferenced_error b/test/incremental/unreferenced_error index 0f5f65feab5c98985d105d06db1e2086cd6f0470..fc63d66a96462524e35e8cba041fe4dd20cbc159 100644 --- a/test/incremental/unreferenced_error +++ b/test/incremental/unreferenced_error @@ -23,8 +23,7 @@ pub fn main() !void { const a = @compileError("bad a"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -introduce compile error#} +#update "introduce compile error" #check errors { main.zig:5:11: error: bad a #} @@ -38,8 +37,7 @@ const a = @compileError("bad a"); const b = "Hi there!\n"; const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -remove error reference#} +#update "remove error reference" #check stdout { Hi there! #} @@ -53,8 +51,7 @@ const a = "Back to a\n"; const b = @compileError("bad b"); const io = std.Io.Threaded.global_single_threaded.io(); #} -#update { -introduce and remove reference to error#} +#update "introduce and remove reference to error" #check stdout { Back to a #} diff --git a/test/tests.zig b/test/tests.zig index ba0079b752ffb808a2cebe89fb5776e1663aa34f..c65cbcee859aee2911ac5bef1027a5db5485bddf 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2201,137 +2201,6 @@ const RunnerTarget = struct { pic: enum { nopic, pic, pie }, }; -pub const incremental_matrix: []const RunnerTarget = &.{ - // Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others - // to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang - // or LLVM). We just have a couple here to make sure that it works. - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .musl, - }, - .cache_mode = .incremental, - .backend = .cbe, - .linker = .old, - .pic = .nopic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .llvm, - .linker = .lld, - .pic = .nopic, - }, - - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .selfhosted, - .linker = .new, - .pic = .nopic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .windows, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .selfhosted, - .linker = .old, - .pic = .pic, - }, - .{ - .target = .{ - .cpu_arch = .wasm32, - .os_tag = .wasi, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .selfhosted, - .linker = .old, - .pic = .nopic, - }, -}; - -pub const debugger_matrix: []const RunnerTarget = &.{ - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .whole, - .backend = .selfhosted, - .linker = .old, - .pic = .nopic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .whole, - .backend = .selfhosted, - .linker = .old, - .pic = .pic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .whole, - .backend = .selfhosted, - .linker = .new, - .pic = .nopic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .whole, - .backend = .selfhosted, - .linker = .new, - .pic = .pic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .selfhosted, - .linker = .new, - .pic = .nopic, - }, - .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, - .cache_mode = .incremental, - .backend = .selfhosted, - .linker = .new, - .pic = .pic, - }, -}; - pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step { const step = b.step("test-stack-traces", "Run the stack trace tests"); @@ -3224,21 +3093,24 @@ pub fn addRunnerTests( defer tests_dir.close(b.graph.io); var test_it = tests_dir.iterate(); while (try test_it.next(b.graph.io)) |@"test"| { + switch (@"test".kind) { + else => continue, + .file => { + if (std.mem.eql(u8, @"test".name, "matrix.zon")) continue; + if (isEditorFileName(@"test".name)) continue; + }, + .directory => {}, + } + for (options.test_filters) |filter| { if (std.mem.find(u8, @"test".name, filter) != null) break; } else if (options.test_filters.len > 0) continue; - const test_path = tests_path.path(b, @"test".name); - switch (@"test".kind) { - else => continue, - .file => if (isEditorFileName(@"test".name)) continue, - .directory => {}, - } - const run = b.addRunArtifact(runner); run.setName(@"test".name); run.enableProtocolMode(); + const test_path = tests_path.path(b, @"test".name); switch (@"test".kind) { else => continue, .file => run.addFileArg(test_path), -- 2.54.0 From 1157dd95714e57a699f06066ccfc7ed511ebf43f Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 8 Oct 2026 01:55:13 -0400 Subject: [PATCH 7/9] test/llvm-ir: convert to new runner --- build.zig | 9 +- lib/std/posix.zig | 2 +- test/Runner.zig | 31 +++++-- test/llvm-ir/allowzero | 72 +++++++++++++++ test/llvm-ir/array_to_vector | 38 ++++++++ test/llvm-ir/dead_store | 43 +++++++++ test/llvm-ir/load_store_bool | 28 ++++++ test/llvm-ir/matrix.zon | 9 ++ test/llvm-ir/nonnull | 30 +++++++ test/llvm-ir/unused_load | 79 ++++++++++++++++ test/llvm_ir.zig | 170 ----------------------------------- test/src/LlvmIr.zig | 135 ---------------------------- test/tests.zig | 23 +---- 13 files changed, 331 insertions(+), 338 deletions(-) create mode 100644 test/llvm-ir/allowzero create mode 100644 test/llvm-ir/array_to_vector create mode 100644 test/llvm-ir/dead_store create mode 100644 test/llvm-ir/load_store_bool create mode 100644 test/llvm-ir/matrix.zon create mode 100644 test/llvm-ir/nonnull create mode 100644 test/llvm-ir/unused_load delete mode 100644 test/llvm_ir.zig delete mode 100644 test/src/LlvmIr.zig diff --git a/build.zig b/build.zig index f2b6c5c9b6d2a3a560b31c5605367bd776ec3f60..cca0bdb582e373599b54faef9414cc7a6eef393e 100644 --- a/build.zig +++ b/build.zig @@ -712,11 +712,6 @@ pub fn build(b: *std.Build) !void { .skip_libc = skip_libc, })); test_step.dependOn(tests.addCliTests(b)); - if (tests.addLlvmIrTests(b, .{ - .enable_llvm = enable_llvm, - .test_filters = test_filters, - .test_target_filters = test_target_filters, - })) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step); try addWasiUpdateStep(b, version); @@ -822,6 +817,10 @@ pub fn build(b: *std.Build) !void { const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests"); try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts); test_step.dependOn(test_incremental_step); + + const test_llvm_ir_step = b.step("test-llvm-ir", "Run the LLVM IR tests"); + try tests.addRunnerTests(b, runner, test_llvm_ir_step, "test/llvm-ir", @import("test/llvm-ir/matrix.zon"), runner_opts); + test_step.dependOn(test_llvm_ir_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 146a521224cd1a041b9200eed79b1d1815918bfb..de41ed68cbe7619c947803c5705e6026525e3a3b 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -797,7 +797,7 @@ pub fn dl_iterate_phdr( const dl = @import("dynamic_library.zig"); switch (builtin.object_format) { - .elf, .c => {}, + .c, .elf, .llvmbc, .llvmir => {}, else => @compileError("dl_iterate_phdr is not available for this target"), } diff --git a/test/Runner.zig b/test/Runner.zig index d614036096d5de25984438bc00314d696d1409b0..5be751b87806c1b2bf6e16b3249722a134805d54 100644 --- a/test/Runner.zig +++ b/test/Runner.zig @@ -917,6 +917,7 @@ fn handleCommand( .arch_os_abi = triple, .object_format = switch (backend) { .sema, .selfhosted, .llvm => null, + .llvmir => "llvmir", .cbe => "c", }, }) catch |err| switch (err) { @@ -1075,7 +1076,7 @@ fn handleCommand( ), }; }, - .stdout, .exit, .gdb, .lldb => if (eb.errorMessageCount() > 0) { + .stdout, .exit, .llvm, .gdb, .lldb => if (eb.errorMessageCount() > 0) { eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) { error.Canceled => {}, else => {}, @@ -1146,6 +1147,7 @@ fn spawnCompiler( .sema => try argv.append(gpa, "-fno-emit-bin"), .selfhosted => try argv.append(gpa, "-fno-llvm"), .llvm => try argv.append(gpa, "-fllvm"), + .llvmir => try argv.append(gpa, "-ofmt=llvmir"), .cbe => try argv.append(gpa, "-ofmt=c"), } else try argv.appendSlice(gpa, &.{ "-I", path_buffer[0 .. (runner.args.lib_dir orelse return runner.fail("\"--lib=path/to/lib\" arg required with cbe", .{})) @@ -1287,6 +1289,8 @@ const Compiler = struct { /// Use the LLVM backend. /// Corresponds to `-fllvm -flld`. llvm, + /// Use the LLVM backend without libLLVM. + llvmir, /// Use the C backend. The output is compiled with `zig cc`. /// Corresponds to `-ofmt=c`. cbe, @@ -1325,7 +1329,7 @@ const Compiler = struct { return .{ .tag = header.tag, .body = body }; } - const Check = enum { errors, stdout, exit, gdb, lldb }; + const Check = enum { errors, stdout, exit, llvm, gdb, lldb }; fn checkSuccess( comp: *Compiler, update: *const Update, @@ -1361,7 +1365,7 @@ const Compiler = struct { var script_buffer: [512]u8 = undefined; const script_path, const script_file, var script_fw = script: switch (check) { .errors => return, - .stdout, .exit => .{ undefined, null, undefined }, + .stdout, .exit, .llvm => .{ undefined, null, undefined }, .gdb => { const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb"; argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" }); @@ -1425,7 +1429,7 @@ const Compiler = struct { const out_path = try std.Io.Dir.path.join(arena, &.{ out_dir_path, comp.out_name }); const bin_path = switch (comp.target.backend.?) { .sema => return, - .selfhosted, .llvm => out_path, + .selfhosted, .llvm, .llvmir => out_path, .cbe => try comp.compileC(update.src_dir, out_path), }; @@ -1527,6 +1531,23 @@ const Compiler = struct { .exe = exe: switch (check) { .errors => unreachable, .stdout, .exit => if (use_executor) .search else .{ .file = bin_file }, + .llvm => { + var bin_fr = bin_file.reader(io, &.{}); + const actual = bin_fr.interface.readAllocAll(arena, @intCast( + bin_fr.getSize() catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return runner.fail("unable to get size of {q}: {t}", .{ bin_path, e }), + }, + )) catch |err| switch (switch (err) { + error.OutOfMemory => |e| return e, + error.EndOfStream => |e| e, + error.ReadFailed => bin_fr.err.?, + }) { + error.Canceled => |e| return e, + else => |e| return runner.fail("unable to read {q}: {t}", .{ bin_path, e }), + }; + return update.checkMatches("LLVM IR", expected, actual); + }, .gdb, .lldb => { if (use_executor) { if (!runner.args.quiet) std.log.warn( @@ -1603,7 +1624,7 @@ const Compiler = struct { } switch (result.term) { .exited => |code| switch (check) { - .errors => unreachable, + .errors, .llvm => unreachable, .stdout => { if (code != 0) return update.fail( "generated executable {q} failed with code {d}", diff --git a/test/llvm-ir/allowzero b/test/llvm-ir/allowzero new file mode 100644 index 0000000000000000000000000000000000000000..e83cf1faf438b237f1d012a691d31998b4d437e3 --- /dev/null +++ b/test/llvm-ir/allowzero @@ -0,0 +1,72 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *allowzero i16) i16 { + return ptr.*; +} +#} +#update "load" +#check llvm { +define #...@test.entry(ptr #...%0) #...#0 #...{ +#...load i16, ptr %0#... +} + +#... +attributes #0 = {#... null_pointer_is_valid #...} +#} + +#write test.zig { +export fn entry(ptr: *allowzero i16) void { + ptr.* = 42; +} +#} +#update "store" +#check llvm { +define #...@test.entry(ptr #...%0) #...#0 #...{ +#...store i16 42, ptr %0#... +} + +#... +attributes #0 = {#... null_pointer_is_valid #...} +#} + +#write test.zig { +export fn entry(ptr: *allowzero i16) i16 { + return entry2(ptr[0..1]); +} +fn entry2(slice: []allowzero i16) i16 { + @setRuntimeSafety(false); + return slice[0]; +} +#} +#update "slice load" +#check llvm { +define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{ +#...load i16, ptr %#... +} + +#... +attributes #2 = {#... null_pointer_is_valid #...} +#} + +#write test.zig { +export fn entry(ptr: *allowzero i16) void { + entry2(ptr[0..1]); +} +fn entry2(slice: []allowzero i16) void { + @setRuntimeSafety(false); + slice[0] = 42; +} +#} +#update "slice store" +#check llvm { +define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{ +#...store i16 42, ptr %#... +} + +#... +attributes #2 = {#... null_pointer_is_valid #...} +#} diff --git a/test/llvm-ir/array_to_vector b/test/llvm-ir/array_to_vector new file mode 100644 index 0000000000000000000000000000000000000000..ab182e1284306a69018581765d41d99d4e45e893 --- /dev/null +++ b/test/llvm-ir/array_to_vector @@ -0,0 +1,38 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(arr: *const [16]u8) @Vector(16, u8) { + return arr.*; +} +#} +#update "one vector load" +#check llvm { +define #...<16 x i8> @test.entry(#...) #...{ +#... + %1 = alloca [16 x i8], align 1#... + %3 = load <16 x i8>, ptr %1, align 1#... + ret <16 x i8> %3#... +#} + +#write test.zig { +export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void { + const q: @Vector(16, u8) = src[0..16].*; + a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 }); + b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 }); +} +#} +#update "feeding overlapping shuffles" +#check llvm { +define #...void @test.entry(ptr #...%0, ptr #...%1, #...) #...{ +#... + %11 = load <16 x i8>, ptr %#... + %12 = shufflevector <16 x i8> %11, #... + store <8 x i8> %12, ptr %0, align 8#... + %13 = shufflevector <16 x i8> %11, #... + store <8 x i8> %13, ptr %1, align 8#... + ret void#... +} +#} diff --git a/test/llvm-ir/dead_store b/test/llvm-ir/dead_store new file mode 100644 index 0000000000000000000000000000000000000000..362b913db4c69597316b1d8bc3e0e82304ef6fc3 --- /dev/null +++ b/test/llvm-ir/dead_store @@ -0,0 +1,43 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + ptr.* = 123; + ptr.* = 321; +} +#} +#update "volatile" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...store volatile i16 123, ptr %0#... +#...store volatile i16 321, ptr %0#... +} + +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + entry2(ptr[0..1]); +} +fn entry2(slice: []volatile i16) void { + @setRuntimeSafety(false); + slice[0] = 123; + slice[0] = 321; +} +#} +#update "volatile slice" +#check llvm { +define #...@test.entry(#...) #...{ +#... +} + +#... +define #...@test.entry2(#...) #...{ +#...store volatile i16 123, ptr %#... +#...store volatile i16 321, ptr %#... +} + +#} diff --git a/test/llvm-ir/load_store_bool b/test/llvm-ir/load_store_bool new file mode 100644 index 0000000000000000000000000000000000000000..e38c45cfad468412e499a87dc42bbf9ae7844bc7 --- /dev/null +++ b/test/llvm-ir/load_store_bool @@ -0,0 +1,28 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn foo(a: *bool, b: *align(2) bool) void { + const tmp = a.*; + a.* = b.*; + b.* = tmp; +} +#} +#update +#check llvm { +define #...void @test.foo(ptr #...%0, ptr #...%1) #...{ +#... + %5 = load i8, ptr %0, align 1#... + %6 = trunc nuw i8 %5 to i1#... + %8 = load i8, ptr %1, align 2#... + %9 = trunc nuw i8 %8 to i1#... + %10 = zext i1 %9 to i8#... + store i8 %10, ptr %0, align 1#... + %11 = zext i1 %6 to i8#... + store i8 %11, ptr %1, align 2#... + ret void#... +} + +#} diff --git a/test/llvm-ir/matrix.zon b/test/llvm-ir/matrix.zon new file mode 100644 index 0000000000000000000000000000000000000000..681e7f7c3a925f928804bb598be3b52a5fabad59 --- /dev/null +++ b/test/llvm-ir/matrix.zon @@ -0,0 +1,9 @@ +.{ + .{ + .target = .{}, + .cache_mode = .whole, + .backend = .llvmir, + .linker = .old, + .pic = .pic, + }, +} diff --git a/test/llvm-ir/nonnull b/test/llvm-ir/nonnull new file mode 100644 index 0000000000000000000000000000000000000000..d3cb0546bdc83b6e3256d17ff0caed5f0a5232bd --- /dev/null +++ b/test/llvm-ir/nonnull @@ -0,0 +1,30 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *i16) i16 { + return ptr.*; +} +#} +#update "store" +#check llvm { +define #...@test.entry(ptr #...nonnull #...%0) #...{ +#...load i16, ptr %0#... +} + +#} + +#write test.zig { +export fn entry(ptr: *i16) void { + ptr.* = 42; +} +#} +#update "load" +#check llvm { +define #...@test.entry(ptr #...nonnull #...%0) #...{ +#...store i16 42, ptr %0#... +} + +#} diff --git a/test/llvm-ir/unused_load b/test/llvm-ir/unused_load new file mode 100644 index 0000000000000000000000000000000000000000..8f6f3a59cfa74bf420520802d2559b6f49bbe948 --- /dev/null +++ b/test/llvm-ir/unused_load @@ -0,0 +1,79 @@ +#obj { +--name test +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *i16) void { + _ = @atomicLoad(i16, ptr, .acquire); +} +#} +#update "atomic acquire" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...load atomic i16, ptr %0 acquire#... +} + +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + _ = @atomicLoad(i16, ptr, .unordered); +} +#} +#update "atomic volatile unordered" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...load atomic volatile i16, ptr %0 unordered#... +} + +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + _ = ptr.*; +} +#} +#update "volatile" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...load volatile i16, ptr %0#... +} + +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + entry2(ptr[0..1]); +} +fn entry2(slice: []volatile i16) void { + @setRuntimeSafety(false); + _ = slice[0]; +} +#} +#update "volatile slice" +#check llvm { +define #...@test.entry(#...) #...{ +#... +} + +#... +define #...@test.entry2(#...) #...{ +#...load volatile i16, ptr %#... +} + +#} + +#write test.zig { +const S = packed struct(u16) { a: u2, b: u8, c: u6 }; +export fn entry(ptr: *volatile S) void { + _ = ptr.b; +} +#} +#update "volatile packed" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...load volatile i16, ptr %#... +} + +#} diff --git a/test/llvm_ir.zig b/test/llvm_ir.zig deleted file mode 100644 index 9cb9dab42e85753e168fe7d9ca4f8c049754b19c..0000000000000000000000000000000000000000 --- a/test/llvm_ir.zig +++ /dev/null @@ -1,170 +0,0 @@ -pub fn addCases(cases: *tests.LlvmIrContext) void { - cases.addMatches("nonnull ptr load", - \\export fn entry(ptr: *i16) i16 { - \\ return ptr.*; - \\} - , &.{ - "ptr nonnull", - "load i16, ptr %0", - }, .{}); - - cases.addMatches("nonnull ptr store", - \\export fn entry(ptr: *i16) void { - \\ ptr.* = 42; - \\} - , &.{ - "ptr nonnull", - "store i16 42, ptr %0", - }, .{}); - - cases.addMatches("unused acquire atomic ptr load", - \\export fn entry(ptr: *i16) void { - \\ _ = @atomicLoad(i16, ptr, .acquire); - \\} - , &.{ - "load atomic i16, ptr %0 acquire", - }, .{}); - - cases.addMatches("unused unordered atomic volatile ptr load", - \\export fn entry(ptr: *volatile i16) void { - \\ _ = @atomicLoad(i16, ptr, .unordered); - \\} - , &.{ - "load atomic volatile i16, ptr %0 unordered", - }, .{}); - - cases.addMatches("unused volatile ptr load", - \\export fn entry(ptr: *volatile i16) void { - \\ _ = ptr.*; - \\} - , &.{ - "load volatile i16, ptr %0", - }, .{}); - - cases.addMatches("dead volatile ptr store", - \\export fn entry(ptr: *volatile i16) void { - \\ ptr.* = 123; - \\ ptr.* = 321; - \\} - , &.{ - "store volatile i16 123, ptr %0", - "store volatile i16 321, ptr %0", - }, .{}); - - cases.addMatches("unused volatile slice load", - \\export fn entry(ptr: *volatile i16) void { - \\ entry2(ptr[0..1]); - \\} - \\fn entry2(ptr: []volatile i16) void { - \\ _ = ptr[0]; - \\} - , &.{ - "load volatile i16, ptr", - }, .{}); - - cases.addMatches("dead volatile slice store", - \\export fn entry(ptr: *volatile i16) void { - \\ entry2(ptr[0..1]); - \\} - \\fn entry2(ptr: []volatile i16) void { - \\ ptr[0] = 123; - \\ ptr[0] = 321; - \\} - , &.{ - "store volatile i16 123, ptr", - "store volatile i16 321, ptr", - }, .{}); - - cases.addMatches("unused volatile packed pointer load", - \\const S = packed struct(u16) { a: u2, b: u8, c: u6 }; - \\export fn entry(ptr: *volatile S) void { - \\ _ = ptr.b; - \\} - , &.{ - "load volatile i16, ptr", - }, .{}); - - cases.addMatches("allowzero ptr load", - \\export fn entry(ptr: *allowzero i16) i16 { - \\ return ptr.*; - \\} - , &.{ - "null_pointer_is_valid", - "load i16, ptr %0", - }, .{}); - - cases.addMatches("allowzero ptr store", - \\export fn entry(ptr: *allowzero i16) void { - \\ ptr.* = 42; - \\} - , &.{ - "null_pointer_is_valid", - "store i16 42, ptr %0", - }, .{}); - - cases.addMatches("allowzero slice load", - \\export fn entry(ptr: *allowzero i16) i16 { - \\ return entry2(ptr[0..1]); - \\} - \\fn entry2(ptr: []allowzero i16) i16 { - \\ return ptr[0]; - \\} - , &.{ - "null_pointer_is_valid", - "load i16, ptr", - }, .{}); - - cases.addMatches("allowzero slice store", - \\export fn entry(ptr: *allowzero i16) void { - \\ entry2(ptr[0..1]); - \\} - \\fn entry2(ptr: []allowzero i16) void { - \\ ptr[0] = 42; - \\} - , &.{ - "null_pointer_is_valid", - "store i16 42, ptr", - }, .{}); - - cases.addMatches("load and store bool", - \\export fn foo(a: *bool, b: *align(2) bool) void { - \\ const tmp = a.*; - \\ a.* = b.*; - \\ b.* = tmp; - \\} - , &.{ - // TODO: this should all be one multiline string literal, but `-femit-llvm-ir` is currently - // emitting CRLF on Windows, which is a pain to handle here. In future that option will emit - // unoptimized LLVM IR emitted directly from Zig, so that bug will go away. - " %3 = load i8, ptr %0, align 1", - " %4 = trunc nuw i8 %3 to i1", - " %5 = load i8, ptr %1, align 2", - " %6 = trunc nuw i8 %5 to i1", - " %7 = zext i1 %6 to i8", - " store i8 %7, ptr %0, align 1", - " %8 = zext i1 %4 to i8", - " store i8 %8, ptr %1, align 2", - }, .{ .strip = true }); - - cases.addMatches("array to vector coercion is one vector load", - \\export fn entry(arr: *const [16]u8) @Vector(16, u8) { - \\ return arr.*; - \\} - , &.{ - "load <16 x i8>, ptr", - }, .{}); - - cases.addMatches("array to vector coercion feeding overlapping shuffles", - \\export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void { - \\ const q: @Vector(16, u8) = src[0..16].*; - \\ a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 }); - \\ b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 }); - \\} - , &.{ - "load <16 x i8>, ptr", - "shufflevector <16 x i8>", - }, .{}); -} - -const std = @import("std"); -const tests = @import("tests.zig"); diff --git a/test/src/LlvmIr.zig b/test/src/LlvmIr.zig deleted file mode 100644 index 3dce66058b2c3eb21e9046f16091d348826d37a4..0000000000000000000000000000000000000000 --- a/test/src/LlvmIr.zig +++ /dev/null @@ -1,135 +0,0 @@ -b: *std.Build, -options: Options, -root_step: *std.Build.Step, - -pub const Options = struct { - enable_llvm: bool, - test_filters: []const []const u8, - test_target_filters: []const []const u8, -}; - -const TestCase = struct { - name: []const u8, - source: []const u8, - check: union(enum) { - matches: []const []const u8, - exact: []const u8, - }, - params: Params, - - pub const Params = struct { - code_model: std.builtin.CodeModel = .default, - dll_export_fns: ?bool = null, - dwarf_format: ?std.dwarf.Format = null, - error_tracing: ?bool = null, - no_builtin: ?bool = null, - omit_frame_pointer: ?bool = null, - // For most cases, we want to test the LLVM IR that we output; we don't want to be in the - // business of testing LLVM's optimization passes. `Debug` gets us the closest to that as it - // disables the vast majority of passes in LLVM. - optimize: std.builtin.Optimize = .debug, - pic: ?bool = null, - pie: ?bool = null, - red_zone: ?bool = null, - sanitize_thread: ?bool = null, - single_threaded: ?bool = null, - stack_check: ?bool = null, - stack_protector: ?bool = null, - strip: ?bool = null, - target: std.Target.Query = .{}, - unwind_tables: ?std.builtin.UnwindTables = null, - valgrind: ?bool = null, - }; -}; - -pub fn addMatches( - self: *LlvmIr, - name: []const u8, - source: []const u8, - matches: []const []const u8, - params: TestCase.Params, -) void { - self.addCase(.{ - .name = name, - .source = source, - .check = .{ .matches = matches }, - .params = params, - }); -} - -pub fn addExact( - self: *LlvmIr, - name: []const u8, - source: []const u8, - expected: []const []const u8, - params: TestCase.Params, -) void { - self.addCase(.{ - .name = name, - .source = source, - .check = .{ .exact = expected }, - .params = params, - }); -} - -pub fn addCase(self: *LlvmIr, case: TestCase) void { - const target = self.b.resolveTargetQuery(case.params.target); - if (self.options.test_target_filters.len > 0) { - const triple_txt = target.query.zigTriple(self.b.allocator) catch @panic("OOM"); - for (self.options.test_target_filters) |filter| { - if (std.mem.find(u8, triple_txt, filter) != null) break; - } else return; - } - - const name = std.fmt.allocPrint(self.b.allocator, "check llvm-ir {s}", .{case.name}) catch @panic("OOM"); - if (self.options.test_filters.len > 0) { - for (self.options.test_filters) |filter| { - if (std.mem.find(u8, name, filter) != null) break; - } else return; - } - - const obj = self.b.addObject(.{ - .name = "test", - .root_module = self.b.createModule(.{ - .root_source_file = self.b.addWriteFiles().add("test.zig", case.source), - - .code_model = case.params.code_model, - .error_tracing = case.params.error_tracing, - .omit_frame_pointer = case.params.omit_frame_pointer, - .optimize = case.params.optimize, - .pic = case.params.pic, - .sanitize_thread = case.params.sanitize_thread, - .single_threaded = case.params.single_threaded, - .strip = case.params.strip, - .target = target, - .unwind_tables = case.params.unwind_tables, - }), - .use_llvm = true, - }); - - obj.dll_export_fns = case.params.dll_export_fns; - obj.pie = case.params.pie; - - obj.root_module.dwarf_format = case.params.dwarf_format; - obj.root_module.no_builtin = case.params.no_builtin; - obj.root_module.red_zone = case.params.red_zone; - obj.root_module.stack_check = case.params.stack_check; - obj.root_module.stack_protector = case.params.stack_protector; - obj.root_module.valgrind = case.params.valgrind; - - // This is not very sophisticated at the moment. Eventually, we should move towards something - // like LLVM's `FileCheck` utility (https://llvm.org/docs/CommandGuide/FileCheck.html), though - // likely a more simplified version as we probably don't want a full-blown regex engine in the - // standard library... - const check = self.b.addCheckFile(obj.getEmittedLlvmIr(), switch (case.check) { - .matches => |m| .{ .expected_matches = m }, - .exact => |e| .{ .expected_exact = e }, - }); - check.setName(name); - check.max_bytes = 64 * 1024 * 1024; // allow fairly big LLVM IR files - - self.root_step.dependOn(&check.step); -} - -const LlvmIr = @This(); -const std = @import("std"); diff --git a/test/tests.zig b/test/tests.zig index c65cbcee859aee2911ac5bef1027a5db5485bddf..eca020095684e3ee05feaf4ba093c8d0e1fc6bdd 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -6,14 +6,12 @@ const OptimizeMode = std.builtin.Optimize; const Step = std.Build.Step; // Cases -const llvm_ir = @import("llvm_ir.zig"); const libc = @import("libc.zig"); const link = @import("link.zig"); // Implementations pub const ErrorTracesContext = @import("src/ErrorTrace.zig"); pub const StackTracesContext = @import("src/StackTrace.zig"); -pub const LlvmIrContext = @import("src/LlvmIr.zig"); pub const LibcContext = @import("src/Libc.zig"); pub const LinkContext = @import("src/Link.zig"); @@ -2196,7 +2194,7 @@ const link_targets = blk: { const RunnerTarget = struct { target: std.Target.Query, cache_mode: enum { whole, incremental }, - backend: enum { selfhosted, llvm, cbe }, + backend: enum { selfhosted, llvm, llvmir, cbe }, linker: enum { lld, old, new }, pic: enum { nopic, pic, pie }, }; @@ -3175,25 +3173,6 @@ fn isEditorFileName(name: []const u8) bool { std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp"); } -pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step { - const step = b.step("test-llvm-ir", "Run the LLVM IR tests"); - - if (!options.enable_llvm) { - step.dependOn(&b.addFail("test-llvm-ir requires -Denable-llvm").step); - return null; - } - - var context: LlvmIrContext = .{ - .b = b, - .options = options, - .root_step = step, - }; - - llvm_ir.addCases(&context); - - return step; -} - const libc_test_nsz_targets: []const std.Target.Query = &.{ .{ .cpu_arch = .arm, -- 2.54.0 From 3cc4f2f0dc660ff505ad35ee68b8f66484648530 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Thu, 15 Oct 2026 14:12:30 -0400 Subject: [PATCH 8/9] test/llvm-targets: convert to new runner --- build.zig | 14 +- lib/std/Target/Query.zig | 158 +++++------- test/Runner.zig | 309 ++++++++++++++++++++++- test/cases.zig | 3 +- test/debugger/enums | 8 +- test/debugger/errors | 8 +- test/debugger/inline_call/manifest | 4 +- test/debugger/matrix.zon | 48 ++-- test/debugger/unions | 8 +- test/incremental/matrix.zon | 40 ++- test/llvm-ir/matrix.zon | 1 - test/llvm-targets/empty_analyze | 50 ++++ test/llvm-targets/empty_assembly | 55 +++++ test/llvm-targets/empty_object | 67 +++++ test/llvm-targets/matrix.zon | 355 +++++++++++++++++++++++++++ test/llvm_targets.zig | 382 ----------------------------- test/src/Cases.zig | 32 --- test/tests.zig | 43 ++-- 18 files changed, 965 insertions(+), 620 deletions(-) create mode 100644 test/llvm-targets/empty_analyze create mode 100644 test/llvm-targets/empty_assembly create mode 100644 test/llvm-targets/empty_object create mode 100644 test/llvm-targets/matrix.zon delete mode 100644 test/llvm_targets.zig diff --git a/build.zig b/build.zig index cca0bdb582e373599b54faef9414cc7a6eef393e..985418a1389f8aa1bd131e3d338d88afa8600943 100644 --- a/build.zig +++ b/build.zig @@ -504,12 +504,6 @@ pub fn build(b: *std.Build) !void { .skip_linux = skip_linux, .skip_llvm = skip_llvm, .skip_libc = skip_libc, - }, .{ - .enable_llvm = enable_llvm, - .llvm_has_m68k = llvm_has_m68k, - .llvm_has_csky = llvm_has_csky, - .llvm_has_arc = llvm_has_arc, - .llvm_has_xtensa = llvm_has_xtensa, }); test_step.dependOn(test_cases_step); @@ -804,6 +798,10 @@ pub fn build(b: *std.Build) !void { .skip_darwin = skip_darwin, .skip_linux = skip_linux, .skip_llvm = skip_llvm, + .llvm_has_m68k = llvm_has_m68k, + .llvm_has_csky = llvm_has_csky, + .llvm_has_arc = llvm_has_arc, + .llvm_has_xtensa = llvm_has_xtensa, .gdb = b.option([]const u8, "gdb", "path to gdb binary"), .lldb = b.option([]const u8, "lldb", "path to lldb binary"), }; @@ -821,6 +819,10 @@ pub fn build(b: *std.Build) !void { const test_llvm_ir_step = b.step("test-llvm-ir", "Run the LLVM IR tests"); try tests.addRunnerTests(b, runner, test_llvm_ir_step, "test/llvm-ir", @import("test/llvm-ir/matrix.zon"), runner_opts); test_step.dependOn(test_llvm_ir_step); + + const test_llvm_targets_step = b.step("test-llvm-targets", "Run the LLVM targets tests"); + try tests.addRunnerTests(b, runner, test_llvm_targets_step, "test/llvm-targets", @import("test/llvm-targets/matrix.zon"), runner_opts); + test_step.dependOn(test_llvm_targets_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/lib/std/Target/Query.zig b/lib/std/Target/Query.zig index 91df353ef218342e4e790e2c64318dfef52ae797..bace539353e1fb9427d7e355a679ecf80275bd1b 100644 --- a/lib/std/Target/Query.zig +++ b/lib/std/Target/Query.zig @@ -261,13 +261,11 @@ pub fn parse(args: ParseOptions) !Query { if (abi_it.next() != null) { if (abi.isGnu()) { result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) { - error.Overflow => return error.InvalidAbiVersion, - error.InvalidVersion => return error.InvalidAbiVersion, + error.Overflow, error.InvalidVersion => return error.InvalidAbiVersion, }; } else if (abi.isAndroid()) { result.android_api_level = std.fmt.parseUnsigned(u32, abi_ver_text, 10) catch |err| switch (err) { - error.InvalidCharacter => return error.InvalidVersion, - error.Overflow => |e| return e, + error.InvalidCharacter, error.Overflow => return error.InvalidAbiVersion, }; } else { return error.InvalidAbiVersion; @@ -428,139 +426,105 @@ pub fn canDetectLibC(self: Query) bool { return false; } -/// Formats a version with the patch component omitted if it is zero, +/// Prints a version with the patch component omitted if it is zero, /// unlike SemanticVersion.format which formats all its version components regardless. -fn formatVersion(version: SemanticVersion, gpa: Allocator, list: *ArrayList(u8)) !void { - if (version.patch == 0) { - try list.print(gpa, "{d}.{d}", .{ version.major, version.minor }); - } else { - try list.print(gpa, "{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); +pub const PrintVersion = struct { + version: SemanticVersion, + pub fn format(print: PrintVersion, w: *std.Io.Writer) std.Io.Writer.Error!void { + try w.print("{d}.{d}", .{ print.version.major, print.version.minor }); + switch (print.version.patch) { + 0 => {}, + else => |patch| try w.print(".{d}", .{patch}), + } } -} +}; -pub fn zigTriple(self: Query, gpa: Allocator) Allocator.Error![]u8 { - if (self.isNativeTriple()) return gpa.dupe(u8, "native"); +pub fn printZigTriple(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void { + if (query.isNativeTriple()) return w.writeAll("native"); - const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native"; - const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native"; - - var result: ArrayList(u8) = .empty; - defer result.deinit(gpa); - - try result.print(gpa, "{s}-{s}", .{ arch_name, os_name }); + try w.print("{s}-{s}", .{ + if (query.cpu_arch) |arch| @tagName(arch) else "native", + if (query.os_tag) |os_tag| @tagName(os_tag) else "native", + }); // The zig target syntax does not allow specifying a max os version with no min, so // if either are present, we need the min. - if (self.os_version_min) |min| { + if (query.os_version_min) |min| { switch (min) { .none => {}, - .semver => |v| { - try result.appendSlice(gpa, "."); - try formatVersion(v, gpa, &result); - }, - .windows => |v| { - try result.print(gpa, "{f}", .{v}); - }, + .semver => |v| try w.print(".{f}", .{PrintVersion{ .version = v }}), + .windows => |v| try w.print("{f}", .{v}), } } - if (self.os_version_max) |max| { + if (query.os_version_max) |max| { switch (max) { .none => {}, - .semver => |v| { - try result.appendSlice(gpa, "..."); - try formatVersion(v, gpa, &result); - }, - .windows => |v| { - // This is counting on a custom format() function defined on `WindowsVersion` - // to add a prefix '.' and make there be a total of three dots. - try result.print(gpa, "..{f}", .{v}); - }, + .semver => |v| try w.print("...{f}", .{PrintVersion{ .version = v }}), + // This is counting on a custom format() function defined on `WindowsVersion` + // to add a prefix '.' and make there be a total of three dots. + .windows => |v| try w.print("..{f}", .{v}), } } - if (self.glibc_version) |v| { - const name = @tagName(self.abi.?); - try result.ensureUnusedCapacity(gpa, name.len + 2); - result.appendAssumeCapacity('-'); - result.appendSliceAssumeCapacity(name); - result.appendAssumeCapacity('.'); - try formatVersion(v, gpa, &result); - } else if (self.android_api_level) |lvl| { - const name = @tagName(self.abi.?); - try result.ensureUnusedCapacity(gpa, name.len + 2); - result.appendAssumeCapacity('-'); - result.appendSliceAssumeCapacity(name); - result.appendAssumeCapacity('.'); - try result.print(gpa, "{d}", .{lvl}); - } else if (self.abi) |abi| { - const name = @tagName(abi); - try result.ensureUnusedCapacity(gpa, name.len + 1); - result.appendAssumeCapacity('-'); - result.appendSliceAssumeCapacity(name); + if (query.glibc_version) |v| { + try w.print("-{t}.{f}", .{ query.abi.?, PrintVersion{ .version = v } }); + } else if (query.android_api_level) |lvl| { + try w.print("-{t}.{d}", .{ query.abi.?, lvl }); + } else if (query.abi) |abi| { + try w.print("-{t}", .{abi}); } - - return result.toOwnedSlice(gpa); } -/// Renders the query into a textual representation that can be parsed via the +/// Prints the query into a textual representation that can be parsed via the /// `-mcpu` flag passed to the Zig compiler. -/// Appends the result to `buffer`. -pub fn serializeCpu(q: Query, buffer: *std.array_list.Managed(u8)) Allocator.Error!void { - try buffer.ensureUnusedCapacity(8); - switch (q.cpu_model) { - .native => { - buffer.appendSliceAssumeCapacity("native"); - }, - .baseline => { - buffer.appendSliceAssumeCapacity("baseline"); - }, - .determined_by_arch_os => { - if (q.cpu_arch == null) { - buffer.appendSliceAssumeCapacity("native"); - } else { - buffer.appendSliceAssumeCapacity("baseline"); - } - }, - .explicit => |model| { - try buffer.appendSlice(model.name); - }, +pub fn printCpu(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void { + cpu_model: switch (query.cpu_model) { + .native, .baseline => |_, cpu_model| try w.print("{t}", .{cpu_model}), + .determined_by_arch_os => continue :cpu_model if (query.cpu_arch) |_| .baseline else .native, + .explicit => |model| try w.writeAll(model.name), } - if (q.cpu_features_add.isEmpty() and q.cpu_features_sub.isEmpty()) { + if (query.cpu_features_add.isEmpty() and query.cpu_features_sub.isEmpty()) { // The CPU name alone is sufficient. return; } - const cpu_arch = q.cpu_arch orelse builtin.cpu.arch; + const cpu_arch = query.cpu_arch orelse builtin.cpu.arch; const all_features = cpu_arch.allFeaturesList(); for (all_features, 0..) |feature, i_usize| { const i: Target.Cpu.Feature.Set.Index = @intCast(i_usize); - try buffer.ensureUnusedCapacity(feature.name.len + 1); - if (q.cpu_features_sub.isEnabled(i)) { - buffer.appendAssumeCapacity('-'); - buffer.appendSliceAssumeCapacity(feature.name); - } else if (q.cpu_features_add.isEnabled(i)) { - buffer.appendAssumeCapacity('+'); - buffer.appendSliceAssumeCapacity(feature.name); + if (query.cpu_features_sub.isEnabled(i)) { + try w.print("-{s}", .{feature.name}); + } else if (query.cpu_features_add.isEnabled(i)) { + try w.print("+{s}", .{feature.name}); } } } -pub fn serializeCpuAlloc(q: Query, ally: Allocator) Allocator.Error![]u8 { - var buffer = std.array_list.Managed(u8).init(ally); - try serializeCpu(q, &buffer); - return buffer.toOwnedSlice(); +/// Deprecated; use `printZigTriple` instead. Will be removed in 0.19.0. +pub fn zigTriple(query: Query, gpa: Allocator) Allocator.Error![]u8 { + return gpa.print("{f}", .{std.fmt.alt(&query, .printZigTriple)}); +} + +/// Deprecated; use `printCpu` instead. Will be removed in 0.19.0. +pub fn serializeCpu(query: Query, buffer: *std.array_list.Managed(u8)) Allocator.Error!void { + try buffer.print("{f}", .{std.fmt.alt(&query, .printCpu)}); +} + +/// Deprecated; use `printCpu` instead. Will be removed in 0.19.0. +pub fn serializeCpuAlloc(query: Query, gpa: Allocator) Allocator.Error![]u8 { + return gpa.print("{f}", .{std.fmt.alt(&query, .printCpu)}); } /// Deprecated; use `zigTriple` instead. Will be removed in 0.18.0. -pub fn allocDescription(self: Query, allocator: Allocator) ![]u8 { - return self.zigTriple(allocator); +pub fn allocDescription(query: Query, allocator: Allocator) ![]u8 { + return query.zigTriple(allocator); } /// Deprecated; set `glibc_version` directly. Will be removed in 0.18.0. -pub fn setGnuLibCVersion(self: *Query, major: u32, minor: u32, patch: u32) void { - self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; +pub fn setGnuLibCVersion(query: *Query, major: u32, minor: u32, patch: u32) void { + query.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; } fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !void { diff --git a/test/Runner.zig b/test/Runner.zig index 5be751b87806c1b2bf6e16b3249722a134805d54..858809125745c16e9f9ccc17b7c8f4d2bc245130 100644 --- a/test/Runner.zig +++ b/test/Runner.zig @@ -3,6 +3,256 @@ const builtin = @import("builtin"); const std = @import("std"); const Runner = @This(); +/// These are passed as `----` strings. +/// +/// If only one specific test is failing on a target, instead of entirely disabling the target here, you +/// can skip the target for that specific test only by adding a line like this to top of the manifest: +/// +/// #skip x86_64-linux-none-baseline-whole-selfhosted-new-pic +pub const Target = struct { + cpu: Cpu = .{ .native = .{} }, + os: Os = .native, + abi: Abi = .default, + ofmt: ObjectFormat = .default, + dynamic_linker: DynamicLinker = .default, + + cache_mode: enum { whole, incremental }, + backend: enum { selfhosted, llvm, llvmir, cbe }, + linker: enum { lld, old, new }, + pic: enum { nopic, pic, pie }, + + pub const Cpu = Cpu: { + @setEvalBranchQuota(3_000); + const Arch = std.Target.Cpu.Arch; + const arch_info = @typeInfo(Arch).@"enum"; + const field_names = .{"native"} ++ arch_info.field_names; + var field_types: [field_names.len]type = undefined; + field_types[0] = struct { + model: Model = .native, + + pub const Model = enum { native, baseline }; + }; + for (field_types[1..], field_names[1..]) |*field_type, field_name| { + const arch = @field(Arch, field_name); + const models = arch.allCpuModels(); + const family = @field(std.Target, @tagName(arch.family())); + field_type.* = struct { + model: Model = .baseline, + features: struct { + add: []const Feature = &.{}, + remove: []const Feature = &.{}, + comptime { + _ = &family; // hack around compiler bug + } + } = .{}, + + pub const Model = Model: { + const explicit_models = @typeInfo(family.cpu).@"struct".decl_names; + var model_names: []const []const u8 = &.{"native"}; + if (!@hasDecl(family.cpu, "baseline")) model_names = model_names ++ .{"baseline"}; + model_names = model_names ++ explicit_models; + const TagInt = std.math.IntFittingRange(0, model_names.len - 1); + var model_values: [model_names.len]TagInt = undefined; + var model_index = 0; + { + var model_value = explicit_models.len; + model_values[model_index] = model_value; + model_index += 1; + model_value += 1; + if (!@hasDecl(family.cpu, "baseline")) { + model_values[model_index] = model_value; + model_index += 1; + model_value += 1; + } + } + for (model_values[model_index..], 0..) |*model_value, value| model_value.* = value; + break :Model @Enum(TagInt, .exhaustive, model_names, &model_values); + }; + + pub const Feature = family.Feature; + + pub fn updateQuery(cpu: *const @This(), query: *std.Target.Query) void { + query.cpu_model = switch (cpu.model) { + .native => .native, + .baseline => .baseline, + else => |model| .{ .explicit = models[@backingInt(model)] }, + }; + for (cpu.features.add) |add_feature| + query.cpu_features_add.addFeature(@backingInt(add_feature)); + for (cpu.features.remove) |remove_feature| + query.cpu_features_sub.addFeature(@backingInt(remove_feature)); + } + }; + } + const TagInt = std.math.IntFittingRange(0, field_names.len - 1); + var field_values: [field_names.len]TagInt = undefined; + field_values[0] = field_names.len - 1; + for (field_values[1..], arch_info.field_values) |*field_value, value| field_value.* = value; + const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values); + break :Cpu @Union(.auto, Tag, field_names, &field_types, &@splat(.{})); + }; + + pub const Os = Os: { + const os_info = @typeInfo(std.Target.Os.Tag).@"enum"; + const field_names = .{"native"} ++ os_info.field_names; + var field_types: [field_names.len]type = undefined; + field_types[0] = void; + for (field_types[1..], field_names[1..]) |*field_type, field_name| { + const version: enum { + none, + semver, + windows, + } = switch (@field(std.Target.Os.Tag, field_name).versionRangeTag()) { + .none => .none, + .semver, .hurd, .linux => .semver, + .windows => .windows, + }; + field_type.* = struct { + version: ?Version = null, + + pub const Version = switch (version) { + .none => struct {}, + .semver => struct { + min: std.SemanticVersion, + max: ?std.SemanticVersion = null, + }, + .windows => struct { + min: std.Target.Os.WindowsVersion, + max: ?std.Target.Os.WindowsVersion = null, + }, + }; + + pub fn updateQuery(os: *const @This(), query: *std.Target.Query) void { + if (os.version) |v| switch (version) { + .none => {}, + .semver => { + query.os_version_min = .{ .semver = v.min }; + if (v.max) |max| query.os_version_max = .{ .semver = max }; + }, + .windows => { + query.os_version_min = .{ .windows = v.min }; + if (v.max) |max| query.os_version_max = .{ .windows = max }; + }, + }; + } + }; + } + const TagInt = std.math.IntFittingRange(0, field_names.len - 1); + var field_values: [field_names.len]TagInt = undefined; + field_values[0] = field_names.len - 1; + for (field_values[1..], os_info.field_values) |*field_value, value| field_value.* = value; + const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values); + break :Os @Union(.auto, Tag, field_names, &field_types, &@splat(.{})); + }; + + pub const Abi = Abi: { + const abi_info = @typeInfo(std.Target.Abi).@"enum"; + const field_names = .{"default"} ++ abi_info.field_names; + var field_types: [field_names.len]type = undefined; + field_types[0] = void; + for (field_types[1..], field_names[1..]) |*field_type, field_name| { + const abi_tag = @field(std.Target.Abi, field_name); + const version: enum { none, libc, android } = if (abi_tag.isAndroid()) + .android + else if (abi_tag.isGnu() or abi_tag.isMusl()) + .libc + else + .none; + field_type.* = struct { + version: ?Version = null, + + pub const Version = switch (version) { + .none => struct {}, + .libc => std.SemanticVersion, + .android => u32, + }; + + pub fn updateQuery(abi: *const @This(), query: *std.Target.Query) void { + if (abi.version) |v| switch (version) { + .none => {}, + .libc => query.glibc_version = v, + .android => query.android_api_level = v, + }; + } + }; + } + const TagInt = std.math.IntFittingRange(0, field_names.len - 1); + var field_values: [field_names.len]TagInt = undefined; + field_values[0] = field_names.len - 1; + for (field_values[1..], abi_info.field_values) |*field_value, value| field_value.* = value; + const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values); + break :Abi @Union(.auto, Tag, field_names, &field_types, &@splat(.{})); + }; + + pub const ObjectFormat = ObjectFormat: { + const ofmt_info = @typeInfo(std.Target.ObjectFormat).@"enum"; + const field_names = .{"default"} ++ ofmt_info.field_names; + const TagInt = std.math.IntFittingRange(0, field_names.len - 1); + var field_values: [field_names.len]TagInt = undefined; + field_values[0] = field_names.len - 1; + for (field_values[1..], ofmt_info.field_values) |*field_value, value| field_value.* = value; + break :ObjectFormat @Enum(TagInt, .exhaustive, field_names, &field_values); + }; + + pub const DynamicLinker = union(enum) { + default, + none, + explicit: []const u8, + }; + + pub fn toQuery(target: *const Target) std.Target.Query { + var query: std.Target.Query = .{}; + query.cpu_arch = switch (target.cpu) { + .native => null, + else => |_, arch| @fromBackingInt(@backingInt(arch)), + }; + switch (target.cpu) { + .native => |native| query.cpu_model = switch (native.model) { + .native => .native, + .baseline => .baseline, + }, + inline else => |cpu| cpu.updateQuery(&query), + } + query.os_tag = switch (target.os) { + .native => null, + else => |_, os| @fromBackingInt(@backingInt(os)), + }; + switch (target.os) { + .native => {}, + inline else => |os| os.updateQuery(&query), + } + query.abi = switch (target.abi) { + .default => null, + else => |_, abi| @fromBackingInt(@backingInt(abi)), + }; + switch (target.abi) { + .default => {}, + inline else => |abi| abi.updateQuery(&query), + } + query.ofmt = switch (target.ofmt) { + .default => null, + else => |ofmt| @fromBackingInt(@backingInt(ofmt)), + }; + query.dynamic_linker = switch (target.dynamic_linker) { + .default => null, + .none => .none, + .explicit => |dynamic_linker| .init(dynamic_linker), + }; + return query; + } + + pub fn format(target: *const Target, w: *std.Io.Writer) std.Io.Writer.Error!void { + try w.print("{f}-{f}-{t}-{t}-{t}-{t}", .{ + std.fmt.alt(&target.toQuery(), .printZigTriple), + std.fmt.alt(&target.toQuery(), .printCpu), + target.cache_mode, + target.backend, + target.linker, + target.pic, + }); + } +}; + gpa: std.mem.Allocator, arena: *std.heap.ArenaAllocator, environ_map: std.process.Environ.Map, @@ -908,22 +1158,69 @@ fn handleCommand( return update.fail("target {q} unknown cache mode {q}", .{ update.target_query, cache_mode_str, }); - const triple = component_it.rest(); + const triple_cpu = component_it.rest(); + var triple_len: usize = 0; + for (0..3) |_| { + triple_len = if (std.mem.findScalarPos(u8, triple_cpu, triple_len, '-')) |dash_pos| + dash_pos + 1 + else + return update.fail("target {q} missing cpu", .{update.target_query}); + if (std.mem.eql(u8, triple_cpu[0..triple_len], "native-")) break; + } + const triple = triple_cpu[0 .. triple_len - 1]; + const cpu = triple_cpu[triple_len..]; + var query_parse_diags: std.Target.Query.ParseOptions.Diagnostics = undefined; break :target .{ .triple = triple, .resolved = std.zig.system.resolveTargetQuery( runner.io, - std.Build.parseTargetQuery(.{ + std.Target.Query.parse(.{ .arch_os_abi = triple, + .cpu_features = cpu, .object_format = switch (backend) { .sema, .selfhosted, .llvm => null, .llvmir => "llvmir", .cbe => "c", }, + .diagnostics = &query_parse_diags, }) catch |err| switch (err) { - error.ParseFailed => return update.fail("unable to parse triple {q}", .{ - triple, - }), + error.UnknownArchitecture => return update.fail( + "unable to resolve target {q}: unknown architecture: {q}", + .{ update.target_query, query_parse_diags.unknown_architecture_name.? }, + ), + error.MissingOperatingSystem => return update.fail( + "unable to resolve target {q}: missing operating system", + .{update.target_query}, + ), + error.UnknownOperatingSystem => return update.fail( + "unable to resolve target {q}: unknown operating system: {q}", + .{ update.target_query, query_parse_diags.os_name.? }, + ), + error.InvalidOperatingSystemVersion => return update.fail( + "unable to resolve target {q}: invalid operating system version", + .{update.target_query}, + ), + error.UnknownApplicationBinaryInterface => return update.fail( + "unable to resolve target {q}: unknown abi", + .{update.target_query}, + ), + error.InvalidAbiVersion => return update.fail( + "unable to resolve target {q}: invalid abi version", + .{update.target_query}, + ), + error.UnexpectedExtraField => unreachable, // validated above + error.UnknownCpuModel => return update.fail( + "unable to resolve target {q}: unknown cpu: {q}", + .{ update.target_query, query_parse_diags.cpu_name.? }, + ), + error.UnknownCpuFeature => return update.fail( + "unable to resolve target {q}: unknown cpu feature: {q}", + .{ update.target_query, query_parse_diags.unknown_feature_name.? }, + ), + error.UnknownObjectFormat => return update.fail( + "unable to resolve target {q}: unknown object format", + .{update.target_query}, + ), }, ) catch |err| switch (err) { error.Canceled => |e| return e, @@ -1265,7 +1562,7 @@ const Compiler = struct { mr_buffer: std.Io.File.MultiReader.Buffer(2), mr: std.Io.File.MultiReader, client: std.zig.Client, - target: Target, + target: Compiler.Target, out_name: []const u8, config: ?std.zig.Server.Message.Config, diff --git a/test/cases.zig b/test/cases.zig index 834855099ed17dd16b981c22c01935bd460a7906..573a10764e5530319655a46fa3f7ec5a8c319af4 100644 --- a/test/cases.zig +++ b/test/cases.zig @@ -9,7 +9,6 @@ pub const BuildOptions = struct { llvm_has_xtensa: bool, }; -pub fn addCases(cases: *Cases, build_options: BuildOptions, b: *std.Build) !void { +pub fn addCases(cases: *Cases, b: *std.Build) !void { try @import("compile_errors.zig").addCases(cases, b); - try @import("llvm_targets.zig").addCases(cases, build_options, b); } diff --git a/test/debugger/enums b/test/debugger/enums index dfd6375be0cdad75c30e4c0f41ba1ad9ce87adcb..10888bfe4ee60a51d7b04d3719c97c71f1dfa42a 100644 --- a/test/debugger/enums +++ b/test/debugger/enums @@ -1,8 +1,8 @@ #todo "passes, but prints errors" -#skip x86_64-linux-none-whole-selfhosted-new-nopic -#skip x86_64-linux-none-whole-selfhosted-new-pic -#skip x86_64-linux-none-incremental-selfhosted-new-nopic -#skip x86_64-linux-none-incremental-selfhosted-new-pic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic #exe { --name enums diff --git a/test/debugger/errors b/test/debugger/errors index 8a8143330ac40d161c7c2f229a6deeb263c6bc66..4d8eadbd4098275511016d87a7d6705264f973eb 100644 --- a/test/debugger/errors +++ b/test/debugger/errors @@ -1,8 +1,8 @@ #todo "passes, but prints errors" -#skip x86_64-linux-none-whole-selfhosted-new-nopic -#skip x86_64-linux-none-whole-selfhosted-new-pic -#skip x86_64-linux-none-incremental-selfhosted-new-nopic -#skip x86_64-linux-none-incremental-selfhosted-new-pic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic #exe { --name errors diff --git a/test/debugger/inline_call/manifest b/test/debugger/inline_call/manifest index f23cf902c8e1da1a5b670744003ae295b4283a01..ba99272bea5103cb01277ea4a4903a798487a24e 100644 --- a/test/debugger/inline_call/manifest +++ b/test/debugger/inline_call/manifest @@ -1,6 +1,6 @@ #todo "implement inline line info in lldb" -#skip x86_64-linux-none-incremental-selfhosted-new-nopic -#skip x86_64-linux-none-incremental-selfhosted-new-pic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic #exe { --name inline_call diff --git a/test/debugger/matrix.zon b/test/debugger/matrix.zon index a3b36d803468d510b7a6af7c64c90efb3e37060b..fb9bc41d4ba88ae453950a6fe5b21ba4efae67e2 100644 --- a/test/debugger/matrix.zon +++ b/test/debugger/matrix.zon @@ -1,65 +1,53 @@ .{ .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .selfhosted, .linker = .old, .pic = .nopic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .selfhosted, .linker = .old, .pic = .pic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .selfhosted, .linker = .new, .pic = .nopic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .selfhosted, .linker = .new, .pic = .pic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .selfhosted, .linker = .new, .pic = .nopic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .selfhosted, .linker = .new, diff --git a/test/debugger/unions b/test/debugger/unions index 786ba275cbf92d418ac4db98301ed24c3214217b..f999ee37135bcfcf027bcd1573b4d322a2fb12c3 100644 --- a/test/debugger/unions +++ b/test/debugger/unions @@ -1,8 +1,8 @@ #todo "passes, but prints errors" -#skip x86_64-linux-none-whole-selfhosted-new-nopic -#skip x86_64-linux-none-whole-selfhosted-new-pic -#skip x86_64-linux-none-incremental-selfhosted-new-nopic -#skip x86_64-linux-none-incremental-selfhosted-new-pic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic +#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic #exe { --name unions diff --git a/test/incremental/matrix.zon b/test/incremental/matrix.zon index 7c239ec719c4d5d5ccaf2b0e96cc305633f7d38f..2f62c48bdbd44b68ab91628bd187e2321d3f2518 100644 --- a/test/incremental/matrix.zon +++ b/test/incremental/matrix.zon @@ -3,22 +3,18 @@ // to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang // or LLVM). We just have a couple here to make sure that it works. .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .musl, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .musl = .{} }, .cache_mode = .incremental, .backend = .cbe, .linker = .old, .pic = .nopic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .llvm, .linker = .lld, @@ -26,33 +22,27 @@ }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .linux, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .linux = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .selfhosted, .linker = .new, .pic = .nopic, }, .{ - .target = .{ - .cpu_arch = .x86_64, - .os_tag = .windows, - .abi = .none, - }, + .cpu = .{ .x86_64 = .{} }, + .os = .{ .windows = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .selfhosted, .linker = .old, .pic = .pic, }, .{ - .target = .{ - .cpu_arch = .wasm32, - .os_tag = .wasi, - .abi = .none, - }, + .cpu = .{ .wasm32 = .{} }, + .os = .{ .wasi = .{} }, + .abi = .{ .none = .{} }, .cache_mode = .incremental, .backend = .selfhosted, .linker = .old, diff --git a/test/llvm-ir/matrix.zon b/test/llvm-ir/matrix.zon index 681e7f7c3a925f928804bb598be3b52a5fabad59..4c810d784d3a445f913defa190d1c6e55a230b38 100644 --- a/test/llvm-ir/matrix.zon +++ b/test/llvm-ir/matrix.zon @@ -1,6 +1,5 @@ .{ .{ - .target = .{}, .cache_mode = .whole, .backend = .llvmir, .linker = .old, diff --git a/test/llvm-targets/empty_analyze b/test/llvm-targets/empty_analyze new file mode 100644 index 0000000000000000000000000000000000000000..c6fdbea1129cc1a7ec6107a812a899d99d46817a --- /dev/null +++ b/test/llvm-targets/empty_analyze @@ -0,0 +1,50 @@ +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic +#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic + +#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic +#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-eabi-baseline-whole-llvm-lld-pic +#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic + +#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic + +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic + +#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic + +#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#obj { +--name llvm_targets +-Mroot=analyze.zig +-fno-emit-asm -fno-emit-bin +#} + +#write analyze.zig +#update +#check errors diff --git a/test/llvm-targets/empty_assembly b/test/llvm-targets/empty_assembly new file mode 100644 index 0000000000000000000000000000000000000000..e140e4f6fcfa0108147f877626e267311203dbd6 --- /dev/null +++ b/test/llvm-targets/empty_assembly @@ -0,0 +1,55 @@ +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic +#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic + +#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic +#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-eabi-baseline-whole-llvm-lld-pic +#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic + +#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic + +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic + +#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic + +#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip xtensa-freestanding-call0-baseline-whole-llvm-lld-pic +#skip xtensa-freestanding-none-baseline-whole-llvm-lld-pic +#skip xtensa-linux-call0-baseline-whole-llvm-lld-pic +#skip xtensa-linux-none-baseline-whole-llvm-lld-pic + +#obj { +--name llvm_targets +-Mroot=assembly.zig +-femit-asm -fno-emit-bin +#} + +#write assembly.zig +#update +#check errors diff --git a/test/llvm-targets/empty_object b/test/llvm-targets/empty_object new file mode 100644 index 0000000000000000000000000000000000000000..6d52ba2d3a9ee515e453f9d13b7bdb1249615391 --- /dev/null +++ b/test/llvm-targets/empty_object @@ -0,0 +1,67 @@ +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip arc-freestanding-none-baseline-whole-llvm-lld-pic +#skip arc-linux-gnu-baseline-whole-llvm-lld-pic +#skip arc-linux-none-baseline-whole-llvm-lld-pic + +#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic +#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic + +#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic +#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-eabi-baseline-whole-llvm-lld-pic +#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic +#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic + +#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic + +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic + +#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip xcore-freestanding-none-baseline-whole-llvm-lld-pic + +#skip xtensa-freestanding-call0-baseline-whole-llvm-lld-pic +#skip xtensa-freestanding-none-baseline-whole-llvm-lld-pic +#skip xtensa-linux-call0-baseline-whole-llvm-lld-pic +#skip xtensa-linux-none-baseline-whole-llvm-lld-pic + +#obj { +--name llvm_targets +-Mroot=object.zig +-fno-emit-asm -femit-bin +#} + +#write object.zig +#update +#check errors diff --git a/test/llvm-targets/matrix.zon b/test/llvm-targets/matrix.zon new file mode 100644 index 0000000000000000000000000000000000000000..a3ec7955d459ec1a2493db0a647731bf488b2eca --- /dev/null +++ b/test/llvm-targets/matrix.zon @@ -0,0 +1,355 @@ +.{ + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .driverkit = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .ios = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .ios = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .maccatalyst = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .macos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .@"switch" = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .tvos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .tvos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .visionos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .visionos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .ilp32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .amdhsa = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .amdpal = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .mesa3d = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .arc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .arm = .{} }, .os = .{ .@"3ds" = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .gba = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .androideabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohoseabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .arm = .{} }, .os = .{ .vita = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .armeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .armeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .avr = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .avr = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .bpfeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .bpfel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .csky = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .csky = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .hexagon = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .hexagon = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .hexagon = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .lanai = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnusf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslsf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnusf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslsf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .m68k = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .m68k = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .m68k = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .mips = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .psx = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .psp = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mipsel = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .abin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .abin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .mips64el = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .msp430 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .nvptx = .{} }, .os = .{ .cuda = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .nvptx = .{} }, .os = .{ .nvcl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .nvptx64 = .{} }, .os = .{ .cuda = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .nvptx64 = .{} }, .os = .{ .nvcl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc = .{} }, .os = .{ .wiiu = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .powerpcle = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpcle = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .ps3 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .riscv32be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .riscv64be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .s390x = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .sparc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opencl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opengl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .vulkan = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .amdhsa = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .opencl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .vulkan = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .thumb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .gba = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .vita = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .ve = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .ve = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .emscripten = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .wasi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .emscripten = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .wasi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .x86 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{ .features = .{ .add = .{.soft_float}, .remove = .{ .mmx, .sse, .sse2, .avx, .avx2 } } } }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .dragonfly = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .driverkit = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnux32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslx32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .x32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .maccatalyst = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .macos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps4 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps5 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .xcore = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + + .{ .cpu = .{ .xtensa = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .call0 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .xtensa = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .xtensa = .{} }, .os = .{ .linux = .{} }, .abi = .{ .call0 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .xtensa = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, +} diff --git a/test/llvm_targets.zig b/test/llvm_targets.zig deleted file mode 100644 index 0c758566fe37fc1af4862620f36dda3d17a9dc0d..0000000000000000000000000000000000000000 --- a/test/llvm_targets.zig +++ /dev/null @@ -1,382 +0,0 @@ -const std = @import("std"); -const Cases = @import("src/Cases.zig"); - -const targets = [_]std.Target.Query{ - .{ .cpu_arch = .aarch64, .os_tag = .driverkit, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .freebsd, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .fuchsia, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .haiku, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .hurd, .abi = .gnu }, - .{ .cpu_arch = .aarch64, .os_tag = .ios, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .ios, .abi = .simulator }, - .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .android }, - .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .ohos }, - .{ .cpu_arch = .aarch64, .os_tag = .maccatalyst, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .rtems, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .serenity, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .@"switch", .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .tvos, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .tvos, .abi = .simulator }, - .{ .cpu_arch = .aarch64, .os_tag = .uefi, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .visionos, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .visionos, .abi = .simulator }, - .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .ilp32 }, - .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .none }, - .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .simulator }, - .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .gnu }, - .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .itanium }, - .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .msvc }, - - .{ .cpu_arch = .aarch64_be, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .aarch64_be, .os_tag = .netbsd, .abi = .none }, - - .{ .cpu_arch = .amdgcn, .os_tag = .amdhsa, .abi = .none }, - // .{ .cpu_arch = .amdgcn, .os_tag = .amdpal, .abi = .none }, - // .{ .cpu_arch = .amdgcn, .os_tag = .mesa3d, .abi = .none }, - - .{ .cpu_arch = .arc, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .arc, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .arc, .os_tag = .linux, .abi = .none }, - - .{ .cpu_arch = .arm, .os_tag = .@"3ds", .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .freebsd, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .fuchsia, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .gba, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .haiku, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .androideabi }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .gnueabi }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .gnueabihf }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .ohoseabi }, - .{ .cpu_arch = .arm, .os_tag = .netbsd, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .netbsd, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .openbsd, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .arm, .os_tag = .rtems, .abi = .eabihf }, - // .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .eabi }, - // .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .eabihf }, - .{ .cpu_arch = .arm, .os_tag = .vita, .abi = .eabihf }, - - .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .gnueabi }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .gnueabihf }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .armeb, .os_tag = .netbsd, .abi = .eabi }, - .{ .cpu_arch = .armeb, .os_tag = .netbsd, .abi = .eabihf }, - .{ .cpu_arch = .armeb, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .armeb, .os_tag = .rtems, .abi = .eabihf }, - - .{ .cpu_arch = .avr, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .avr, .os_tag = .rtems, .abi = .none }, - - .{ .cpu_arch = .bpfeb, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .bpfel, .os_tag = .freestanding, .abi = .none }, - - // .{ .cpu_arch = .csky, .os_tag = .freestanding, .abi = .eabi }, - // .{ .cpu_arch = .csky, .os_tag = .freestanding, .abi = .eabihf }, - // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .eabi }, - // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .eabihf }, - // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .gnueabi }, - // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .gnueabihf }, - - .{ .cpu_arch = .hexagon, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .none }, - - .{ .cpu_arch = .lanai, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .loongarch32, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnu }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnuf32 }, - .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnusf }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .musl }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslf32 }, - // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslsf }, - .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .none }, - // .{ .cpu_arch = .loongarch32, .os_tag = .uefi, .abi = .none }, - - .{ .cpu_arch = .loongarch64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnu }, - // .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnuf32 }, - .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnusf }, - .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .musl }, - // .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .muslf32 }, - .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .muslsf }, - .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .none }, - // .{ .cpu_arch = .loongarch64, .os_tag = .uefi, .abi = .none }, - - .{ .cpu_arch = .m68k, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .m68k, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .m68k, .os_tag = .rtems, .abi = .none }, - - .{ .cpu_arch = .mips, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .mips, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabi }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabihf }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .mips, .os_tag = .netbsd, .abi = .eabi }, - .{ .cpu_arch = .mips, .os_tag = .netbsd, .abi = .eabihf }, - .{ .cpu_arch = .mips, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .mips, .os_tag = .rtems, .abi = .eabihf }, - - .{ .cpu_arch = .mipsel, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .mipsel, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabi }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabihf }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabi }, - .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabihf }, - // .{ .cpu_arch = .mipsel, .os_tag = .psx, .abi = .eabi }, - .{ .cpu_arch = .mipsel, .os_tag = .psp, .abi = .eabihf }, - .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabihf }, - - .{ .cpu_arch = .mips64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .abin32 }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabi64 }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabin32 }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .muslabi64 }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .muslabin32 }, - .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .mips64, .os_tag = .openbsd, .abi = .none }, - - .{ .cpu_arch = .mips64el, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .abin32 }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabi64 }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabin32 }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .muslabi64 }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .muslabin32 }, - .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .mips64el, .os_tag = .openbsd, .abi = .none }, - - .{ .cpu_arch = .msp430, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .nvptx, .os_tag = .cuda, .abi = .none }, - .{ .cpu_arch = .nvptx, .os_tag = .nvcl, .abi = .none }, - - .{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none }, - .{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none }, - - .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .netbsd, .abi = .eabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .openbsd, .abi = .eabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabihf }, - .{ .cpu_arch = .powerpc, .os_tag = .wiiu, .abi = .eabihf }, - - .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf }, - - .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none }, - .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .powerpc64, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .powerpc64, .os_tag = .ps3, .abi = .ilp32 }, - .{ .cpu_arch = .powerpc64, .os_tag = .rtems, .abi = .none }, - - .{ .cpu_arch = .powerpc64le, .os_tag = .freebsd, .abi = .none }, - .{ .cpu_arch = .powerpc64le, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .none }, - - .{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .riscv32, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .riscv32, .os_tag = .rtems, .abi = .none }, - // .{ .cpu_arch = .riscv32, .os_tag = .uefi, .abi = .none }, - - // .{ .cpu_arch = .riscv32be, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .riscv64, .os_tag = .freebsd, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .fuchsia, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .haiku, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .hurd, .abi = .gnu }, - .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .android }, - .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .rtems, .abi = .none }, - .{ .cpu_arch = .riscv64, .os_tag = .serenity, .abi = .none }, - // .{ .cpu_arch = .riscv64, .os_tag = .uefi, .abi = .none }, - - // .{ .cpu_arch = .riscv64be, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .none }, - - .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .sparc, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .sparc, .os_tag = .rtems, .abi = .none }, - - .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .sparc64, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .sparc64, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .sparc64, .os_tag = .rtems, .abi = .none }, - - // .{ .cpu_arch = .spirv32, .os_tag = .opencl, .abi = .none }, - // .{ .cpu_arch = .spirv32, .os_tag = .opengl, .abi = .none }, - // .{ .cpu_arch = .spirv32, .os_tag = .vulkan, .abi = .none }, - // .{ .cpu_arch = .spirv64, .os_tag = .amdhsa, .abi = .none }, - // .{ .cpu_arch = .spirv64, .os_tag = .opencl, .abi = .none }, - // .{ .cpu_arch = .spirv64, .os_tag = .vulkan, .abi = .none }, - - .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .thumb, .os_tag = .fuchsia, .abi = .eabihf }, - .{ .cpu_arch = .thumb, .os_tag = .gba, .abi = .eabi }, - .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .thumb, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .thumb, .os_tag = .rtems, .abi = .eabihf }, - .{ .cpu_arch = .thumb, .os_tag = .vita, .abi = .eabihf }, - .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .gnu }, - .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .itanium }, - .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .msvc }, - - .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .eabi }, - .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .eabihf }, - .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .eabi }, - .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .eabihf }, - .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .musleabi }, - .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .musleabihf }, - .{ .cpu_arch = .thumbeb, .os_tag = .rtems, .abi = .eabi }, - .{ .cpu_arch = .thumbeb, .os_tag = .rtems, .abi = .eabihf }, - - .{ .cpu_arch = .ve, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .ve, .os_tag = .linux, .abi = .none }, - - .{ .cpu_arch = .wasm32, .os_tag = .emscripten, .abi = .none }, - .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .wasm32, .os_tag = .wasi, .abi = .none }, - - .{ .cpu_arch = .wasm64, .os_tag = .emscripten, .abi = .none }, - .{ .cpu_arch = .wasm64, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .wasm64, .os_tag = .wasi, .abi = .none }, - - .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .haiku, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .hurd, .abi = .gnu }, - .{ .cpu_arch = .x86, .os_tag = .illumos, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .android }, - .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .rtems, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none }, - .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu }, - .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .itanium }, - .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .msvc }, - - .{ .cpu_arch = .x86_64, .os_tag = .freebsd, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none }, - .{ - .cpu_arch = .x86_64, - .os_tag = .freestanding, - .abi = .none, - .cpu_features_add = std.Target.x86.featureSet(&.{.soft_float}), - .cpu_features_sub = std.Target.x86.featureSet(&.{ .mmx, .sse, .sse2, .avx, .avx2 }), - }, - .{ .cpu_arch = .x86_64, .os_tag = .fuchsia, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .dragonfly, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .driverkit, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .haiku, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .hurd, .abi = .gnu }, - .{ .cpu_arch = .x86_64, .os_tag = .illumos, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .android }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnux32 }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .muslx32 }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .ohos }, - .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .x32 }, - .{ .cpu_arch = .x86_64, .os_tag = .maccatalyst, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .netbsd, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .openbsd, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .ps4, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .ps5, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .rtems, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .serenity, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .uefi, .abi = .none }, - .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu }, - .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .itanium }, - .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .msvc }, - - .{ .cpu_arch = .xcore, .os_tag = .freestanding, .abi = .none }, - - .{ .cpu_arch = .xtensa, .os_tag = .freestanding, .abi = .call0 }, - .{ .cpu_arch = .xtensa, .os_tag = .freestanding, .abi = .none }, - .{ .cpu_arch = .xtensa, .os_tag = .linux, .abi = .call0 }, - .{ .cpu_arch = .xtensa, .os_tag = .linux, .abi = .none }, -}; - -pub fn addCases( - ctx: *Cases, - build_options: @import("cases.zig").BuildOptions, - b: *std.Build, -) !void { - if (!build_options.enable_llvm) return; - for (targets) |target_query| { - if (target_query.cpu_arch) |arch| switch (arch) { - .m68k => if (!build_options.llvm_has_m68k) continue, - .csky => if (!build_options.llvm_has_csky) continue, - .arc => if (!build_options.llvm_has_arc) continue, - .xtensa => if (!build_options.llvm_has_xtensa) continue, - else => {}, - }; - var case = ctx.addObjLlvm("llvm_targets", b.resolveTargetQuery(target_query)); - case.addCompile(""); - } -} diff --git a/test/src/Cases.zig b/test/src/Cases.zig index c6036823d92ffd09d752de600a25a354229a0de8..ac367a5813f9d644617aaa0c22259307105144c3 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -164,38 +164,6 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target_query: std.Target. return &ctx.cases.items[ctx.cases.items.len - 1]; } -pub fn addObjLlvm(ctx: *Cases, name: []const u8, target: std.Build.ResolvedTarget) *Case { - const can_emit_asm = switch (target.result.cpu.arch) { - .csky, - .xtensa, - => false, - else => true, - }; - const can_emit_bin = switch (target.result.cpu.arch) { - .arc, - .csky, - .nvptx, - .nvptx64, - .xcore, - .xtensa, - => false, - else => true, - }; - - ctx.cases.append(.{ - .name = name, - .target = target, - .files = .init(ctx.arena), - .case = null, - .output_mode = .Obj, - .deps = std.array_list.Managed(DepModule).init(ctx.arena), - .backend = .llvm, - .emit_bin = can_emit_bin, - .emit_asm = can_emit_asm, - }) catch @panic("out of memory"); - return &ctx.cases.items[ctx.cases.items.len - 1]; -} - pub fn addObj( ctx: *Cases, name: []const u8, diff --git a/test/tests.zig b/test/tests.zig index eca020095684e3ee05feaf4ba093c8d0e1fc6bdd..3ed14aedd5f077e47896465829564134db178d7c 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2186,19 +2186,6 @@ const link_targets = blk: { }; }; -/// These are passed to `src/Runner.zig` as `----` strings. -/// -/// If only one specific test is failing on a target, instead of entirely disabling the target here, you -/// can skip the target for that specific test only by adding a line like this to top of the manifest: -/// #skip x86_64-linux-selfhosted -const RunnerTarget = struct { - target: std.Target.Query, - cache_mode: enum { whole, incremental }, - backend: enum { selfhosted, llvm, llvmir, cbe }, - linker: enum { lld, old, new }, - pic: enum { nopic, pic, pie }, -}; - pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step { const step = b.step("test-stack-traces", "Run the stack trace tests"); @@ -3037,7 +3024,6 @@ pub fn addCases( b: *std.Build, parent_step: *Step, case_test_options: @import("src/Cases.zig").CaseTestOptions, - build_options: @import("cases.zig").BuildOptions, ) !void { const arena = b.allocator; const gpa = b.allocator; @@ -3051,7 +3037,7 @@ pub fn addCases( defer dir.close(io); cases.addFromDir(dir, "test/cases", b); - try @import("cases.zig").addCases(&cases, build_options, b); + try @import("cases.zig").addCases(&cases, b); cases.lowerToBuildSteps( b, @@ -3060,6 +3046,7 @@ pub fn addCases( ); } +pub const RunnerTarget = @import("Runner.zig").Target; pub const RunnerOptions = struct { test_filters: []const []const u8, test_target_filters: []const []const u8, @@ -3072,10 +3059,13 @@ pub const RunnerOptions = struct { skip_darwin: bool, skip_linux: bool, skip_llvm: bool, + llvm_has_m68k: bool, + llvm_has_csky: bool, + llvm_has_arc: bool, + llvm_has_xtensa: bool, gdb: ?[]const u8, lldb: ?[]const u8, }; - pub fn addRunnerTests( b: *std.Build, runner: *std.Build.Step.Compile, @@ -3119,7 +3109,7 @@ pub fn addRunnerTests( _ = run.addPrefixedOutputDirectoryArg("--src=", "src"); for (matrix) |test_target| { - const resolved_target = b.resolveTargetQuery(test_target.target); + const resolved_target = b.resolveTargetQuery(test_target.toQuery()); if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; @@ -3135,15 +3125,18 @@ pub fn addRunnerTests( if (options.skip_darwin and target.os.tag.isDarwin()) continue; if (options.skip_linux and target.os.tag == .linux) continue; - if (options.skip_llvm and test_target.backend == .llvm) continue; + if (test_target.backend == .llvm) { + if (options.skip_llvm) continue; + switch (target.cpu.arch) { + else => {}, + .m68k => if (!options.llvm_has_m68k) continue, + .csky => if (!options.llvm_has_csky) continue, + .arc => if (!options.llvm_has_arc) continue, + .xtensa => if (!options.llvm_has_xtensa) continue, + } + } - const target_str = b.fmt("{s}-{t}-{t}-{t}-{t}", .{ - resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"), - test_target.cache_mode, - test_target.backend, - test_target.linker, - test_target.pic, - }); + const target_str = b.fmt("{f}", .{test_target}); for (options.test_target_filters) |filter| { if (std.mem.find(u8, target_str, filter) != null) break; -- 2.54.0 From 6148ec9f438e38c94ce95d5802103c7c078acff0 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 19 Oct 2026 19:07:00 -0400 Subject: [PATCH 9/9] test/llvm: combine `test-llvm-ir` and `test-llvm-targets` The IR tests should be run on the same target matrix anyway. --- build.zig | 10 +- lib/compiler/Maker/Step/Run.zig | 8 +- src/main.zig | 2 +- test/Runner.zig | 245 ++++++++++++--------- test/llvm-ir/array_to_vector | 38 ---- test/llvm-ir/dead_store | 43 ---- test/llvm-ir/load_store_bool | 28 --- test/llvm-ir/matrix.zon | 8 - test/llvm-ir/nonnull | 30 --- test/{llvm-ir => llvm}/allowzero | 28 ++- test/llvm/array_to_vector | 109 +++++++++ test/llvm/dead_store | 65 ++++++ test/{llvm-targets => llvm}/empty_analyze | 6 +- test/{llvm-targets => llvm}/empty_assembly | 6 +- test/{llvm-targets => llvm}/empty_object | 6 +- test/llvm/load_store_bool | 95 ++++++++ test/{llvm-targets => llvm}/matrix.zon | 56 ++--- test/llvm/nonnull | 44 ++++ test/{llvm-ir => llvm}/unused_load | 32 ++- 19 files changed, 565 insertions(+), 294 deletions(-) delete mode 100644 test/llvm-ir/array_to_vector delete mode 100644 test/llvm-ir/dead_store delete mode 100644 test/llvm-ir/load_store_bool delete mode 100644 test/llvm-ir/matrix.zon delete mode 100644 test/llvm-ir/nonnull rename test/{llvm-ir => llvm}/allowzero (55%) create mode 100644 test/llvm/array_to_vector create mode 100644 test/llvm/dead_store rename test/{llvm-targets => llvm}/empty_analyze (96%) rename test/{llvm-targets => llvm}/empty_assembly (96%) rename test/{llvm-targets => llvm}/empty_object (97%) create mode 100644 test/llvm/load_store_bool rename test/{llvm-targets => llvm}/matrix.zon (98%) create mode 100644 test/llvm/nonnull rename test/{llvm-ir => llvm}/unused_load (51%) diff --git a/build.zig b/build.zig index 985418a1389f8aa1bd131e3d338d88afa8600943..ed8b16da95710fd2d401cc9fc0c59c08b3462369 100644 --- a/build.zig +++ b/build.zig @@ -816,13 +816,9 @@ pub fn build(b: *std.Build) !void { try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts); test_step.dependOn(test_incremental_step); - const test_llvm_ir_step = b.step("test-llvm-ir", "Run the LLVM IR tests"); - try tests.addRunnerTests(b, runner, test_llvm_ir_step, "test/llvm-ir", @import("test/llvm-ir/matrix.zon"), runner_opts); - test_step.dependOn(test_llvm_ir_step); - - const test_llvm_targets_step = b.step("test-llvm-targets", "Run the LLVM targets tests"); - try tests.addRunnerTests(b, runner, test_llvm_targets_step, "test/llvm-targets", @import("test/llvm-targets/matrix.zon"), runner_opts); - test_step.dependOn(test_llvm_targets_step); + const test_llvm_step = b.step("test-llvm", "Run the LLVM IR tests"); + try tests.addRunnerTests(b, runner, test_llvm_step, "test/llvm", @import("test/llvm/matrix.zon"), runner_opts); + test_step.dependOn(test_llvm_step); } fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void { diff --git a/lib/compiler/Maker/Step/Run.zig b/lib/compiler/Maker/Step/Run.zig index 73b36d1ec7ad1b592cce4ac4716193c5ac5249b5..ed55273d560d5f92f73488c7ced019414a85ac13 100644 --- a/lib/compiler/Maker/Step/Run.zig +++ b/lib/compiler/Maker/Step/Run.zig @@ -795,6 +795,7 @@ fn waitZigTest( multi_reader: *Io.File.MultiReader, opt_metadata: *?TestMetadata, results: *Step.TestResults, + eb_wip: *std.zig.ErrorBundle.Wip, ) !union(enum) { write_failed: anyerror, no_poll: struct { @@ -885,7 +886,7 @@ fn waitZigTest( .{ builtin.zig_version_string, body }, ); }, - .error_bundle => step.result_error_bundle = try std.zig.Server.allocErrorBundle(gpa, body), + .error_bundle => try eb_wip.addBundleAsRoots(try std.zig.Server.allocErrorBundle(arena, body)), .test_metadata => { // `metadata` would only be populated if we'd already seen a `test_metadata`, but we // only request it once (and importantly, we don't re-request it if we kill and @@ -1573,6 +1574,9 @@ fn evalZigTest( }; var test_metadata: ?TestMetadata = null; + var eb_wip: std.zig.ErrorBundle.Wip = try .init(gpa); + defer eb_wip.deinit(); + while (true) { var child = try process.spawn(io, spawn_options); var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; @@ -1602,6 +1606,7 @@ fn evalZigTest( &multi_reader, &test_metadata, &test_results, + &eb_wip, )) { .write_failed => |err| { // The runner unexpectedly closed a stdio pipe, which means a crash. Make sure we've captured @@ -1687,6 +1692,7 @@ fn evalZigTest( } } } + step.result_error_bundle = try eb_wip.toOwnedBundle(""); return; }, .timeout => |timeout| { diff --git a/src/main.zig b/src/main.zig index 77a53032b45b49d1ee726244866ca2f2f117a27a..49838feb8beb6de697b763fc6852054050033a6e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3368,7 +3368,7 @@ fn buildOutputType( const target = &main_mod.resolved_target.result; if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) { - if (emit_bin != .no and create_module.resolved_options.use_llvm) { + if (emit_bin != .no and target.ofmt != .llvmbc and target.ofmt != .llvmir and create_module.resolved_options.use_llvm) { fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{ @tagName(target.cpu.arch), }); diff --git a/test/Runner.zig b/test/Runner.zig index 858809125745c16e9f9ccc17b7c8f4d2bc245130..1d838172a23bc9e182529cb6d37305def72f4c90 100644 --- a/test/Runner.zig +++ b/test/Runner.zig @@ -17,7 +17,7 @@ pub const Target = struct { dynamic_linker: DynamicLinker = .default, cache_mode: enum { whole, incremental }, - backend: enum { selfhosted, llvm, llvmir, cbe }, + backend: enum { selfhosted, llvm, cbe }, linker: enum { lld, old, new }, pic: enum { nopic, pic, pie }, @@ -942,6 +942,7 @@ fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestEr }; defer { update.manifest_sr.deinit(); + if (update.compiler) |*comp| comp.deinit(); update.src_dir.close(runner.io); update.prog_node.end(); } @@ -1161,11 +1162,12 @@ fn handleCommand( const triple_cpu = component_it.rest(); var triple_len: usize = 0; for (0..3) |_| { + const component_start = triple_len; triple_len = if (std.mem.findScalarPos(u8, triple_cpu, triple_len, '-')) |dash_pos| dash_pos + 1 else return update.fail("target {q} missing cpu", .{update.target_query}); - if (std.mem.eql(u8, triple_cpu[0..triple_len], "native-")) break; + if (std.mem.eql(u8, triple_cpu[component_start..triple_len], "native-")) break; } const triple = triple_cpu[0 .. triple_len - 1]; const cpu = triple_cpu[triple_len..]; @@ -1179,7 +1181,6 @@ fn handleCommand( .cpu_features = cpu, .object_format = switch (backend) { .sema, .selfhosted, .llvm => null, - .llvmir => "llvmir", .cbe => "c", }, .diagnostics = &query_parse_diags, @@ -1393,7 +1394,6 @@ fn handleCommand( } else return update.fail("unexpected stderr:\n{s}", .{stderr_buffered}); } - try comp.exit(); return update.fail("compiler failed to send terminating error_bundle", .{}); }, } @@ -1417,9 +1417,27 @@ fn spawnCompiler( const gpa = runner.gpa; const arena = runner.arena.allocator(); if (compiler.*) |*comp| { - try comp.exit(); + comp.deinit(); compiler.* = null; } + errdefer compiler.* = null; + + compiler.* = .{ + .runner = runner, + .allow_compiler_stderr = true, + .output_mode = output_mode, + .state = .idle, + .child = undefined, + .fw = undefined, + .mr_buffer = undefined, + .mr = undefined, + .client = undefined, + .target = target, + .emit_name = null, + .prog_node = .none, + .config = null, + }; + const comp = &compiler.*.?; var argv: std.ArrayList([]const u8) = .empty; defer argv.deinit(gpa); @@ -1431,20 +1449,19 @@ fn spawnCompiler( .Lib => "build-lib", }, "-target", - target.triple, + comp.target.triple, "--cache-dir", ".zig-cache", }); - switch (target.cache_mode) { + switch (comp.target.cache_mode) { .whole => {}, .incremental => try argv.append(gpa, "-fincremental"), } var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; - if (target.backend) |b| switch (b) { + if (comp.target.backend) |b| switch (b) { .sema => try argv.append(gpa, "-fno-emit-bin"), .selfhosted => try argv.append(gpa, "-fno-llvm"), .llvm => try argv.append(gpa, "-fllvm"), - .llvmir => try argv.append(gpa, "-ofmt=llvmir"), .cbe => try argv.append(gpa, "-ofmt=c"), } else try argv.appendSlice(gpa, &.{ "-I", path_buffer[0 .. (runner.args.lib_dir orelse return runner.fail("\"--lib=path/to/lib\" arg required with cbe", .{})) @@ -1452,12 +1469,12 @@ fn spawnCompiler( error.Canceled => |e| return e, else => |e| return runner.fail("unable to get lib path: {t}", .{e}), }] }); - switch (target.linker) { + switch (comp.target.linker) { .lld => try argv.appendSlice(gpa, &.{ "-flld", "-fno-new-linker" }), .old => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fno-new-linker" }), .new => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fnew-linker" }), } - switch (target.pic) { + switch (comp.target.pic) { .nopic => try argv.appendSlice(gpa, &.{ "-fno-PIC", "-fno-PIE" }), .pic => try argv.appendSlice(gpa, &.{ "-fPIC", "-fno-PIE" }), .pie => try argv.appendSlice(gpa, &.{ "-fPIC", "-fPIE" }), @@ -1466,6 +1483,7 @@ fn spawnCompiler( var need: usize = 1; var state: enum { positional, @"--name" } = .positional; var root_name: ?[]const u8 = null; + var emit: ?std.zig.EmitArtifact = .bin; while (true) { const done = if (args_r.fill(need)) false else |err| switch (err) { error.ReadFailed => |e| return e, @@ -1479,10 +1497,42 @@ fn spawnCompiler( switch (state) { .positional => if (std.mem.eql(u8, arg, "--name")) { state = .@"--name"; + } else if (std.mem.cutPrefix(u8, arg, "-ofmt=")) |ofmt| { + comp.target.resolved.ofmt = + std.meta.stringToEnum(std.Target.ObjectFormat, ofmt) orelse + return runner.fail("invalid object format {q}", .{ofmt}); } else if (std.mem.cutPrefix(u8, arg, "-M")) |module| { var module_name_it = std.mem.splitScalar(u8, module, '='); const module_name = module_name_it.next().?; root_name = root_name orelse module_name; + } else if (std.mem.eql(u8, arg, "-femit-asm")) { + emit = .@"asm"; + } else if (std.mem.eql(u8, arg, "-femit-bin")) { + emit = .bin; + } else if (std.mem.eql(u8, arg, "-femit-docs")) { + emit = .docs; + } else if (std.mem.eql(u8, arg, "-femit-h")) { + emit = .h; + } else if (std.mem.eql(u8, arg, "-femit-implib")) { + emit = .implib; + } else if (std.mem.eql(u8, arg, "-femit-llvm-bc")) { + emit = .llvm_bc; + } else if (std.mem.eql(u8, arg, "-femit-llvm-ir")) { + emit = .llvm_ir; + } else if (std.mem.eql(u8, arg, "-fno-emit-asm")) { + if (emit == .@"asm") emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-bin")) { + if (emit == .bin) emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-docs")) { + if (emit == .docs) emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-h")) { + if (emit == .h) emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-implib")) { + if (emit == .implib) emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-llvm-bc")) { + if (emit == .llvm_bc) emit = null; + } else if (std.mem.eql(u8, arg, "-fno-emit-llvm-ir")) { + if (emit == .llvm_ir) emit = null; }, .@"--name" => { root_name = arg; @@ -1500,27 +1550,27 @@ fn spawnCompiler( } try argv.append(gpa, "--listen=-"); - const out_name = try std.zig.EmitArtifact.bin.cacheName(arena, .{ + comp.emit_name = if (emit) |e| try e.cacheName(arena, .{ .root_name = root_name orelse "root", - .cpu_arch = target.resolved.cpu.arch, - .os_tag = target.resolved.os.tag, - .ofmt = target.resolved.ofmt, - .abi = target.resolved.abi, + .cpu_arch = comp.target.resolved.cpu.arch, + .os_tag = comp.target.resolved.os.tag, + .ofmt = comp.target.resolved.ofmt, + .abi = comp.target.resolved.abi, .output_mode = output_mode, - }); + }) else null; var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined; - const comp_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "compile {s}", .{ - out_name, + comp.prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "compile {s}", .{ + comp.emit_name orelse root_name orelse "root", }) catch &name_buffer, 0); - errdefer comp_prog_node.end(); + errdefer comp.prog_node.end(); - const child = std.process.spawn(runner.io, .{ + comp.child = std.process.spawn(runner.io, .{ .exe = .{ .file = runner.args.zig_exe orelse return runner.fail("missing \"--zig=path/to/zig\" arg", .{}) }, .argv = argv.items, .cwd = .{ .dir = src_dir }, - .progress_node = comp_prog_node, + .progress_node = comp.prog_node, .stdin = .pipe, .stdout = .pipe, .stderr = .pipe, @@ -1529,31 +1579,14 @@ fn spawnCompiler( error.OperationUnsupported => return error.SkipTest, else => |e| return runner.fail("unable to spawn compiler: {t}", .{e}), }; - compiler.* = .{ - .runner = runner, - .prog_node = comp_prog_node, - .allow_compiler_stderr = true, - .output_mode = output_mode, - .state = .idle, - .child = child, - .fw = undefined, - .mr_buffer = undefined, - .mr = undefined, - .client = undefined, - .target = target, - .out_name = out_name, - .config = null, - }; - const comp = &compiler.*.?; - comp.fw = child.stdin.?.writerStreaming(runner.io, &.{}); + comp.fw = comp.child.stdin.?.writerStreaming(runner.io, &.{}); comp.mr.init(gpa, runner.io, comp.mr_buffer.toStreams(), &.{ - child.stdout.?, child.stderr.?, + comp.child.stdout.?, comp.child.stderr.?, }); comp.client = .{ .in = comp.mr.reader(0), .out = &comp.fw.interface }; } const Compiler = struct { runner: *Runner, - prog_node: std.Progress.Node, allow_compiler_stderr: bool, output_mode: std.lang.OutputMode, state: enum { idle, update }, @@ -1563,7 +1596,8 @@ const Compiler = struct { mr: std.Io.File.MultiReader, client: std.zig.Client, target: Compiler.Target, - out_name: []const u8, + emit_name: ?[]const u8, + prog_node: std.Progress.Node, config: ?std.zig.Server.Message.Config, const Target = struct { @@ -1586,8 +1620,6 @@ const Compiler = struct { /// Use the LLVM backend. /// Corresponds to `-fllvm -flld`. llvm, - /// Use the LLVM backend without libLLVM. - llvmir, /// Use the C backend. The output is compiled with `zig cc`. /// Corresponds to `-ofmt=c`. cbe, @@ -1598,6 +1630,12 @@ const Compiler = struct { const Pic = enum { nopic, pic, pie }; }; + fn deinit(comp: *Compiler) void { + comp.child.kill(comp.runner.io); + comp.prog_node.end(); + comp.prog_node = .none; + } + fn receiveMessage(comp: *Compiler) FailError!?struct { tag: std.zig.Server.Message.Tag, body: []const u8, @@ -1639,6 +1677,11 @@ const Compiler = struct { const arena = runner.arena.allocator(); const io = runner.io; const target = &comp.target.resolved; + const emit_name = switch (check) { + else => comp.emit_name orelse + return update.fail("unable to perform {t} check without emitted file", .{check}), + .errors => return, // expect no emitted file + }; const config = &comp.config.?; var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined; @@ -1655,14 +1698,49 @@ const Compiler = struct { }), }; - var argv: std.ArrayList([]const u8) = .initBuffer(try arena.alloc([]const u8, 5 + 4)); + const emit_path = emit_path: { + const emit_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ + "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*); + const emit_path = + try std.Io.Dir.path.join(arena, &.{ emit_dir_path, emit_name }); + break :emit_path switch (comp.target.backend.?) { + .sema => return, + .selfhosted, .llvm => emit_path, + .cbe => try comp.compileC(update.src_dir, emit_path), + }; + }; + + const emit_file = update.src_dir.openFile(io, emit_path, .{}) catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return update.fail("unable to open {q}: {t}", .{ emit_path, e }), + }; + defer emit_file.close(io); + + var argv: std.ArrayList([]const u8) = try .initCapacity(arena, 5 + 4); var environ_map: std.process.Environ.Map = .init(gpa); defer environ_map.deinit(); try environ_map.putAll(&runner.environ_map); var script_buffer: [512]u8 = undefined; const script_path, const script_file, var script_fw = script: switch (check) { - .errors => return, - .stdout, .exit, .llvm => .{ undefined, null, undefined }, + .errors => unreachable, + .stdout, .exit => .{ undefined, null, undefined }, + .llvm => { + var emit_fr = emit_file.reader(io, &.{}); + const actual = emit_fr.interface.readAllocAll(arena, @intCast( + emit_fr.getSize() catch |err| switch (err) { + error.Canceled => |e| return e, + else => |e| return runner.fail("unable to get size of {q}: {t}", .{ emit_path, e }), + }, + )) catch |err| switch (switch (err) { + error.OutOfMemory => |e| return e, + error.EndOfStream => |e| e, + error.ReadFailed => emit_fr.err.?, + }) { + error.Canceled => |e| return e, + else => |e| return runner.fail("unable to read {q}: {t}", .{ emit_path, e }), + }; + return update.checkMatches("LLVM IR", expected, actual); + }, .gdb => { const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb"; argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" }); @@ -1721,15 +1799,6 @@ const Compiler = struct { }; defer if (script_file) |file| file.close(io); - const out_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ - "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*); - const out_path = try std.Io.Dir.path.join(arena, &.{ out_dir_path, comp.out_name }); - const bin_path = switch (comp.target.backend.?) { - .sema => return, - .selfhosted, .llvm, .llvmir => out_path, - .cbe => try comp.compileC(update.src_dir, out_path), - }; - const need_cross_libc = target.os.tag == .linux and config.flags.link_libc and config.flags.link_mode == .dynamic; const use_executor = use_executor: switch (std.zig.system.getExternalExecutor(io, target, .{ @@ -1796,7 +1865,7 @@ const Compiler = struct { break :use_executor true; } else continue :use_executor .bad_os_or_cpu, }; - argv.appendAssumeCapacity(bin_path); + argv.appendAssumeCapacity(emit_path); if (!runner.args.quiet) std.log.info("{f}", .{std.zig.SubprocessCommand{ .argv = argv.items, @@ -1815,41 +1884,19 @@ const Compiler = struct { var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined; const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{ - comp.out_name, + emit_name, }) catch &name_buffer, 0); defer run_prog_node.end(); - const bin_file = update.src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) { - error.Canceled => |e| return e, - else => |e| return update.fail("unable to open {q}: {t}", .{ bin_path, e }), - }; - defer bin_file.close(io); const result = std.process.run(gpa, io, .{ .exe = exe: switch (check) { - .errors => unreachable, - .stdout, .exit => if (use_executor) .search else .{ .file = bin_file }, - .llvm => { - var bin_fr = bin_file.reader(io, &.{}); - const actual = bin_fr.interface.readAllocAll(arena, @intCast( - bin_fr.getSize() catch |err| switch (err) { - error.Canceled => |e| return e, - else => |e| return runner.fail("unable to get size of {q}: {t}", .{ bin_path, e }), - }, - )) catch |err| switch (switch (err) { - error.OutOfMemory => |e| return e, - error.EndOfStream => |e| e, - error.ReadFailed => bin_fr.err.?, - }) { - error.Canceled => |e| return e, - else => |e| return runner.fail("unable to read {q}: {t}", .{ bin_path, e }), - }; - return update.checkMatches("LLVM IR", expected, actual); - }, + .errors, .llvm => unreachable, + .stdout, .exit => if (use_executor) .search else .{ .file = emit_file }, .gdb, .lldb => { if (use_executor) { if (!runner.args.quiet) std.log.warn( "skipping debugging of {q} via executor for foreign target {q}", - .{ bin_path, comp.target.triple }, + .{ emit_path, comp.target.triple }, ); return; } @@ -1895,7 +1942,7 @@ const Compiler = struct { } orelse { if (!runner.args.quiet) std.log.warn( "skipping debugging of {q} because of missing \"--{t}=path/to/{[1]t}\" arg", - .{ bin_path, check }, + .{ emit_path, check }, ); return; } }; @@ -1909,11 +1956,11 @@ const Compiler = struct { // Chances are the foreign executor isn't available. Skip this evaluation. if (!runner.args.quiet) std.log.warn( "skipping execution of {q} via executor for foreign target {q}: {t}", - .{ bin_path, comp.target.triple, err }, + .{ emit_path, comp.target.triple, err }, ); return; } else return update.fail("unable to run the generated executable {q}: {t}", .{ - bin_path, err, + emit_path, err, }); defer { gpa.free(result.stdout); @@ -1925,7 +1972,7 @@ const Compiler = struct { .stdout => { if (code != 0) return update.fail( "generated executable {q} failed with code {d}", - .{ bin_path, code }, + .{ emit_path, code }, ); std.testing.expectEqualStrings( expected, @@ -1953,27 +2000,27 @@ const Compiler = struct { .gdb, .lldb => { if (code != debug_success) return update.fail( "debugging {q} failed with code {d}", - .{ bin_path, code }, + .{ emit_path, code }, ); try update.checkMatches("stdout", expected, result.stdout); }, }, .signal => |sig| return update.fail( "generated executable {q} terminated with signal {t}", - .{ bin_path, sig }, + .{ emit_path, sig }, ), .stopped => |sig| return update.fail( "generated executable {q} stopped with signal {t}", - .{ bin_path, sig }, + .{ emit_path, sig }, ), .unknown => return update.fail( "generated executable {q} terminated unexpectedly", - .{bin_path}, + .{emit_path}, ), } if (!use_executor and result.stderr.len > 0) { std.log.err("#update {q} generated executable {q} had unexpected stderr:\n{s}", .{ - update.name, bin_path, result.stderr, + update.name, emit_path, result.stderr, }); } } @@ -1999,6 +2046,7 @@ const Compiler = struct { error.ReadFailed => unreachable, // .fixed }; const comp = &compiler.?; + defer comp.deinit(); comp.client.serveBodylessMessage(.update) catch |err| switch (err) { error.WriteFailed => switch (comp.fw.err.?) { error.Canceled => |e| return e, @@ -2006,7 +2054,7 @@ const Compiler = struct { }, }; comp.state = .update; - var out_path: ?[]const u8 = null; + var emit_path: ?[]const u8 = null; while (try comp.receiveMessage()) |message| switch (message.tag) { else => {}, // Ignore other messages, .config => { @@ -2019,9 +2067,9 @@ const Compiler = struct { _ = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable; const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch unreachable; - const out_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ + const emit_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*); - out_path = try std.Io.Dir.path.join(arena, &.{ out_dir, comp.out_name }); + emit_path = try std.Io.Dir.path.join(arena, &.{ emit_dir, comp.emit_name.? }); }, .error_bundle => { const eb = std.zig.Server.allocErrorBundle( @@ -2040,7 +2088,7 @@ const Compiler = struct { }, }; try comp.exit(); - return out_path.?; + return emit_path.?; } fn exit(comp: *Compiler) FailError!void { @@ -2058,7 +2106,6 @@ const Compiler = struct { if (comp.client.in.bufferedLen() > 0) return runner.fail("unable to receive messages", .{}); const term = comp.child.wait(runner.io) catch |err| return runner.fail("child process failed: {t}", .{err}); - comp.prog_node.end(); switch (term) { .exited => |code| if (code != 0) return runner.fail("compiler failed with code {d}", .{code}), @@ -2309,8 +2356,8 @@ pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelabl }; } - var inherit_dirs: std.ArrayList(std.Io.Dir) = .initBuffer(try arena.alloc(std.Io.Dir, 3)); - var inherit_files: std.ArrayList(std.Io.File) = .initBuffer(try arena.alloc(std.Io.File, 4)); + var inherit_dirs: std.ArrayList(std.Io.Dir) = try .initCapacity(arena, 3); + var inherit_files: std.ArrayList(std.Io.File) = try .initCapacity(arena, 4); inherit_files.appendSliceAssumeCapacity(&.{ args.test_file, args.zig_exe }); inherit_dirs.appendSliceAssumeCapacity(&.{ args.lib_dir, args.src_dir }); if (args.libc_runtimes_dir) |libc_runtimes_dir| inherit_dirs.appendAssumeCapacity(libc_runtimes_dir); diff --git a/test/llvm-ir/array_to_vector b/test/llvm-ir/array_to_vector deleted file mode 100644 index ab182e1284306a69018581765d41d99d4e45e893..0000000000000000000000000000000000000000 --- a/test/llvm-ir/array_to_vector +++ /dev/null @@ -1,38 +0,0 @@ -#obj { ---name test --Mroot=test.zig -#} - -#write test.zig { -export fn entry(arr: *const [16]u8) @Vector(16, u8) { - return arr.*; -} -#} -#update "one vector load" -#check llvm { -define #...<16 x i8> @test.entry(#...) #...{ -#... - %1 = alloca [16 x i8], align 1#... - %3 = load <16 x i8>, ptr %1, align 1#... - ret <16 x i8> %3#... -#} - -#write test.zig { -export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void { - const q: @Vector(16, u8) = src[0..16].*; - a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 }); - b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 }); -} -#} -#update "feeding overlapping shuffles" -#check llvm { -define #...void @test.entry(ptr #...%0, ptr #...%1, #...) #...{ -#... - %11 = load <16 x i8>, ptr %#... - %12 = shufflevector <16 x i8> %11, #... - store <8 x i8> %12, ptr %0, align 8#... - %13 = shufflevector <16 x i8> %11, #... - store <8 x i8> %13, ptr %1, align 8#... - ret void#... -} -#} diff --git a/test/llvm-ir/dead_store b/test/llvm-ir/dead_store deleted file mode 100644 index 362b913db4c69597316b1d8bc3e0e82304ef6fc3..0000000000000000000000000000000000000000 --- a/test/llvm-ir/dead_store +++ /dev/null @@ -1,43 +0,0 @@ -#obj { ---name test --Mroot=test.zig -#} - -#write test.zig { -export fn entry(ptr: *volatile i16) void { - ptr.* = 123; - ptr.* = 321; -} -#} -#update "volatile" -#check llvm { -define #...@test.entry(ptr #...%0) #...{ -#...store volatile i16 123, ptr %0#... -#...store volatile i16 321, ptr %0#... -} - -#} - -#write test.zig { -export fn entry(ptr: *volatile i16) void { - entry2(ptr[0..1]); -} -fn entry2(slice: []volatile i16) void { - @setRuntimeSafety(false); - slice[0] = 123; - slice[0] = 321; -} -#} -#update "volatile slice" -#check llvm { -define #...@test.entry(#...) #...{ -#... -} - -#... -define #...@test.entry2(#...) #...{ -#...store volatile i16 123, ptr %#... -#...store volatile i16 321, ptr %#... -} - -#} diff --git a/test/llvm-ir/load_store_bool b/test/llvm-ir/load_store_bool deleted file mode 100644 index e38c45cfad468412e499a87dc42bbf9ae7844bc7..0000000000000000000000000000000000000000 --- a/test/llvm-ir/load_store_bool +++ /dev/null @@ -1,28 +0,0 @@ -#obj { ---name test --Mroot=test.zig -#} - -#write test.zig { -export fn foo(a: *bool, b: *align(2) bool) void { - const tmp = a.*; - a.* = b.*; - b.* = tmp; -} -#} -#update -#check llvm { -define #...void @test.foo(ptr #...%0, ptr #...%1) #...{ -#... - %5 = load i8, ptr %0, align 1#... - %6 = trunc nuw i8 %5 to i1#... - %8 = load i8, ptr %1, align 2#... - %9 = trunc nuw i8 %8 to i1#... - %10 = zext i1 %9 to i8#... - store i8 %10, ptr %0, align 1#... - %11 = zext i1 %6 to i8#... - store i8 %11, ptr %1, align 2#... - ret void#... -} - -#} diff --git a/test/llvm-ir/matrix.zon b/test/llvm-ir/matrix.zon deleted file mode 100644 index 4c810d784d3a445f913defa190d1c6e55a230b38..0000000000000000000000000000000000000000 --- a/test/llvm-ir/matrix.zon +++ /dev/null @@ -1,8 +0,0 @@ -.{ - .{ - .cache_mode = .whole, - .backend = .llvmir, - .linker = .old, - .pic = .pic, - }, -} diff --git a/test/llvm-ir/nonnull b/test/llvm-ir/nonnull deleted file mode 100644 index d3cb0546bdc83b6e3256d17ff0caed5f0a5232bd..0000000000000000000000000000000000000000 --- a/test/llvm-ir/nonnull +++ /dev/null @@ -1,30 +0,0 @@ -#obj { ---name test --Mroot=test.zig -#} - -#write test.zig { -export fn entry(ptr: *i16) i16 { - return ptr.*; -} -#} -#update "store" -#check llvm { -define #...@test.entry(ptr #...nonnull #...%0) #...{ -#...load i16, ptr %0#... -} - -#} - -#write test.zig { -export fn entry(ptr: *i16) void { - ptr.* = 42; -} -#} -#update "load" -#check llvm { -define #...@test.entry(ptr #...nonnull #...%0) #...{ -#...store i16 42, ptr %0#... -} - -#} diff --git a/test/llvm-ir/allowzero b/test/llvm/allowzero similarity index 55% rename from test/llvm-ir/allowzero rename to test/llvm/allowzero index e83cf1faf438b237f1d012a691d31998b4d437e3..3883eb84115c94f32695c11c4fec99d8924c3497 100644 --- a/test/llvm-ir/allowzero +++ b/test/llvm/allowzero @@ -1,5 +1,31 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic + +#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + #obj { ---name test +--name test -fno-lld -fno-new-linker -ofmt=llvmir -Mroot=test.zig #} diff --git a/test/llvm/array_to_vector b/test/llvm/array_to_vector new file mode 100644 index 0000000000000000000000000000000000000000..db4316af54b7fcd71b1f28fedd50aff961831252 --- /dev/null +++ b/test/llvm/array_to_vector @@ -0,0 +1,109 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic + +#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic + +#skip loongarch32-freestanding-none-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnu-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnusf-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-none-baseline-whole-llvm-lld-pic +#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic + +#skip loongarch64-freestanding-none-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnusf-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-none-baseline-whole-llvm-lld-pic +#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip riscv32-freestanding-none-baseline-whole-llvm-lld-pic +#skip riscv32-linux-gnu-baseline-whole-llvm-lld-pic +#skip riscv32-linux-musl-baseline-whole-llvm-lld-pic +#skip riscv32-linux-none-baseline-whole-llvm-lld-pic +#skip riscv32-netbsd-none-baseline-whole-llvm-lld-pic +#skip riscv32-rtems-none-baseline-whole-llvm-lld-pic +#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic +#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip riscv64-freebsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-freestanding-none-baseline-whole-llvm-lld-pic +#skip riscv64-fuchsia-none-baseline-whole-llvm-lld-pic +#skip riscv64-haiku-none-baseline-whole-llvm-lld-pic +#skip riscv64-hurd-gnu-baseline-whole-llvm-lld-pic +#skip riscv64-linux-android-baseline-whole-llvm-lld-pic +#skip riscv64-linux-gnu-baseline-whole-llvm-lld-pic +#skip riscv64-linux-musl-baseline-whole-llvm-lld-pic +#skip riscv64-linux-none-baseline-whole-llvm-lld-pic +#skip riscv64-netbsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-openbsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-rtems-none-baseline-whole-llvm-lld-pic +#skip riscv64-serenity-none-baseline-whole-llvm-lld-pic +#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic +#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + +#obj { +--name test -fno-lld -fno-new-linker -ofmt=llvmir +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(arr: *const [16]u8) @Vector(16, u8) { + return arr.*; +} +#} +#update "one vector load" +#check llvm { +define #...<16 x i8> @test.entry(#...) #...{ +#... + %1 = alloca [16 x i8], align 1#... + %3 = load <16 x i8>, ptr %1, align 1#... + ret <16 x i8> %3#... +#} + +#write test.zig { +export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void { + const q: @Vector(16, u8) = src[0..16].*; + a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 }); + b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 }); +} +#} +#update "feeding overlapping shuffles" +#check llvm { +define #...void @test.entry(ptr #...%0, ptr #...%1, #...) #...{ +#... + %11 = load <16 x i8>, ptr %#... + %12 = shufflevector <16 x i8> %11, #... + store <8 x i8> %12, ptr %0, align 8#... + %13 = shufflevector <16 x i8> %11, #... + store <8 x i8> %13, ptr %1, align 8#... + ret void#... +} +#} diff --git a/test/llvm/dead_store b/test/llvm/dead_store new file mode 100644 index 0000000000000000000000000000000000000000..ec59117ad730d0cdc64af2411ab2ac0275e6c287 --- /dev/null +++ b/test/llvm/dead_store @@ -0,0 +1,65 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + +#obj { +--name test -fno-lld -fno-new-linker -ofmt=llvmir +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + ptr.* = 123; + ptr.* = 321; +} +#} +#update "volatile" +#check llvm { +define #...@test.entry(ptr #...%0) #...{ +#...store volatile i16 123, ptr %0#... +#...store volatile i16 321, ptr %0#... +} + +#} + +#write test.zig { +export fn entry(ptr: *volatile i16) void { + entry2(ptr[0..1]); +} +fn entry2(slice: []volatile i16) void { + @setRuntimeSafety(false); + slice[0] = 123; + slice[0] = 321; +} +#} +#update "volatile slice" +#check llvm { +define #...@test.entry(#...) #...{ +#... +} + +#... +define #...@test.entry2(#...) #...{ +#...store volatile i16 123, ptr %#... +#...store volatile i16 321, ptr %#... +} + +#} diff --git a/test/llvm-targets/empty_analyze b/test/llvm/empty_analyze similarity index 96% rename from test/llvm-targets/empty_analyze rename to test/llvm/empty_analyze index c6fdbea1129cc1a7ec6107a812a899d99d46817a..83f8b9adfad2a1b79ec2adf06739cab3cee88900 100644 --- a/test/llvm-targets/empty_analyze +++ b/test/llvm/empty_analyze @@ -40,11 +40,11 @@ #skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic #obj { ---name llvm_targets --Mroot=analyze.zig +--name test +-Mroot=test.zig -fno-emit-asm -fno-emit-bin #} -#write analyze.zig +#write test.zig #update #check errors diff --git a/test/llvm-targets/empty_assembly b/test/llvm/empty_assembly similarity index 96% rename from test/llvm-targets/empty_assembly rename to test/llvm/empty_assembly index e140e4f6fcfa0108147f877626e267311203dbd6..30a58733d045c6e1c9c6af10fbf8aae192e75754 100644 --- a/test/llvm-targets/empty_assembly +++ b/test/llvm/empty_assembly @@ -45,11 +45,11 @@ #skip xtensa-linux-none-baseline-whole-llvm-lld-pic #obj { ---name llvm_targets --Mroot=assembly.zig +--name test +-Mroot=test.zig -femit-asm -fno-emit-bin #} -#write assembly.zig +#write test.zig #update #check errors diff --git a/test/llvm-targets/empty_object b/test/llvm/empty_object similarity index 97% rename from test/llvm-targets/empty_object rename to test/llvm/empty_object index 6d52ba2d3a9ee515e453f9d13b7bdb1249615391..b42e86be09bd48d78ae38accc26574b3403981ac 100644 --- a/test/llvm-targets/empty_object +++ b/test/llvm/empty_object @@ -57,11 +57,11 @@ #skip xtensa-linux-none-baseline-whole-llvm-lld-pic #obj { ---name llvm_targets --Mroot=object.zig +--name test +-Mroot=test.zig -fno-emit-asm -femit-bin #} -#write object.zig +#write test.zig #update #check errors diff --git a/test/llvm/load_store_bool b/test/llvm/load_store_bool new file mode 100644 index 0000000000000000000000000000000000000000..b59421e5cf1b3b31fa26570e02c83dedc30aaeac --- /dev/null +++ b/test/llvm/load_store_bool @@ -0,0 +1,95 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic + +#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic + +#skip loongarch32-freestanding-none-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnu-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-gnusf-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch32-linux-none-baseline-whole-llvm-lld-pic +#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic + +#skip loongarch64-freestanding-none-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-gnusf-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-musl-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-muslsf-baseline-whole-llvm-lld-pic +#skip loongarch64-linux-none-baseline-whole-llvm-lld-pic +#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip riscv32-freestanding-none-baseline-whole-llvm-lld-pic +#skip riscv32-linux-gnu-baseline-whole-llvm-lld-pic +#skip riscv32-linux-musl-baseline-whole-llvm-lld-pic +#skip riscv32-linux-none-baseline-whole-llvm-lld-pic +#skip riscv32-netbsd-none-baseline-whole-llvm-lld-pic +#skip riscv32-rtems-none-baseline-whole-llvm-lld-pic +#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip riscv64-freebsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-freestanding-none-baseline-whole-llvm-lld-pic +#skip riscv64-fuchsia-none-baseline-whole-llvm-lld-pic +#skip riscv64-haiku-none-baseline-whole-llvm-lld-pic +#skip riscv64-hurd-gnu-baseline-whole-llvm-lld-pic +#skip riscv64-linux-android-baseline-whole-llvm-lld-pic +#skip riscv64-linux-gnu-baseline-whole-llvm-lld-pic +#skip riscv64-linux-musl-baseline-whole-llvm-lld-pic +#skip riscv64-linux-none-baseline-whole-llvm-lld-pic +#skip riscv64-netbsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-openbsd-none-baseline-whole-llvm-lld-pic +#skip riscv64-rtems-none-baseline-whole-llvm-lld-pic +#skip riscv64-serenity-none-baseline-whole-llvm-lld-pic +#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic + +#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + +#obj { +--name test -fno-lld -fno-new-linker -ofmt=llvmir +-Mroot=test.zig +#} + +#write test.zig { +export fn foo(a: *bool, b: *align(2) bool) void { + const tmp = a.*; + a.* = b.*; + b.* = tmp; +} +#} +#update +#check llvm { +define #...void @test.foo(ptr #...%0, ptr #...%1) #...{ +#... + %5 = load i8, ptr %0, align 1#... + %6 = trunc nuw i8 %5 to i1#... + %8 = load i8, ptr %1, align 2#... + %9 = trunc nuw i8 %8 to i1#... + %10 = zext i1 %9 to i8#... + store i8 %10, ptr %0, align 1#... + %11 = zext i1 %6 to i8#... + store i8 %11, ptr %1, align 2#... + ret void#... +} + +#} diff --git a/test/llvm-targets/matrix.zon b/test/llvm/matrix.zon similarity index 98% rename from test/llvm-targets/matrix.zon rename to test/llvm/matrix.zon index a3ec7955d459ec1a2493db0a647731bf488b2eca..8dafd5efada10939b1ca29d4f9d16f166907b03c 100644 --- a/test/llvm-targets/matrix.zon +++ b/test/llvm/matrix.zon @@ -250,12 +250,12 @@ .{ .cpu = .{ .sparc = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, .{ .cpu = .{ .sparc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opencl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opengl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, @@ -316,31 +316,31 @@ .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{ .features = .{ .add = .{.soft_float}, .remove = .{ .mmx, .sse, .sse2, .avx, .avx2 } } } }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .dragonfly = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{ .features = .{ .add = .{.soft_float}, .remove = .{ .mmx, .sse, .sse2, .avx, .avx2 } } } }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .dragonfly = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .driverkit = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnux32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslx32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .x32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnux32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslx32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .x32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .maccatalyst = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .macos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps4 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps5 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, - .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps4 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps5 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, + .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic }, diff --git a/test/llvm/nonnull b/test/llvm/nonnull new file mode 100644 index 0000000000000000000000000000000000000000..90d904ba6df7befeace21f9bf6b27e4cc4fec35c --- /dev/null +++ b/test/llvm/nonnull @@ -0,0 +1,44 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + +#obj { +--name test -fno-lld -fno-new-linker -ofmt=llvmir +-Mroot=test.zig +#} + +#write test.zig { +export fn entry(ptr: *i16) i16 { + return ptr.*; +} +#} +#update "store" +#check llvm { +define #...@test.entry(ptr #...nonnull #...%0) #...{ +#...load i16, ptr %0#... +} + +#} + +#write test.zig { +export fn entry(ptr: *i16) void { + ptr.* = 42; +} +#} +#update "load" +#check llvm { +define #...@test.entry(ptr #...nonnull #...%0) #...{ +#...store i16 42, ptr %0#... +} + +#} diff --git a/test/llvm-ir/unused_load b/test/llvm/unused_load similarity index 51% rename from test/llvm-ir/unused_load rename to test/llvm/unused_load index 8f6f3a59cfa74bf420520802d2559b6f49bbe948..b18d0e52d080e7c6769c3f562db251c4df2378bc 100644 --- a/test/llvm-ir/unused_load +++ b/test/llvm/unused_load @@ -1,5 +1,35 @@ +#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic +#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic +#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic + +#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic + +#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic +#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic + +#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic +#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic + +#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic +#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic +#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic + +#skip wasm32-emscripten-none-baseline-whole-llvm-lld-pic +#skip wasm32-freestanding-none-baseline-whole-llvm-lld-pic +#skip wasm32-wasi-none-baseline-whole-llvm-lld-pic + +#skip wasm64-emscripten-none-baseline-whole-llvm-lld-pic +#skip wasm64-freestanding-none-baseline-whole-llvm-lld-pic +#skip wasm64-wasi-none-baseline-whole-llvm-lld-pic + +#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic +#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic +#skip x86_64-linux-x32-baseline-whole-llvm-new-pic + #obj { ---name test +--name test -fno-lld -fno-new-linker -ofmt=llvmir -Mroot=test.zig #} -- 2.54.0