authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-21 10:06:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-21 10:06:42-07:00
log465b2d51d1a54761b3517eef93ccffcf7df44233
tree098598c0323c1244904e088cae984a1e5c0458b6
parented136f830665c38af3d0d4beb1177584cb6d40d7
parent6148ec9f438e38c94ce95d5802103c7c078acff0

Merge pull request 'test/llvm-*: convert to new runner' (#37285) from jacobly/llvm-ir-tests into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37285 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

143 files changed, 6334 insertions(+), 5568 deletions(-)

CMakeLists.txt+1-1
...@@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES...@@ -330,7 +330,7 @@ set(ZIG_STAGE2_SOURCES
330 src/Air/Legalize.zig330 src/Air/Legalize.zig
331 src/Air/Liveness.zig331 src/Air/Liveness.zig
332 src/Air/Liveness/Verify.zig332 src/Air/Liveness/Verify.zig
333 src/Air/print.zig333 src/Air/Print.zig
334 src/Builtin.zig334 src/Builtin.zig
335 src/Compilation.zig335 src/Compilation.zig
336 src/Compilation/Config.zig336 src/Compilation/Config.zig
bootstrap.c+1-1
...@@ -179,7 +179,7 @@ int main(int argc, char **argv) {...@@ -179,7 +179,7 @@ int main(int argc, char **argv) {
179 "pub const version: [:0]const u8 = \"%s\";\n"179 "pub const version: [:0]const u8 = \"%s\";\n"
180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"180 "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n"
181 "pub const enable_debug_extensions = false;\n"181 "pub const enable_debug_extensions = false;\n"
182 "pub const enable_logging = false;\n"182 "pub const log_level: @import(\"std\").log.Level = .err;\n"
183 "pub const enable_link_snapshots = false;\n"183 "pub const enable_link_snapshots = false;\n"
184 "pub const enable_tracy = false;\n"184 "pub const enable_tracy = false;\n"
185 "pub const value_tracing = false;\n"185 "pub const value_tracing = false;\n"
build.zig+32-27
...@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {...@@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void {
25 },25 },
26 });26 });
27 const optimize = b.standardOptimizeOption(.{});27 const optimize = b.standardOptimizeOption(.{});
28 const is_debug = switch (optimize) {
29 .debug => true,
30 .safe, .fast, .small => false,
31 };
2832
29 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;33 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;
30 const single_threaded = b.option(bool, "single-threaded", "Build artifacts that run in single threaded mode");34 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 {...@@ -205,9 +209,9 @@ pub fn build(b: *std.Build) !void {
205 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;209 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;
206210
207 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: {211 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: {
208 if (strip == true) break :blk @as(u32, 0);212 if (strip == true) break :blk 0;
209 if (optimize != .debug) break :blk 0;213 if (is_debug) break :blk 4;
210 break :blk 4;214 break :blk 0;
211 };215 };
212216
213 const exe = addCompilerStep(b, .{217 const exe = addCompilerStep(b, .{
...@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {...@@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void {
255 exe.root_module.link_libc = true;259 exe.root_module.link_libc = true;
256 }260 }
257261
258 const is_debug = optimize == .debug;
259 const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;262 const enable_debug_extensions = b.option(bool, "debug-extensions", "Enable commands and options useful for debugging the compiler") orelse is_debug;
260 const enable_logging = b.option(bool, "log", "Enable debug logging with --debug-log") orelse is_debug;263 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) {
264 true => .debug,
265 false => switch (optimize) {
266 .debug => .debug,
267 .safe, .fast => .info,
268 .small => .err,
269 },
270 };
261271
262 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");272 const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git.");
263 const version_slice = if (opt_version_string) |version| version else v: {273 const version_slice = if (opt_version_string) |version| version else v: {
...@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {...@@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void {
398 exe_options.addOption(std.SemanticVersion, "semver", semver);408 exe_options.addOption(std.SemanticVersion, "semver", semver);
399409
400 exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);410 exe_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);
401 exe_options.addOption(bool, "enable_logging", enable_logging);411 exe_options.addOption(std.log.Level, "log_level", log_level);
402 exe_options.addOption(bool, "enable_tracy", tracy != null);412 exe_options.addOption(bool, "enable_tracy", tracy != null);
403 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);413 exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack);
404 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);414 exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation);
...@@ -494,12 +504,6 @@ pub fn build(b: *std.Build) !void {...@@ -494,12 +504,6 @@ pub fn build(b: *std.Build) !void {
494 .skip_linux = skip_linux,504 .skip_linux = skip_linux,
495 .skip_llvm = skip_llvm,505 .skip_llvm = skip_llvm,
496 .skip_libc = skip_libc,506 .skip_libc = skip_libc,
497 }, .{
498 .enable_llvm = enable_llvm,
499 .llvm_has_m68k = llvm_has_m68k,
500 .llvm_has_csky = llvm_has_csky,
501 .llvm_has_arc = llvm_has_arc,
502 .llvm_has_xtensa = llvm_has_xtensa,
503 });507 });
504 test_step.dependOn(test_cases_step);508 test_step.dependOn(test_cases_step);
505509
...@@ -702,11 +706,6 @@ pub fn build(b: *std.Build) !void {...@@ -702,11 +706,6 @@ pub fn build(b: *std.Build) !void {
702 .skip_libc = skip_libc,706 .skip_libc = skip_libc,
703 }));707 }));
704 test_step.dependOn(tests.addCliTests(b));708 test_step.dependOn(tests.addCliTests(b));
705 if (tests.addLlvmIrTests(b, .{
706 .enable_llvm = enable_llvm,
707 .test_filters = test_filters,
708 .test_target_filters = test_target_filters,
709 })) |test_llvm_ir_step| test_step.dependOn(test_llvm_ir_step);
710709
711 try addWasiUpdateStep(b, version);710 try addWasiUpdateStep(b, version);
712711
...@@ -783,7 +782,7 @@ pub fn build(b: *std.Build) !void {...@@ -783,7 +782,7 @@ pub fn build(b: *std.Build) !void {
783 const runner = b.addExecutable(.{782 const runner = b.addExecutable(.{
784 .name = "runner",783 .name = "runner",
785 .root_module = b.createModule(.{784 .root_module = b.createModule(.{
786 .root_source_file = b.path("test/src/Runner.zig"),785 .root_source_file = b.path("test/Runner.zig"),
787 .target = b.graph.host,786 .target = b.graph.host,
788 }),787 }),
789 });788 });
...@@ -799,21 +798,27 @@ pub fn build(b: *std.Build) !void {...@@ -799,21 +798,27 @@ pub fn build(b: *std.Build) !void {
799 .skip_darwin = skip_darwin,798 .skip_darwin = skip_darwin,
800 .skip_linux = skip_linux,799 .skip_linux = skip_linux,
801 .skip_llvm = skip_llvm,800 .skip_llvm = skip_llvm,
801 .llvm_has_m68k = llvm_has_m68k,
802 .llvm_has_csky = llvm_has_csky,
803 .llvm_has_arc = llvm_has_arc,
804 .llvm_has_xtensa = llvm_has_xtensa,
802 .gdb = b.option([]const u8, "gdb", "path to gdb binary"),805 .gdb = b.option([]const u8, "gdb", "path to gdb binary"),
803 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),806 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),
804 };807 };
805808
809 const test_debugger_step = b.step("test-debugger", "Run the debugger tests");
810 if (runner_opts.gdb != null or runner_opts.lldb != null) {
811 try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", @import("test/debugger/matrix.zon"), runner_opts);
812 test_step.dependOn(test_debugger_step);
813 } else test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);
814
806 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests");815 const test_incremental_step = b.step("test-incremental", "Run the incremental compilation tests");
807 try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", tests.incremental_matrix, runner_opts);816 try tests.addRunnerTests(b, runner, test_incremental_step, "test/incremental", @import("test/incremental/matrix.zon"), runner_opts);
808 test_step.dependOn(test_incremental_step);817 test_step.dependOn(test_incremental_step);
809818
810 const test_debugger_step = b.step("test-debugger", "Run the debugger tests");819 const test_llvm_step = b.step("test-llvm", "Run the LLVM IR tests");
811 if (runner_opts.gdb == null and runner_opts.lldb == null) {820 try tests.addRunnerTests(b, runner, test_llvm_step, "test/llvm", @import("test/llvm/matrix.zon"), runner_opts);
812 test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").step);821 test_step.dependOn(test_llvm_step);
813 } else {
814 try tests.addRunnerTests(b, runner, test_debugger_step, "test/debugger", tests.debugger_matrix, runner_opts);
815 test_step.dependOn(test_debugger_step);
816 }
817}822}
818823
819fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {824fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
...@@ -837,7 +842,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {...@@ -837,7 +842,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
837 exe_options.addOption([:0]const u8, "version", version);842 exe_options.addOption([:0]const u8, "version", version);
838 exe_options.addOption(std.SemanticVersion, "semver", semver);843 exe_options.addOption(std.SemanticVersion, "semver", semver);
839 exe_options.addOption(bool, "enable_debug_extensions", false);844 exe_options.addOption(bool, "enable_debug_extensions", false);
840 exe_options.addOption(bool, "enable_logging", false);845 exe_options.addOption(std.log.Level, "log_level", .err);
841 exe_options.addOption(bool, "enable_tracy", false);846 exe_options.addOption(bool, "enable_tracy", false);
842 exe_options.addOption(bool, "enable_tracy_callstack", false);847 exe_options.addOption(bool, "enable_tracy_callstack", false);
843 exe_options.addOption(bool, "enable_tracy_allocation", false);848 exe_options.addOption(bool, "enable_tracy_allocation", false);
lib/compiler/Maker.zig-4
...@@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void {...@@ -509,14 +509,10 @@ pub fn main(init: process.Init.Minimal) !void {
509 } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {509 } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) {
510 // --glibc-runtimes was the old name of the flag; kept for compatibility for now.510 // --glibc-runtimes was the old name of the flag; kept for compatibility for now.
511 graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);511 graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i);
512 } else if (mem.eql(u8, arg, "--verbose-air")) {
513 graph.verbose_air = true;
514 } else if (mem.eql(u8, arg, "--verbose-cc")) {512 } else if (mem.eql(u8, arg, "--verbose-cc")) {
515 graph.verbose_cc = true;513 graph.verbose_cc = true;
516 } else if (mem.eql(u8, arg, "--verbose-link")) {514 } else if (mem.eql(u8, arg, "--verbose-link")) {
517 graph.verbose_link = true;515 graph.verbose_link = true;
518 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
519 graph.verbose_llvm_ir = true;
520 } else if (mem.eql(u8, arg, "--watch")) {516 } else if (mem.eql(u8, arg, "--watch")) {
521 watch_flag = true;517 watch_flag = true;
522 } else if (mem.eql(u8, arg, "--time-report")) {518 } else if (mem.eql(u8, arg, "--time-report")) {
lib/compiler/Maker/Graph.zig-3
...@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,...@@ -32,11 +32,8 @@ debug_compile_errors: bool = false,
32debug_incremental: bool = false,32debug_incremental: bool = false,
33fuzzing: bool = false,33fuzzing: bool = false,
34verbose: bool = false,34verbose: bool = false,
35verbose_air: bool = false,
36verbose_cc: bool = false,35verbose_cc: bool = false,
37verbose_link: bool = false,36verbose_link: bool = false,
38verbose_llvm_cpu_features: bool = false,
39verbose_llvm_ir: bool = false,
40libc_file: ?[]const u8 = null,37libc_file: ?[]const u8 = null,
41/// What does this do? Nobody bothered to document it, and I think it's a38/// What does this do? Nobody bothered to document it, and I think it's a
42/// smelly option. So unless somebody deletes these passive aggressive comments39/// smelly option. So unless somebody deletes these passive aggressive comments
lib/compiler/Maker/Package/Manifest.zig+3-89
...@@ -494,95 +494,9 @@ const Parse = struct {...@@ -494,95 +494,9 @@ const Parse = struct {
494 };494 };
495 switch (result) {495 switch (result) {
496 .success => {},496 .success => {},
497 .failure => |err| try p.appendStrLitError(err, token, bytes, offset),497 .failure => |err| try p.appendErrorOff(token, @intCast(offset + err.offset()), "{f}", .{
498 }498 err.fmt(bytes[offset..]),
499 }499 }),
500
501 /// TODO: try to DRY this with AstGen.failWithStrLitError
502 fn appendStrLitError(
503 p: *Parse,
504 err: std.zig.string_literal.Error,
505 token: Ast.TokenIndex,
506 bytes: []const u8,
507 offset: u32,
508 ) Allocator.Error!void {
509 const raw_string = bytes[offset..];
510 switch (err) {
511 .invalid_escape_character => |bad_index| {
512 try p.appendErrorOff(
513 token,
514 offset + @as(u32, @intCast(bad_index)),
515 "invalid escape character: '{c}'",
516 .{raw_string[bad_index]},
517 );
518 },
519 .expected_hex_digit => |bad_index| {
520 try p.appendErrorOff(
521 token,
522 offset + @as(u32, @intCast(bad_index)),
523 "expected hex digit, found '{c}'",
524 .{raw_string[bad_index]},
525 );
526 },
527 .empty_unicode_escape_sequence => |bad_index| {
528 try p.appendErrorOff(
529 token,
530 offset + @as(u32, @intCast(bad_index)),
531 "empty unicode escape sequence",
532 .{},
533 );
534 },
535 .expected_hex_digit_or_rbrace => |bad_index| {
536 try p.appendErrorOff(
537 token,
538 offset + @as(u32, @intCast(bad_index)),
539 "expected hex digit or '}}', found '{c}'",
540 .{raw_string[bad_index]},
541 );
542 },
543 .invalid_unicode_codepoint => |bad_index| {
544 try p.appendErrorOff(
545 token,
546 offset + @as(u32, @intCast(bad_index)),
547 "unicode escape does not correspond to a unicode code point",
548 .{},
549 );
550 },
551 .expected_lbrace => |bad_index| {
552 try p.appendErrorOff(
553 token,
554 offset + @as(u32, @intCast(bad_index)),
555 "expected '{{', found '{c}",
556 .{raw_string[bad_index]},
557 );
558 },
559 .expected_rbrace => |bad_index| {
560 try p.appendErrorOff(
561 token,
562 offset + @as(u32, @intCast(bad_index)),
563 "expected '}}', found '{c}",
564 .{raw_string[bad_index]},
565 );
566 },
567 .expected_single_quote => |bad_index| {
568 try p.appendErrorOff(
569 token,
570 offset + @as(u32, @intCast(bad_index)),
571 "expected single quote ('), found '{c}",
572 .{raw_string[bad_index]},
573 );
574 },
575 .invalid_character => |bad_index| {
576 try p.appendErrorOff(
577 token,
578 offset + @as(u32, @intCast(bad_index)),
579 "invalid byte in string or character literal: '{c}'",
580 .{raw_string[bad_index]},
581 );
582 },
583 .empty_char_literal => {
584 try p.appendErrorOff(token, offset, "empty character literal", .{});
585 },
586 }500 }
587 }501 }
588502
lib/compiler/Maker/ScannedConfig.zig+2-6
...@@ -351,6 +351,8 @@ const general_usage =...@@ -351,6 +351,8 @@ const general_usage =
351 \\ preferred optimization mode: fast, safe, small351 \\ preferred optimization mode: fast, safe, small
352 \\352 \\
353 \\ --verbose Print commands before executing them353 \\ --verbose Print commands before executing them
354 \\ --verbose-cc Print C compiler commands before executing them
355 \\ --verbose-link Print linker commands before executing them
354 \\ --color [auto|off|on] Enable or disable colored error messages356 \\ --color [auto|off|on] Enable or disable colored error messages
355 \\ --error-style [style] Control how build errors are printed357 \\ --error-style [style] Control how build errors are printed
356 \\ verbose (Default) Report errors with full context358 \\ verbose (Default) Report errors with full context
...@@ -417,11 +419,5 @@ const general_usage =...@@ -417,11 +419,5 @@ const general_usage =
417 \\ none (default) No build ID419 \\ none (default) No build ID
418 \\ --debug-log [scope] Enable debugging the compiler420 \\ --debug-log [scope] Enable debugging the compiler
419 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered421 \\ --debug-pkg-config Fail if unknown pkg-config flags encountered
420 \\ --verbose-link Enable compiler debug output for linking
421 \\ --verbose-air Enable compiler debug output for Zig AIR
422 \\ --verbose-llvm-ir Enable compiler debug output for LLVM IR
423 \\ --verbose-cimport Enable compiler debug output for C imports
424 \\ --verbose-cc Enable compiler debug output for C compilation
425 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
426 \\422 \\
427;423;
lib/compiler/Maker/Step/Compile.zig+1-4
...@@ -608,11 +608,8 @@ fn lowerZigArgs(...@@ -608,11 +608,8 @@ fn lowerZigArgs(
608608
609 try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);609 try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors);
610 try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);610 try addBool(gpa, zig_args, "--debug-incremental", graph.debug_incremental);
611 try addBool(gpa, zig_args, "--verbose-air", graph.verbose_air);
612 try addBool(gpa, zig_args, "--verbose-llvm-ir", graph.verbose_llvm_ir);
613 try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
614 try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc);611 try addBool(gpa, zig_args, "--verbose-cc", graph.verbose_cc or conf_comp.flags.verbose_cc);
615 try addBool(gpa, zig_args, "--verbose-llvm-cpu-features", graph.verbose_llvm_cpu_features);612 try addBool(gpa, zig_args, "--verbose-link", graph.verbose_link or conf_comp.flags.verbose_link);
616 try addBool(gpa, zig_args, "--time-report", graph.time_report);613 try addBool(gpa, zig_args, "--time-report", graph.time_report);
617614
618 if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin");615 if (conf_comp.generated_bin.value == null) try zig_args.append(gpa, "-fno-emit-bin");
lib/compiler/Maker/Step/Run.zig+7-1
...@@ -795,6 +795,7 @@ fn waitZigTest(...@@ -795,6 +795,7 @@ fn waitZigTest(
795 multi_reader: *Io.File.MultiReader,795 multi_reader: *Io.File.MultiReader,
796 opt_metadata: *?TestMetadata,796 opt_metadata: *?TestMetadata,
797 results: *Step.TestResults,797 results: *Step.TestResults,
798 eb_wip: *std.zig.ErrorBundle.Wip,
798) !union(enum) {799) !union(enum) {
799 write_failed: anyerror,800 write_failed: anyerror,
800 no_poll: struct {801 no_poll: struct {
...@@ -885,7 +886,7 @@ fn waitZigTest(...@@ -885,7 +886,7 @@ fn waitZigTest(
885 .{ builtin.zig_version_string, body },886 .{ builtin.zig_version_string, body },
886 );887 );
887 },888 },
888 .error_bundle => step.result_error_bundle = try std.zig.Server.allocErrorBundle(gpa, body),889 .error_bundle => try eb_wip.addBundleAsRoots(try std.zig.Server.allocErrorBundle(arena, body)),
889 .test_metadata => {890 .test_metadata => {
890 // `metadata` would only be populated if we'd already seen a `test_metadata`, but we891 // `metadata` would only be populated if we'd already seen a `test_metadata`, but we
891 // only request it once (and importantly, we don't re-request it if we kill and892 // only request it once (and importantly, we don't re-request it if we kill and
...@@ -1573,6 +1574,9 @@ fn evalZigTest(...@@ -1573,6 +1574,9 @@ fn evalZigTest(
1573 };1574 };
1574 var test_metadata: ?TestMetadata = null;1575 var test_metadata: ?TestMetadata = null;
15751576
1577 var eb_wip: std.zig.ErrorBundle.Wip = try .init(gpa);
1578 defer eb_wip.deinit();
1579
1576 while (true) {1580 while (true) {
1577 var child = try process.spawn(io, spawn_options);1581 var child = try process.spawn(io, spawn_options);
1578 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;1582 var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
...@@ -1602,6 +1606,7 @@ fn evalZigTest(...@@ -1602,6 +1606,7 @@ fn evalZigTest(
1602 &multi_reader,1606 &multi_reader,
1603 &test_metadata,1607 &test_metadata,
1604 &test_results,1608 &test_results,
1609 &eb_wip,
1605 )) {1610 )) {
1606 .write_failed => |err| {1611 .write_failed => |err| {
1607 // The runner unexpectedly closed a stdio pipe, which means a crash. Make sure we've captured1612 // The runner unexpectedly closed a stdio pipe, which means a crash. Make sure we've captured
...@@ -1687,6 +1692,7 @@ fn evalZigTest(...@@ -1687,6 +1692,7 @@ fn evalZigTest(
1687 }1692 }
1688 }1693 }
1689 }1694 }
1695 step.result_error_bundle = try eb_wip.toOwnedBundle("");
1690 return;1696 return;
1691 },1697 },
1692 .timeout => |timeout| {1698 .timeout => |timeout| {
lib/compiler/aro/aro/Driver.zig+1-1
...@@ -927,7 +927,7 @@ pub fn parseArgs(...@@ -927,7 +927,7 @@ pub fn parseArgs(
927 break :debug switch (d.comp.target.ofmt) {927 break :debug switch (d.comp.target.ofmt) {
928 .elf, .macho, .wasm => .{ .dwarf = .@"32" },928 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
929 .coff => .code_view,929 .coff => .code_view,
930 .c => switch (d.comp.target.os.tag) {930 .c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) {
931 .windows, .uefi => .code_view,931 .windows, .uefi => .code_view,
932 else => .{ .dwarf = .@"32" },932 else => .{ .dwarf = .@"32" },
933 },933 },
lib/lldb/pretty_printers.py+100-51
...@@ -13,34 +13,73 @@ page_size = 1 << 12...@@ -13,34 +13,73 @@ page_size = 1 << 12
1313
14def log2_int(i): return i.bit_length() - 114def log2_int(i): return i.bit_length() - 1
1515
16def create_struct(parent, name, struct_type, inits):16class ValueInit:
17 struct_bytes, struct_data = bytearray(struct_type.size), lldb.SBData()17 def __init__(self, value: lldb.SBValue): self.value = value
18 for field in struct_type.fields:18 def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes:
19 field_size = field.type.size19 return self.value.data.uint8
20 field_init = inits[field.name]20 def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue:
21 if isinstance(field_init, int):21 return self.value.Clone(name)
22 match struct_data.byte_order:22
23 case lldb.eByteOrderLittle:23class FromBytes(ValueInit):
24 byte_order = 'little'24 def __init__(self, value_bytes: bytes): self.value_bytes = value_bytes
25 case lldb.eByteOrderBig:25 def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes: return self.value_bytes
26 byte_order = 'big'26 def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue:
27 field_bytes = field_init.to_bytes(field_size, byte_order, signed=field.type.GetTypeFlags() & lldb.eTypeIsSigned != 0)27 data = lldb.SBData()
28 elif isinstance(field_init, lldb.SBValue):28 error = lldb.SBError()
29 field_bytes = field_init.data.uint829 value_bytes = self.toBytes(parent, value_type);
30 else: return30 target = parent.target
31 match struct_data.byte_order:31 data.SetData(error, value_bytes, target.byte_order, target.addr_size)
32 return parent.CreateValueFromData(name, data, value_type)
33
34class IntLiteral(FromBytes):
35 def __init__(self, int_value: int): self.int_value = int_value
36 def toBytes(self, parent: lldb.SBValue, int_type: lldb.SBType) -> bytes:
37 int_flags = int_type.GetTypeFlags()
38 assert int_flags & lldb.eTypeIsInteger != 0
39 int_is_signed = int_flags & lldb.eTypeIsSigned != 0
40 match parent.target.byte_order:
32 case lldb.eByteOrderLittle:41 case lldb.eByteOrderLittle:
33 field_bytes = field_bytes[:field_size]42 byte_order = 'little'
34 field_start = field.byte_offset
35 struct_bytes[field_start:field_start + len(field_bytes)] = field_bytes
36 case lldb.eByteOrderBig:43 case lldb.eByteOrderBig:
37 field_bytes = field_bytes[-field_size:]44 byte_order = 'big'
38 field_end = field.byte_offset + field_size45 return self.int_value.to_bytes(int_type.size, byte_order, signed=int_is_signed)
39 struct_bytes[field_end - len(field_bytes):field_end] = field_bytes46
40 struct_data.SetData(lldb.SBError(), struct_bytes, struct_data.byte_order, struct_data.GetAddressByteSize())47class FromBackingInt(FromBytes):
41 return parent.CreateValueFromData(name, struct_data, struct_type)48 def __init__(self, field_value: int): self.field_value = field_value
4249 def fieldValue(self, enum_type: lldb.SBType) -> int: return self.field_value
43# Define Zig Language50 def toBytes(self, parent: lldb.SBValue, enum_type: lldb.SBType) -> bytes:
51 assert enum_type.type == lldb.eTypeClassEnumeration
52 backing_int = IntLiteral(self.fieldValue(enum_type));
53 return backing_int.toBytes(parent, enum_type.GetEnumerationIntegerType())
54
55class EnumField(FromBackingInt):
56 def __init__(self, field_index: int): self.field_index = field_index
57 def fieldIndex(self, enum_type: lldb.SBType) -> int: return self.field_index
58 def fieldValue(self, enum_type: lldb.SBType) -> int:
59 enum_is_signed = enum_type.GetEnumerationIntegerType().GetTypeFlags() & lldb.eTypeIsSigned != 0
60 field = enum_type.enum_members[self.fieldIndex(enum_type)]
61 return field.signed if enum_is_signed else field.unsigned
62
63class EnumLiteral(EnumField):
64 def __init__(self, field_name: str): self.field_name = field_name
65 def fieldName(self, enum_type: lldb.SBType) -> str: return self.field_name
66 def fieldIndex(self, enum_type: lldb.SBType) -> int:
67 field_name = self.fieldName(enum_type)
68 return next(field_index for field_index, field in enumerate(enum_type.enum_members)
69 if field.name == field_name)
70
71class StructInit(FromBytes):
72 def __init__(self, field_inits: dict[str, ValueInit]): self.field_inits = field_inits
73 def toBytes(self, parent: lldb.SBValue, struct_type: lldb.SBType) -> bytes:
74 assert struct_type.type == lldb.eTypeClassStruct
75 struct_bytes = bytearray(struct_type.size)
76 for field in struct_type.fields:
77 field_bytes = self.field_inits[field.name].toBytes(parent, field.type)
78 assert len(field_bytes) == field.type.size
79 struct_bytes[field.byte_offset:field.byte_offset + len(field_bytes)] = field_bytes
80 return bytes(struct_bytes)
81
82# Define Zig Language (for programs compiled with the llvm backend)
4483
45zig_keywords = {84zig_keywords = {
46 'addrspace',85 'addrspace',
...@@ -204,7 +243,7 @@ class zig_TaggedUnion_SynthProvider:...@@ -204,7 +243,7 @@ class zig_TaggedUnion_SynthProvider:
204 except: return -1243 except: return -1
205 def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None244 def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None
206245
207# Define Zig Standard Library246# Define Zig Standard Library (for programs compiled with the llvm backend)
208247
209class std_MultiArrayList_SynthProvider:248class std_MultiArrayList_SynthProvider:
210 def __init__(self, value, _=None): self.value = value249 def __init__(self, value, _=None): self.value = value
...@@ -331,7 +370,7 @@ class std_Entry_SynthProvider:...@@ -331,7 +370,7 @@ class std_Entry_SynthProvider:
331 def get_child_index(self, name): return self.indices.get(name)370 def get_child_index(self, name): return self.indices.get(name)
332 def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None371 def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None
333372
334# Define Zig Compiler373# Define Zig Compiler (compiled with the llvm backend)
335374
336class TagAndPayload_SynthProvider:375class TagAndPayload_SynthProvider:
337 def __init__(self, value, _=None): self.value = value376 def __init__(self, value, _=None): self.value = value
...@@ -435,8 +474,9 @@ class InternPool_Index_SynthProvider:...@@ -435,8 +474,9 @@ class InternPool_Index_SynthProvider:
435 def __init__(self, value, _=None): self.value = value474 def __init__(self, value, _=None): self.value = value
436 def update(self):475 def update(self):
437 try:476 try:
477 target = self.value.target
438 index_type = self.value.type478 index_type = self.value.type
439 for helper in self.value.target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull):479 for helper in target.FindFunctions('%s.dbHelper' % index_type.name, lldb.eFunctionNameTypeFull):
440 ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes()480 ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes()
441 if ptr_self_type.GetPointeeType() == index_type: break481 if ptr_self_type.GetPointeeType() == index_type: break
442 else: return482 else: return
...@@ -465,7 +505,7 @@ class InternPool_Index_SynthProvider:...@@ -465,7 +505,7 @@ class InternPool_Index_SynthProvider:
465 for trailing_field in encoding_field.type.fields:505 for trailing_field in encoding_field.type.fields:
466 trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data)506 trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data)
467 trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned507 trailing_len = dynamic_values['trailing.%s.len' % trailing_field.name].unsigned
468 trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, trailing_data.GetAddressByteSize()))508 trailing_data.Append(lldb.SBData.CreateDataFromInt(trailing_len, target.addr_size, target=target))
469 extra_index += trailing_len509 extra_index += trailing_len
470 self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type)510 self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type)
471 else:511 else:
...@@ -685,8 +725,18 @@ value_tag_handlers = {...@@ -685,8 +725,18 @@ value_tag_handlers = {
685class root_InternPool_Local_List_SynthProvider:725class root_InternPool_Local_List_SynthProvider:
686 def __init__(self, value, _=None): self.value = value726 def __init__(self, value, _=None): self.value = value
687 def update(self):727 def update(self):
688 capacity = self.value.EvaluateExpression('@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity')728 capacity = IntLiteral(self.value.EvaluateExpression(
689 self.view = create_struct(self.value, '.view', self.value.type.FindDirectNestedType('View'), { 'bytes': self.value.GetChildMemberWithName('bytes'), 'len': capacity, 'capacity': capacity }).GetNonSyntheticValue()729 '@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity',
730 ).unsigned)
731 View = self.value.type.FindDirectNestedType('View')
732 self.view = StructInit({
733 'bytes': ValueInit(self.value.GetChildMemberWithName('bytes')),
734 'len': capacity,
735 'capacity': capacity,
736 'pointer_stability': StructInit({
737 'state': EnumField(0),
738 }),
739 }).create(self.value, '.view', View).GetNonSyntheticValue()
690 def has_children(self): return True740 def has_children(self): return True
691 def num_children(self): return 1741 def num_children(self): return 1
692 def get_child_index(self, name):742 def get_child_index(self, name):
...@@ -719,7 +769,10 @@ class root_InternPool_Index_SynthProvider:...@@ -719,7 +769,10 @@ class root_InternPool_Index_SynthProvider:
719 unwrapped_type = self.value.type.FindDirectNestedType('Unwrapped')769 unwrapped_type = self.value.type.FindDirectNestedType('Unwrapped')
720 ip = self.value.CreateValueFromType(unwrapped_type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?')770 ip = self.value.CreateValueFromType(unwrapped_type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?')
721 tid_shift_30 = ip.GetChildMemberWithName('tid_shift_30').unsigned771 tid_shift_30 = ip.GetChildMemberWithName('tid_shift_30').unsigned
722 self.unwrapped = create_struct(self.value, '.unwrapped', unwrapped_type, { 'tid': wrapped >> tid_shift_30, 'index': wrapped & (1 << tid_shift_30) - 1 })772 self.unwrapped = StructInit({
773 'tid': FromBackingInt(wrapped >> tid_shift_30),
774 'index': IntLiteral(wrapped & (1 << tid_shift_30) - 1),
775 }).create(self.value, '.unwrapped', unwrapped_type)
723 def has_children(self): return True776 def has_children(self): return True
724 def num_children(self): return 0777 def num_children(self): return 0
725 def get_child_index(self, name):778 def get_child_index(self, name):
...@@ -732,6 +785,7 @@ class root_InternPool_Index_SynthProvider:...@@ -732,6 +785,7 @@ class root_InternPool_Index_SynthProvider:
732class root_InternPool_Index_Unwrapped_SynthProvider:785class root_InternPool_Index_Unwrapped_SynthProvider:
733 def __init__(self, value, _=None): self.value = value786 def __init__(self, value, _=None): self.value = value
734 def update(self):787 def update(self):
788 target = self.value.target
735 self.tag, self.index, self.data, self.payload, self.trailing = None, None, None, None, None789 self.tag, self.index, self.data, self.payload, self.trailing = None, None, None, None, None
736 index = self.value.GetChildMemberWithName('index')790 index = self.value.GetChildMemberWithName('index')
737 ip = self.value.CreateValueFromType(self.value.type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?')791 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:...@@ -742,36 +796,34 @@ class root_InternPool_Index_Unwrapped_SynthProvider:
742 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')796 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')
743 if encoding_index:797 if encoding_index:
744 index_type = encoding_index.GetValueAsType()798 index_type = encoding_index.GetValueAsType()
745 index_bytes, index_data = index.data.uint8, lldb.SBData()799 index_bytes = index.data.uint8
746 match index_data.byte_order:800 match target.byte_order:
747 case lldb.eByteOrderLittle:801 case lldb.eByteOrderLittle:
748 index_bytes = bytes(index_bytes[:index_type.size])802 index_bytes = bytes(index_bytes[:index_type.size])
749 case lldb.eByteOrderBig:803 case lldb.eByteOrderBig:
750 index_bytes = bytes(index_bytes[-index_type.size:])804 index_bytes = bytes(index_bytes[-index_type.size:])
751 index_data.SetData(lldb.SBError(), index_bytes, index_data.byte_order, index_data.GetAddressByteSize())805 self.index = FromBytes(index_bytes).create(self.value, '.index', index_type)
752 self.index = self.value.CreateValueFromData('.index', index_data, index_type)
753 elif encoding_data:806 elif encoding_data:
754 data_type = encoding_data.GetValueAsType()807 data_type = encoding_data.GetValueAsType()
755 data_bytes, data_data = item_data.data.uint8, lldb.SBData()808 data_bytes = item_data.data.uint8
756 match data_data.byte_order:809 match target.byte_order:
757 case lldb.eByteOrderLittle:810 case lldb.eByteOrderLittle:
758 data_bytes = bytes(data_bytes[:data_type.size])811 data_bytes = bytes(data_bytes[:data_type.size])
759 case lldb.eByteOrderBig:812 case lldb.eByteOrderBig:
760 data_bytes = bytes(data_bytes[-data_type.size:])813 data_bytes = bytes(data_bytes[-data_type.size:])
761 data_data.SetData(lldb.SBError(), data_bytes, data_data.byte_order, data_data.GetAddressByteSize())814 self.data = FromBytes(data_bytes).create(self.value, '.data', data_type)
762 self.data = self.value.CreateValueFromData('.data', data_data, data_type)
763 elif encoding_payload:815 elif encoding_payload:
764 extra = shared.GetChildMemberWithName('extra').GetChildMemberWithName('view').GetChildMemberWithName('0')816 extra = shared.GetChildMemberWithName('extra').GetChildMemberWithName('view').GetChildMemberWithName('0')
765 extra_index = item_data.unsigned817 extra_index = item_data.unsigned
766 payload_type = encoding_payload.GetValueAsType()818 payload_type = encoding_payload.GetValueAsType()
767 payload_fields = dict()819 payload_fields = dict()
768 for payload_field in payload_type.fields:820 for payload_field in payload_type.fields:
769 payload_fields[payload_field.name] = extra.child[extra_index]821 payload_fields[payload_field.name] = ValueInit(extra.child[extra_index])
770 extra_index += 1822 extra_index += 1
771 self.payload = create_struct(self.value, '.payload', payload_type, payload_fields)823 self.payload = StructInit(payload_fields).create(self.value, '.payload', payload_type)
772 if encoding_trailing and encoding_config:824 if encoding_trailing and encoding_config:
773 trailing_type = encoding_trailing.GetValueAsType()825 trailing_type = encoding_trailing.GetValueAsType()
774 trailing_bytes, trailing_data = bytearray(trailing_type.size), lldb.SBData()826 trailing_bytes = bytearray(trailing_type.size)
775 def eval_config(config_name):827 def eval_config(config_name):
776 expr = encoding_config.GetChildMemberWithName(config_name).value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"')828 expr = encoding_config.GetChildMemberWithName(config_name).value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"')
777 if 'payload.' in expr:829 if 'payload.' in expr:
...@@ -780,13 +832,11 @@ class root_InternPool_Index_Unwrapped_SynthProvider:...@@ -780,13 +832,11 @@ class root_InternPool_Index_Unwrapped_SynthProvider:
780 field_type, field_byte_offset = trailing_type, 0832 field_type, field_byte_offset = trailing_type, 0
781 expr_parts = expr.split('.')833 expr_parts = expr.split('.')
782 for expr_part in expr_parts[1:]:834 for expr_part in expr_parts[1:]:
783 field = next(filter(lambda field: field.name == expr_part, field_type.fields))835 field = next(field for field in field_type.fields if field.name == expr_part)
784 field_type = field.type836 field_type = field.type
785 field_byte_offset += field.byte_offset837 field_byte_offset += field.byte_offset
786 field_data = lldb.SBData()
787 field_bytes = trailing_bytes[field_byte_offset:field_byte_offset + field_type.size]838 field_bytes = trailing_bytes[field_byte_offset:field_byte_offset + field_type.size]
788 field_data.SetData(lldb.SBError(), field_bytes, field_data.byte_order, field_data.GetAddressByteSize())839 return FromBytes(field_bytes).create(self.value, '.%s' % expr_parts[-1], field_type)
789 return self.value.CreateValueFromData('.%s' % expr_parts[-1], field_data, field_type)
790 else:840 else:
791 return self.value.frame.EvaluateExpression(expr)841 return self.value.frame.EvaluateExpression(expr)
792 for trailing_field in trailing_type.fields:842 for trailing_field in trailing_type.fields:
...@@ -812,7 +862,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider:...@@ -812,7 +862,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider:
812 trailing_bytes[ptr_field_byte_offset:ptr_field_byte_offset + ptr_field.type.size] = extra.child[extra_index].address_of.data.uint8862 trailing_bytes[ptr_field_byte_offset:ptr_field_byte_offset + ptr_field.type.size] = extra.child[extra_index].address_of.data.uint8
813 len_field_value = eval_config('%s.len' % trailing_field_name)863 len_field_value = eval_config('%s.len' % trailing_field_name)
814 len_field_size = len_field.type.size864 len_field_size = len_field.type.size
815 match trailing_data.byte_order:865 match target.byte_order:
816 case lldb.eByteOrderLittle:866 case lldb.eByteOrderLittle:
817 len_field_bytes = len_field_value.data.uint8[:len_field_size]867 len_field_bytes = len_field_value.data.uint8[:len_field_size]
818 trailing_bytes[len_field_byte_offset:len_field_byte_offset + len(len_field_bytes)] = len_field_bytes868 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:...@@ -827,8 +877,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider:
827 trailing_bytes[trailing_field_byte_offset + offset:trailing_field_byte_offset + offset + 4] = extra.child[extra_index].data.uint8877 trailing_bytes[trailing_field_byte_offset + offset:trailing_field_byte_offset + offset + 4] = extra.child[extra_index].data.uint8
828 extra_index += 1878 extra_index += 1
829 break879 break
830 trailing_data.SetData(lldb.SBError(), trailing_bytes, trailing_data.byte_order, trailing_data.GetAddressByteSize())880 self.trailing = FromBytes(trailing_bytes).create(self.value, '.trailing', trailing_type)
831 self.trailing = self.value.CreateValueFromData('.trailing', trailing_data, trailing_type)
832 def has_children(self): return True881 def has_children(self): return True
833 def num_children(self): return 1 + ((self.index or self.data or self.payload) is not None) + (self.trailing is not None)882 def num_children(self): return 1 + ((self.index or self.data or self.payload) is not None) + (self.trailing is not None)
834 def get_child_index(self, name):883 def get_child_index(self, name):
lib/std/Build/Configuration.zig+2
...@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {...@@ -2519,6 +2519,8 @@ pub const TargetQuery = struct {
2519 coff,2519 coff,
2520 elf,2520 elf,
2521 hex,2521 hex,
2522 llvmbc,
2523 llvmir,
2522 macho,2524 macho,
2523 plan9,2525 plan9,
2524 raw,2526 raw,
lib/std/Io/Threaded.zig+79-54
...@@ -7191,9 +7191,9 @@ fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize {...@@ -7191,9 +7191,9 @@ fn realPathPosix(fd: posix.fd_t, out_buffer: []u8) File.RealPathError!usize {
7191 return n;7191 return n;
7192 },7192 },
7193 .linux, .serenity, .illumos => {7193 .linux, .serenity, .illumos => {
7194 var procfs_buf: ["/proc/self/path/-2147483648\x00".len]u8 = undefined;7194 var proc_buf: [std.fmt.count("/proc/self/path/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined;
7195 const template = if (native_os == .illumos) "/proc/self/path/{d}" else "/proc/self/fd/{d}";7195 const template = if (native_os == .illumos) "/proc/self/path/{d}" else "/proc/self/fd/{d}";
7196 const proc_path = std.mem.printSentinel(&procfs_buf, template, .{fd}, 0) catch unreachable;7196 const proc_path = std.mem.printSentinel(&proc_buf, template, .{fd}, 0) catch unreachable;
7197 const syscall: Syscall = try .start();7197 const syscall: Syscall = try .start();
7198 while (true) {7198 while (true) {
7199 const rc = posix.system.readlink(proc_path, out_buffer.ptr, out_buffer.len);7199 const rc = posix.system.readlink(proc_path, out_buffer.ptr, out_buffer.len);
...@@ -7266,27 +7266,32 @@ fn fileHardLink(...@@ -7266,27 +7266,32 @@ fn fileHardLink(
7266 new_sub_path: []const u8,7266 new_sub_path: []const u8,
7267 options: File.HardLinkOptions,7267 options: File.HardLinkOptions,
7268) File.HardLinkError!void {7268) File.HardLinkError!void {
7269 _ = userdata;7269 const t: *Threaded = @ptrCast(@alignCast(userdata));
7270 if (native_os != .linux) return error.OperationUnsupported;7270 _ = t;
72717271
7272 var new_path_buffer: [posix.PATH_MAX]u8 = undefined;7272 var new_path_buffer: [posix.PATH_MAX]u8 = undefined;
7273 const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer);7273 const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer);
72747274
7275 const flags: u32 = if (options.follow_symlinks)7275 switch (native_os) {
7276 posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH7276 else => return error.OperationUnsupported,
7277 else7277 .freebsd, .linux => {
7278 posix.AT.EMPTY_PATH;7278 const flags: u32 = if (options.follow_symlinks)
7279 posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH
7280 else
7281 posix.AT.EMPTY_PATH;
72797282
7280 return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) {7283 return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) {
7281 error.FileNotFound => {7284 error.FileNotFound => {},
7282 if (options.follow_symlinks) return error.FileNotFound;7285 else => |e| return e,
7283 var proc_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;7286 };
7284 const proc_path = std.mem.printSentinel(&proc_buf, "/proc/self/fd/{d}", .{file.handle}, 0) catch
7285 unreachable;
7286 return linkat(posix.AT.FDCWD, proc_path, new_dir.handle, new_sub_path_posix, posix.AT.SYMLINK_FOLLOW);
7287 },7287 },
7288 else => |e| return e,7288 .netbsd, .openbsd => {},
7289 };7289 }
7290
7291 if (options.follow_symlinks) return error.FileNotFound;
7292 var dev_buf: [std.fmt.count("/dev/fd/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined;
7293 const dev_path = std.mem.printSentinel(&dev_buf, "/dev/fd/{d}", .{file.handle}, 0) catch unreachable;
7294 return linkat(posix.AT.FDCWD, dev_path, new_dir.handle, new_sub_path_posix, posix.AT.SYMLINK_FOLLOW);
7290}7295}
72917296
7292fn linkat(7297fn linkat(
...@@ -8732,12 +8737,12 @@ fn fchmodatFallback(...@@ -8732,12 +8737,12 @@ fn fchmodatFallback(
8732) Dir.SetFilePermissionsError!void {8737) Dir.SetFilePermissionsError!void {
8733 comptime assert(native_os == .linux);8738 comptime assert(native_os == .linux);
87348739
8735 // Fallback to changing permissions using procfs:8740 // Fallback to changing permissions using devfs:
8736 //8741 //
8737 // 1. Open `path` as a `PATH` descriptor.8742 // 1. Open `path` as a `PATH` descriptor.
8738 // 2. Stat the fd and check if it isn't a symbolic link.8743 // 2. Stat the fd and check if it isn't a symbolic link.
8739 // 3. Generate the procfs reference to the fd via `/proc/self/fd/{fd}`.8744 // 3. Generate the devfs reference to the fd via `/dev/fd/{fd}`.
8740 // 4. Pass the procfs path to `chmod` with the `mode`.8745 // 4. Pass the devfs path to `chmod` with the `mode`.
8741 const path_fd: posix.fd_t = fd: {8746 const path_fd: posix.fd_t = fd: {
8742 const syscall: Syscall = try .start();8747 const syscall: Syscall = try .start();
8743 while (true) {8748 while (true) {
...@@ -8808,11 +8813,11 @@ fn fchmodatFallback(...@@ -8808,11 +8813,11 @@ fn fchmodatFallback(
8808 if ((path_mode & posix.S.IFMT) == posix.S.IFLNK)8813 if ((path_mode & posix.S.IFMT) == posix.S.IFLNK)
8809 return error.OperationUnsupported;8814 return error.OperationUnsupported;
88108815
8811 var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;8816 var dev_buf: [std.fmt.count("/dev/fd/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined;
8812 const proc_path = std.mem.printSentinel(&procfs_buf, "/proc/self/fd/{d}", .{path_fd}, 0) catch unreachable;8817 const dev_path = std.mem.printSentinel(&dev_buf, "/dev/fd/{d}", .{path_fd}, 0) catch unreachable;
8813 const syscall: Syscall = try .start();8818 const syscall: Syscall = try .start();
8814 while (true) {8819 while (true) {
8815 switch (posix.errno(posix.system.chmod(proc_path, mode))) {8820 switch (posix.errno(posix.system.chmod(dev_path, mode))) {
8816 .SUCCESS => return syscall.finish(),8821 .SUCCESS => return syscall.finish(),
8817 .INTR => {8822 .INTR => {
8818 try syscall.checkCancel();8823 try syscall.checkCancel();
...@@ -8821,7 +8826,7 @@ fn fchmodatFallback(...@@ -8821,7 +8826,7 @@ fn fchmodatFallback(
8821 else => |e| {8826 else => |e| {
8822 syscall.finish();8827 syscall.finish();
8823 switch (e) {8828 switch (e) {
8824 .NOENT => return error.OperationUnsupported, // procfs not mounted.8829 .NOENT => return error.OperationUnsupported, // devfs not mounted.
8825 .BADF => |err| return errnoBug(err),8830 .BADF => |err| return errnoBug(err),
8826 .FAULT => |err| return errnoBug(err),8831 .FAULT => |err| return errnoBug(err),
8827 .INVAL => |err| return errnoBug(err),8832 .INVAL => |err| return errnoBug(err),
...@@ -17446,9 +17451,6 @@ pub fn posixExecveat(...@@ -17446,9 +17451,6 @@ pub fn posixExecveat(
17446) process.ReplaceError {17451) process.ReplaceError {
17447 try Thread.checkCancel();17452 try Thread.checkCancel();
17448 switch (err: {17453 switch (err: {
17449 if (path) |p| if (dir == posix.AT.FDCWD or Dir.path.isAbsoluteZ(p)) {
17450 break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr));
17451 };
17452 if (comptime native_os == .linux and (!builtin.link_libc or17454 if (comptime native_os == .linux and (!builtin.link_libc or
17453 (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order(17455 (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order(
17454 .{ .major = 2, .minor = 34, .patch = 0 },17456 .{ .major = 2, .minor = 34, .patch = 0 },
...@@ -17462,34 +17464,57 @@ pub fn posixExecveat(...@@ -17462,34 +17464,57 @@ pub fn posixExecveat(
17462 .NOSYS => {},17464 .NOSYS => {},
17463 }17465 }
17464 }17466 }
17465 var path_buffer: [posix.PATH_MAX]u8 = undefined;17467 if (path) |p| if (dir == posix.AT.FDCWD or Dir.path.isAbsoluteZ(p)) {
17466 var path_len = realPathPosix(dir, &path_buffer) catch |err| switch (err) {17468 break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr));
17467 else => |e| return e,
17468 error.InputOutput,
17469 error.FileTooBig,
17470 error.NoSpaceLeft,
17471 error.PathAlreadyExists,
17472 error.SymLinkLoop,
17473 error.NetworkNotFound,
17474 error.PipeBusy,
17475 error.AntivirusInterference,
17476 => return error.FileNotFound,
17477 error.DeviceBusy,
17478 error.NoDevice,
17479 error.UnrecognizedVolume,
17480 => return error.FileSystem,
17481 };17469 };
17482 if (path) |p| {17470 const exe: posix.fd_t = if (path) |p| exe: {
17483 const path_slice = std.mem.span(p);17471 var flags: posix.O = .{};
17484 path_buffer[path_len] = Dir.path.sep;17472 if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true;
17485 path_len += 1;17473 if (@hasField(posix.O, "LARGEFILE")) flags.LARGEFILE = true;
17486 @memcpy(path_buffer[path_len..][0..path_slice.len], path_slice);17474 if (@hasField(posix.O, "NOCTTY")) flags.NOCTTY = true;
17487 path_len += path_slice.len;17475 if (@hasField(posix.O, "PATH")) flags.PATH = true;
17488 }17476 if (@hasField(posix.O, "EXEC")) flags.EXEC = true;
17489 path_buffer[path_len] = 0;17477 const rc = openat_sym(dir, p, flags, @as(posix.mode_t, 0));
17490 break :err posix.errno(17478 while (true) switch (posix.errno(rc)) {
17491 posix.system.execve(path_buffer[0..path_len :0], argv, env_block.slice.ptr),17479 .SUCCESS => break :exe @intCast(rc),
17492 );17480 .INTR, .AGAIN => {},
17481 .FAULT => |err| return errnoBug(err),
17482 .INVAL => return error.BadPathName,
17483 .BADF => |err| return errnoBug(err), // File descriptor used after closed.
17484 .ACCES => return error.AccessDenied,
17485 .FBIG => return error.InvalidExe,
17486 .OVERFLOW => return error.InvalidExe,
17487 .ISDIR => return error.IsDir,
17488 .LOOP => return error.InvalidExe,
17489 .MFILE => return error.ProcessFdQuotaExceeded,
17490 .NAMETOOLONG => return error.NameTooLong,
17491 .NFILE => return error.SystemFdQuotaExceeded,
17492 .NODEV => return error.FileSystem,
17493 .NOENT => return error.FileNotFound,
17494 .SRCH => return error.FileNotFound, // Linux when opening procfs files.
17495 .NOMEM => return error.SystemResources,
17496 .NOTDIR => return error.NotDir,
17497 .PERM => return error.PermissionDenied,
17498 .BUSY => return error.FileSystem,
17499 .TXTBSY => return error.FileBusy,
17500 .NXIO => return error.FileSystem,
17501 .ILSEQ => return error.BadPathName,
17502 else => |err| return posix.unexpectedErrno(err),
17503 };
17504 } else dir;
17505 defer closeFd(exe);
17506 if (builtin.link_libc and @TypeOf(posix.system.fexecve) != void) {
17507 break :err posix.errno(posix.system.fexecve(exe, argv, env_block.slice.ptr));
17508 }
17509 switch (native_os) {
17510 else => return error.OperationUnsupported,
17511 .linux, .serenity, .illumos => {
17512 var proc_buf: [std.fmt.count("/proc/self/path/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined;
17513 const template = if (native_os == .illumos) "/proc/self/path/{d}" else "/proc/self/fd/{d}";
17514 const proc_path = std.mem.printSentinel(&proc_buf, template, .{exe}, 0) catch unreachable;
17515 break :err posix.errno(posix.system.execve(proc_path, argv, env_block.slice.ptr));
17516 },
17517 }
17493 }) {17518 }) {
17494 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.17519 .FAULT => |err| return errnoBug(err), // Bad pointer parameter.
17495 .@"2BIG" => return error.SystemResources,17520 .@"2BIG" => return error.SystemResources,
lib/std/Target.zig+6
...@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {...@@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum {
1043 elf,1043 elf,
1044 /// The Intel HEX format for storing binary code in ASCII text.1044 /// The Intel HEX format for storing binary code in ASCII text.
1045 hex,1045 hex,
1046 /// LLVM binary intermediate representation.
1047 llvmbc,
1048 /// LLVM text intermediate representation.
1049 llvmir,
1046 /// The Mach object format used by macOS and other Apple platforms.1050 /// The Mach object format used by macOS and other Apple platforms.
1047 macho,1051 macho,
1048 /// The a.out format used by Plan 9 from Bell Labs.1052 /// The a.out format used by Plan 9 from Bell Labs.
...@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {...@@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum {
1060 .coff => ".obj",1064 .coff => ".obj",
1061 .elf, .macho, .wasm => ".o",1065 .elf, .macho, .wasm => ".o",
1062 .hex => ".ihex",1066 .hex => ".ihex",
1067 .llvmbc => ".bc",
1068 .llvmir => ".ll",
1063 .plan9 => arch.plan9Ext(),1069 .plan9 => arch.plan9Ext(),
1064 .raw => ".bin",1070 .raw => ".bin",
1065 .spirv => ".spv",1071 .spirv => ".spv",
lib/std/Target/Query.zig+61-97
...@@ -261,13 +261,11 @@ pub fn parse(args: ParseOptions) !Query {...@@ -261,13 +261,11 @@ pub fn parse(args: ParseOptions) !Query {
261 if (abi_it.next() != null) {261 if (abi_it.next() != null) {
262 if (abi.isGnu()) {262 if (abi.isGnu()) {
263 result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) {263 result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) {
264 error.Overflow => return error.InvalidAbiVersion,264 error.Overflow, error.InvalidVersion => return error.InvalidAbiVersion,
265 error.InvalidVersion => return error.InvalidAbiVersion,
266 };265 };
267 } else if (abi.isAndroid()) {266 } else if (abi.isAndroid()) {
268 result.android_api_level = std.fmt.parseUnsigned(u32, abi_ver_text, 10) catch |err| switch (err) {267 result.android_api_level = std.fmt.parseUnsigned(u32, abi_ver_text, 10) catch |err| switch (err) {
269 error.InvalidCharacter => return error.InvalidVersion,268 error.InvalidCharacter, error.Overflow => return error.InvalidAbiVersion,
270 error.Overflow => |e| return e,
271 };269 };
272 } else {270 } else {
273 return error.InvalidAbiVersion;271 return error.InvalidAbiVersion;
...@@ -428,139 +426,105 @@ pub fn canDetectLibC(self: Query) bool {...@@ -428,139 +426,105 @@ pub fn canDetectLibC(self: Query) bool {
428 return false;426 return false;
429}427}
430428
431/// Formats a version with the patch component omitted if it is zero,429/// Prints a version with the patch component omitted if it is zero,
432/// unlike SemanticVersion.format which formats all its version components regardless.430/// unlike SemanticVersion.format which formats all its version components regardless.
433fn formatVersion(version: SemanticVersion, gpa: Allocator, list: *ArrayList(u8)) !void {431pub const PrintVersion = struct {
434 if (version.patch == 0) {432 version: SemanticVersion,
435 try list.print(gpa, "{d}.{d}", .{ version.major, version.minor });433 pub fn format(print: PrintVersion, w: *std.Io.Writer) std.Io.Writer.Error!void {
436 } else {434 try w.print("{d}.{d}", .{ print.version.major, print.version.minor });
437 try list.print(gpa, "{d}.{d}.{d}", .{ version.major, version.minor, version.patch });435 switch (print.version.patch) {
436 0 => {},
437 else => |patch| try w.print(".{d}", .{patch}),
438 }
438 }439 }
439}440};
440
441pub fn zigTriple(self: Query, gpa: Allocator) Allocator.Error![]u8 {
442 if (self.isNativeTriple()) return gpa.dupe(u8, "native");
443
444 const arch_name = if (self.cpu_arch) |arch| @tagName(arch) else "native";
445 const os_name = if (self.os_tag) |os_tag| @tagName(os_tag) else "native";
446441
447 var result: ArrayList(u8) = .empty;442pub fn printZigTriple(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void {
448 defer result.deinit(gpa);443 if (query.isNativeTriple()) return w.writeAll("native");
449444
450 try result.print(gpa, "{s}-{s}", .{ arch_name, os_name });445 try w.print("{s}-{s}", .{
446 if (query.cpu_arch) |arch| @tagName(arch) else "native",
447 if (query.os_tag) |os_tag| @tagName(os_tag) else "native",
448 });
451449
452 // The zig target syntax does not allow specifying a max os version with no min, so450 // The zig target syntax does not allow specifying a max os version with no min, so
453 // if either are present, we need the min.451 // if either are present, we need the min.
454 if (self.os_version_min) |min| {452 if (query.os_version_min) |min| {
455 switch (min) {453 switch (min) {
456 .none => {},454 .none => {},
457 .semver => |v| {455 .semver => |v| try w.print(".{f}", .{PrintVersion{ .version = v }}),
458 try result.appendSlice(gpa, ".");456 .windows => |v| try w.print("{f}", .{v}),
459 try formatVersion(v, gpa, &result);
460 },
461 .windows => |v| {
462 try result.print(gpa, "{f}", .{v});
463 },
464 }457 }
465 }458 }
466 if (self.os_version_max) |max| {459 if (query.os_version_max) |max| {
467 switch (max) {460 switch (max) {
468 .none => {},461 .none => {},
469 .semver => |v| {462 .semver => |v| try w.print("...{f}", .{PrintVersion{ .version = v }}),
470 try result.appendSlice(gpa, "...");463 // This is counting on a custom format() function defined on `WindowsVersion`
471 try formatVersion(v, gpa, &result);464 // to add a prefix '.' and make there be a total of three dots.
472 },465 .windows => |v| try w.print("..{f}", .{v}),
473 .windows => |v| {
474 // This is counting on a custom format() function defined on `WindowsVersion`
475 // to add a prefix '.' and make there be a total of three dots.
476 try result.print(gpa, "..{f}", .{v});
477 },
478 }466 }
479 }467 }
480468
481 if (self.glibc_version) |v| {469 if (query.glibc_version) |v| {
482 const name = @tagName(self.abi.?);470 try w.print("-{t}.{f}", .{ query.abi.?, PrintVersion{ .version = v } });
483 try result.ensureUnusedCapacity(gpa, name.len + 2);471 } else if (query.android_api_level) |lvl| {
484 result.appendAssumeCapacity('-');472 try w.print("-{t}.{d}", .{ query.abi.?, lvl });
485 result.appendSliceAssumeCapacity(name);473 } else if (query.abi) |abi| {
486 result.appendAssumeCapacity('.');474 try w.print("-{t}", .{abi});
487 try formatVersion(v, gpa, &result);
488 } else if (self.android_api_level) |lvl| {
489 const name = @tagName(self.abi.?);
490 try result.ensureUnusedCapacity(gpa, name.len + 2);
491 result.appendAssumeCapacity('-');
492 result.appendSliceAssumeCapacity(name);
493 result.appendAssumeCapacity('.');
494 try result.print(gpa, "{d}", .{lvl});
495 } else if (self.abi) |abi| {
496 const name = @tagName(abi);
497 try result.ensureUnusedCapacity(gpa, name.len + 1);
498 result.appendAssumeCapacity('-');
499 result.appendSliceAssumeCapacity(name);
500 }475 }
501
502 return result.toOwnedSlice(gpa);
503}476}
504477
505/// Renders the query into a textual representation that can be parsed via the478/// Prints the query into a textual representation that can be parsed via the
506/// `-mcpu` flag passed to the Zig compiler.479/// `-mcpu` flag passed to the Zig compiler.
507/// Appends the result to `buffer`.480pub fn printCpu(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void {
508pub fn serializeCpu(q: Query, buffer: *std.array_list.Managed(u8)) Allocator.Error!void {481 cpu_model: switch (query.cpu_model) {
509 try buffer.ensureUnusedCapacity(8);482 .native, .baseline => |_, cpu_model| try w.print("{t}", .{cpu_model}),
510 switch (q.cpu_model) {483 .determined_by_arch_os => continue :cpu_model if (query.cpu_arch) |_| .baseline else .native,
511 .native => {484 .explicit => |model| try w.writeAll(model.name),
512 buffer.appendSliceAssumeCapacity("native");
513 },
514 .baseline => {
515 buffer.appendSliceAssumeCapacity("baseline");
516 },
517 .determined_by_arch_os => {
518 if (q.cpu_arch == null) {
519 buffer.appendSliceAssumeCapacity("native");
520 } else {
521 buffer.appendSliceAssumeCapacity("baseline");
522 }
523 },
524 .explicit => |model| {
525 try buffer.appendSlice(model.name);
526 },
527 }485 }
528486
529 if (q.cpu_features_add.isEmpty() and q.cpu_features_sub.isEmpty()) {487 if (query.cpu_features_add.isEmpty() and query.cpu_features_sub.isEmpty()) {
530 // The CPU name alone is sufficient.488 // The CPU name alone is sufficient.
531 return;489 return;
532 }490 }
533491
534 const cpu_arch = q.cpu_arch orelse builtin.cpu.arch;492 const cpu_arch = query.cpu_arch orelse builtin.cpu.arch;
535 const all_features = cpu_arch.allFeaturesList();493 const all_features = cpu_arch.allFeaturesList();
536494
537 for (all_features, 0..) |feature, i_usize| {495 for (all_features, 0..) |feature, i_usize| {
538 const i: Target.Cpu.Feature.Set.Index = @intCast(i_usize);496 const i: Target.Cpu.Feature.Set.Index = @intCast(i_usize);
539 try buffer.ensureUnusedCapacity(feature.name.len + 1);497 if (query.cpu_features_sub.isEnabled(i)) {
540 if (q.cpu_features_sub.isEnabled(i)) {498 try w.print("-{s}", .{feature.name});
541 buffer.appendAssumeCapacity('-');499 } else if (query.cpu_features_add.isEnabled(i)) {
542 buffer.appendSliceAssumeCapacity(feature.name);500 try w.print("+{s}", .{feature.name});
543 } else if (q.cpu_features_add.isEnabled(i)) {
544 buffer.appendAssumeCapacity('+');
545 buffer.appendSliceAssumeCapacity(feature.name);
546 }501 }
547 }502 }
548}503}
549504
550pub fn serializeCpuAlloc(q: Query, ally: Allocator) Allocator.Error![]u8 {505/// Deprecated; use `printZigTriple` instead. Will be removed in 0.19.0.
551 var buffer = std.array_list.Managed(u8).init(ally);506pub fn zigTriple(query: Query, gpa: Allocator) Allocator.Error![]u8 {
552 try serializeCpu(q, &buffer);507 return gpa.print("{f}", .{std.fmt.alt(&query, .printZigTriple)});
553 return buffer.toOwnedSlice();508}
509
510/// Deprecated; use `printCpu` instead. Will be removed in 0.19.0.
511pub fn serializeCpu(query: Query, buffer: *std.array_list.Managed(u8)) Allocator.Error!void {
512 try buffer.print("{f}", .{std.fmt.alt(&query, .printCpu)});
513}
514
515/// Deprecated; use `printCpu` instead. Will be removed in 0.19.0.
516pub fn serializeCpuAlloc(query: Query, gpa: Allocator) Allocator.Error![]u8 {
517 return gpa.print("{f}", .{std.fmt.alt(&query, .printCpu)});
554}518}
555519
556/// Deprecated; use `zigTriple` instead. Will be removed in 0.18.0.520/// Deprecated; use `zigTriple` instead. Will be removed in 0.18.0.
557pub fn allocDescription(self: Query, allocator: Allocator) ![]u8 {521pub fn allocDescription(query: Query, allocator: Allocator) ![]u8 {
558 return self.zigTriple(allocator);522 return query.zigTriple(allocator);
559}523}
560524
561/// Deprecated; set `glibc_version` directly. Will be removed in 0.18.0.525/// Deprecated; set `glibc_version` directly. Will be removed in 0.18.0.
562pub fn setGnuLibCVersion(self: *Query, major: u32, minor: u32, patch: u32) void {526pub fn setGnuLibCVersion(query: *Query, major: u32, minor: u32, patch: u32) void {
563 self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch };527 query.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch };
564}528}
565529
566fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !void {530fn parseOs(result: *Query, diags: *ParseOptions.Diagnostics, text: []const u8) !void {
lib/std/c.zig+26-11
...@@ -8387,6 +8387,8 @@ pub const AT = switch (native_os) {...@@ -8387,6 +8387,8 @@ pub const AT = switch (native_os) {
8387 /// to determine the target of relative file paths in the openat() and8387 /// to determine the target of relative file paths in the openat() and
8388 /// similar syscalls.8388 /// similar syscalls.
8389 pub const FDCWD = -100;8389 pub const FDCWD = -100;
8390 /// Fail rename if target exists
8391 pub const RENAME_NOREPLACE = 0x0001;
8390 /// Check access using effective user and group ID8392 /// Check access using effective user and group ID
8391 pub const EACCESS = 0x0100;8393 pub const EACCESS = 0x0100;
8392 /// Do not follow symbolic links8394 /// Do not follow symbolic links
...@@ -8397,6 +8399,10 @@ pub const AT = switch (native_os) {...@@ -8397,6 +8399,10 @@ pub const AT = switch (native_os) {
8397 pub const REMOVEDIR = 0x0800;8399 pub const REMOVEDIR = 0x0800;
8398 /// Fail if not under dirfd8400 /// Fail if not under dirfd
8399 pub const BENEATH = 0x1000;8401 pub const BENEATH = 0x1000;
8402 /// Do not allow name resolution to walk out of dirfd
8403 pub const RESOLVE_BENEATH = 0x2000;
8404 /// Operate on dirfd if path is empty
8405 pub const EMPTY_PATH = 0x4000;
8400 },8406 },
8401 .netbsd => struct {8407 .netbsd => struct {
8402 /// Magic value that specify the use of the current working directory8408 /// Magic value that specify the use of the current working directory
...@@ -8552,7 +8558,11 @@ pub const O = switch (native_os) {...@@ -8552,7 +8558,11 @@ pub const O = switch (native_os) {
8552 DIRECTORY: bool = false,8558 DIRECTORY: bool = false,
8553 CLOEXEC: bool = false,8559 CLOEXEC: bool = false,
8554 SEARCH: bool = false,8560 SEARCH: bool = false,
8555 _: u8 = 0,8561 NOSIGPIPE: bool = false,
8562 REGULAR: bool = false,
8563 EXEC: bool = false,
8564 CLOFORK: bool = false,
8565 _: u4 = 0,
8556 },8566 },
8557 .openbsd => packed struct(u32) {8567 .openbsd => packed struct(u32) {
8558 ACCMODE: std.posix.ACCMODE = .RDONLY,8568 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;...@@ -10937,9 +10947,13 @@ pub extern "c" fn mkdirat(dirfd: fd_t, path: [*:0]const u8, mode: mode_t) c_int;
10937pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;10947pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int;
10938pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int;10948pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int;
10939pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;10949pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int;
10940pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int;10950pub extern "c" fn renameat(olddirfd: fd_t, oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int;
10941pub extern "c" fn chdir(path: [*:0]const u8) c_int;10951pub extern "c" fn chdir(path: [*:0]const u8) c_int;
10942pub extern "c" fn fchdir(fd: fd_t) c_int;10952pub extern "c" fn fchdir(fd: fd_t) c_int;
10953pub const fexecve = switch (native_os) {
10954 else => {},
10955 .freebsd, .linux, .netbsd => private.fexecve,
10956};
10943pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;10957pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;
10944pub 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;10958pub 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;
10945pub extern "c" fn dup(fd: fd_t) c_int;10959pub extern "c" fn dup(fd: fd_t) c_int;
...@@ -11791,34 +11805,35 @@ pub const setkeymap = serenity.setkeymap;...@@ -11791,34 +11805,35 @@ pub const setkeymap = serenity.setkeymap;
1179111805
11792/// External definitions shared by two or more operating systems.11806/// External definitions shared by two or more operating systems.
11793const private = struct {11807const private = struct {
11794 pub extern "c" fn strdup(s: [*:0]const c_char) ?[*:0]c_char;11808 extern "c" fn strdup(s: [*:0]const c_char) ?[*:0]c_char;
11795 pub extern "c" fn _strdup(s: [*:0]const c_char) ?[*:0]c_char;11809 extern "c" fn _strdup(s: [*:0]const c_char) ?[*:0]c_char;
11796 pub extern "c" fn wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t;11810 extern "c" fn wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t;
11797 pub extern "c" fn _wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t;11811 extern "c" fn _wcsdup(s: [*:0]const wchar_t) ?[*:0]wchar_t;
1179811812
11799 pub extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;11813 extern "c" fn swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;
11800 pub extern "c" fn _swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;11814 extern "c" fn _swab(noalias from: *const anyopaque, noalias to: *anyopaque, n: isize) void;
1180111815
11802 extern "c" fn close(fd: fd_t) c_int;
11803 extern "c" fn clock_getres(clk_id: clockid_t, tp: *timespec) c_int;11816 extern "c" fn clock_getres(clk_id: clockid_t, tp: *timespec) c_int;
11804 extern "c" fn clock_gettime(clk_id: clockid_t, tp: *timespec) c_int;11817 extern "c" fn clock_gettime(clk_id: clockid_t, tp: *timespec) c_int;
11818 extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int;
11819 extern "c" fn close(fd: fd_t) c_int;
11805 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;11820 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;
11821 extern "c" fn fexecve(fd: fd_t, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int;
11806 extern "c" fn flock(fd: fd_t, operation: c_int) c_int;11822 extern "c" fn flock(fd: fd_t, operation: c_int) c_int;
11807 extern "c" fn fork() c_int;11823 extern "c" fn fork() c_int;
11808 extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;11824 extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int;
11809 extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, buf: *Stat, flag: u32) c_int;11825 extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, buf: *Stat, flag: u32) c_int;
11810 extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;11826 extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize;
11811 extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) switch (native_os) {11827 extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) switch (native_os) {
11828 else => c_int,
11812 .freebsd => isize,11829 .freebsd => isize,
11813 .illumos => usize,11830 .illumos => usize,
11814 else => c_int,
11815 };11831 };
11816 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;11832 extern "c" fn getrusage(who: c_int, usage: *rusage) c_int;
11817 extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;11833 extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int;
11818 extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int;11834 extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int;
11819 extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;11835 extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int;
11820 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;11836 extern "c" fn nanosleep(rqtp: *const timespec, rmtp: ?*timespec) c_int;
11821 extern "c" fn clock_nanosleep(clockid: clockid_t, flags: TIMER, t: *const timespec, remain: ?*timespec) c_int;
11822 extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int;11837 extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int;
11823 extern "c" fn readdir(dir: *DIR) ?*dirent;11838 extern "c" fn readdir(dir: *DIR) ?*dirent;
11824 extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;11839 extern "c" fn realpath(noalias file_name: [*:0]const u8, noalias resolved_name: [*]u8) ?[*:0]u8;
lib/std/debug.zig+1-1
...@@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {...@@ -76,7 +76,7 @@ pub fn TargetInfo(os: std.Target.Os.Tag, arch: std.Target.Cpu.Arch) type {
76 },76 },
77 .macho => @import("debug/SelfInfo/MachO.zig"),77 .macho => @import("debug/SelfInfo/MachO.zig"),
78 .plan9, .spirv, .wasm, .raw, .hex => void,78 .plan9, .spirv, .wasm, .raw, .hex => void,
79 .c => unreachable,79 .c, .llvmbc, .llvmir => unreachable,
80 };80 };
81}81}
8282
lib/std/fmt.zig+7-1
...@@ -285,7 +285,13 @@ pub fn Alt(...@@ -285,7 +285,13 @@ pub fn Alt(
285pub fn alt(285pub fn alt(
286 context: anytype,286 context: anytype,
287 comptime func_name: @EnumLiteral(),287 comptime func_name: @EnumLiteral(),
288) Alt(@TypeOf(context), @field(@TypeOf(context), @tagName(func_name))) {288) Alt(@TypeOf(context), @field(switch (@typeInfo(@TypeOf(context))) {
289 else => @TypeOf(context),
290 .pointer => |pointer| switch (pointer.size) {
291 else => @TypeOf(context),
292 .one => pointer.child,
293 },
294}, @tagName(func_name))) {
289 return .{ .data = context };295 return .{ .data = context };
290}296}
291297
lib/std/posix.zig+1-1
...@@ -797,7 +797,7 @@ pub fn dl_iterate_phdr(...@@ -797,7 +797,7 @@ pub fn dl_iterate_phdr(
797 const dl = @import("dynamic_library.zig");797 const dl = @import("dynamic_library.zig");
798798
799 switch (builtin.object_format) {799 switch (builtin.object_format) {
800 .elf, .c => {},800 .c, .elf, .llvmbc, .llvmir => {},
801 else => @compileError("dl_iterate_phdr is not available for this target"),801 else => @compileError("dl_iterate_phdr is not available for this target"),
802 }802 }
803803
lib/std/zig.zig+2
...@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe...@@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe
218 },218 },
219 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),219 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
220 },220 },
221 .llvmbc => return std.fmt.allocPrint(allocator, "{s}.bc", .{root_name}),
222 .llvmir => return std.fmt.allocPrint(allocator, "{s}.ll", .{root_name}),
221 .macho => switch (options.output_mode) {223 .macho => switch (options.output_mode) {
222 .Exe => return allocator.dupe(u8, root_name),224 .Exe => return allocator.dupe(u8, root_name),
223 .Lib => {225 .Lib => {
lib/std/zig/llvm/Builder.zig+16-5
...@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va...@@ -10855,11 +10855,22 @@ pub fn resolveAlignmentForwardReference(b: *Builder, fwd_ref: Alignment.Lazy, va
10855 b.alignment_forward_references.items[index] = value;10855 b.alignment_forward_references.items[index] = value;
10856}10856}
1085710857
10858pub fn dump(b: *Builder, io: Io) void {10858pub const Print = struct {
10859 var buffer: [4000]u8 = undefined;10859 name: []const u8,
10860 const stderr: Io.File = .stderr();10860 builder: *Builder,
10861 b.printToFile(io, stderr, &buffer) catch {};10861 err: ?Allocator.Error,
10862}10862
10863 pub fn format(p: *Print, w: *Writer) Writer.Error!void {
10864 try w.print("{q}", .{p.name});
10865 p.builder.print(w) catch |err| switch (err) {
10866 error.WriteFailed => |e| return e,
10867 error.OutOfMemory => |e| {
10868 p.err = e;
10869 return error.WriteFailed;
10870 },
10871 };
10872 }
10873};
1086310874
10864pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {10875pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void {
10865 var buffer: [4000]u8 = undefined;10876 var buffer: [4000]u8 = undefined;
lib/std/zig/string_literal.zig+17-1
...@@ -38,6 +38,11 @@ pub const Error = union(enum) {...@@ -38,6 +38,11 @@ pub const Error = union(enum) {
38 invalid_character: usize,38 invalid_character: usize,
39 /// `''`. Not returned for string literals.39 /// `''`. Not returned for string literals.
40 empty_char_literal,40 empty_char_literal,
41 /// The input ended before the end of the literal.
42 end_of_input: usize,
43 /// The literal ended before the end of the input. There was an otherwise successful
44 /// parse of a prefix of the input of length given by this payload written to the writer.
45 end_of_literal: usize,
4146
42 const FormatMessage = struct {47 const FormatMessage = struct {
43 err: Error,48 err: Error,
...@@ -83,6 +88,12 @@ pub const Error = union(enum) {...@@ -83,6 +88,12 @@ pub const Error = union(enum) {
83 .empty_char_literal => try writer.writeAll(88 .empty_char_literal => try writer.writeAll(
84 "empty character literal",89 "empty character literal",
85 ),90 ),
91 .end_of_input => try writer.writeAll(
92 "expected end of string literal",
93 ),
94 .end_of_literal => try writer.writeAll(
95 "unexpected end of string literal",
96 ),
86 }97 }
87 }98 }
8899
...@@ -104,6 +115,8 @@ pub const Error = union(enum) {...@@ -104,6 +115,8 @@ pub const Error = union(enum) {
104 .expected_rbrace,115 .expected_rbrace,
105 .expected_single_quote,116 .expected_single_quote,
106 .invalid_character,117 .invalid_character,
118 .end_of_input,
119 .end_of_literal,
107 => |n| n,120 => |n| n,
108 .empty_char_literal => 0,121 .empty_char_literal => 0,
109 };122 };
...@@ -339,13 +352,16 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result {...@@ -339,13 +352,16 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result {
339 try writer.writeAll(buf[0..len]);352 try writer.writeAll(buf[0..len]);
340 } else {353 } else {
341 try writer.writeByte(@as(u8, @intCast(codepoint)));354 try writer.writeByte(@as(u8, @intCast(codepoint)));
355 if (index == bytes.len) return .{ .failure = .{ .end_of_input = index } };
342 }356 }
343 },357 },
344 .failure => |err| return .{ .failure = err },358 .failure => |err| return .{ .failure = err },
345 }359 }
346 },360 },
347 '\n' => return .{ .failure = .{ .invalid_character = index } },361 '\n' => return .{ .failure = .{ .invalid_character = index } },
348 '"' => return .success,362 '"' => return if (index < bytes.len - 1) .{
363 .failure = .{ .end_of_literal = index },
364 } else .success,
349 else => {365 else => {
350 try writer.writeByte(b);366 try writer.writeByte(b);
351 index += 1;367 index += 1;
src/Air.zig+5-5
...@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");...@@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig");
13const Type = @import("Type.zig");13const Type = @import("Type.zig");
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
1716
18pub const Legalize = @import("Air/Legalize.zig");17pub const Legalize = @import("Air/Legalize.zig");
19pub const Liveness = @import("Air/Liveness.zig");18pub const Liveness = @import("Air/Liveness.zig");
19pub const Print = @import("Air/Print.zig");
20pub const Verify = @import("Air/Verify.zig");20pub const Verify = @import("Air/Verify.zig");
2121
22instructions: std.MultiArrayList(Inst).Slice,22instructions: std.MultiArrayList(Inst).Slice,
...@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index...@@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
2517}2517}
25182518
2519pub const legalize = Legalize.legalize;2519pub const legalize = Legalize.legalize;
2520pub const write = print.write;2520pub const write = Print.write;
2521pub const writeInst = print.writeInst;2521pub const writeInst = Print.writeInst;
2522pub const dump = print.dump;2522pub const dump = Print.dump;
2523pub const dumpInst = print.dumpInst;2523pub const dumpInst = Print.dumpInst;
25242524
2525pub const CoveragePoint = enum(u1) {2525pub const CoveragePoint = enum(u1) {
2526 /// Indicates the block is not a place of interest corresponding to2526 /// Indicates the block is not a place of interest corresponding to
src/Air/Print.zig created+1059
...@@ -0,0 +1,1059 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11const Printer = @This();
12
13zcu: *Zcu,
14fqn: InternPool.NullTerminatedString,
15air: *const Air,
16liveness: *const ?Air.Liveness,
17
18pub fn format(p: *const Printer, w: *std.Io.Writer) std.Io.Writer.Error!void {
19 try w.print("{qf}:\n", .{p.fqn.fmt(&p.zcu.intern_pool)});
20 try p.air.write(w, p.zcu, p.liveness.*);
21}
22
23pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void {
24 comptime assert(build_options.log_level == .debug);
25 const instruction_bytes = air.instructions.len *
26 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
27 // the debug safety tag but we want to measure release size.
28 (@sizeOf(Air.Inst.Tag) + 8);
29 const extra_bytes = air.extra.items.len * @sizeOf(u32);
30 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
31 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
32 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
33 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
34 @sizeOf(Air.Liveness) + liveness_extra_bytes +
35 liveness_special_bytes + tomb_bytes;
36
37 // zig fmt: off
38 try stream.print(
39 \\# Total AIR+Liveness bytes: {Bi}
40 \\# AIR Instructions: {d} ({Bi})
41 \\# AIR Extra Data: {d} ({Bi})
42 \\# Liveness tomb_bits: {Bi}
43 \\# Liveness Extra Data: {d} ({Bi})
44 \\# Liveness special table: {d} ({Bi})
45 \\
46 , .{
47 total_bytes,
48 air.instructions.len, instruction_bytes,
49 air.extra.items.len, extra_bytes,
50 tomb_bytes,
51 if (liveness) |l| l.extra.len else 0, liveness_extra_bytes,
52 if (liveness) |l| l.special.count() else 0, liveness_special_bytes,
53 });
54 // zig fmt: on
55
56 var writer: Writer = .{
57 .zcu = zcu,
58 .gpa = zcu.comp.gpa,
59 .air = air,
60 .liveness = liveness,
61 .indent = 2,
62 .skip_body = false,
63 };
64 try writer.writeBody(stream, air.getMainBody());
65}
66
67pub fn writeInst(
68 air: Air,
69 stream: *std.Io.Writer,
70 inst: Air.Inst.Index,
71 zcu: *Zcu,
72 liveness: ?Air.Liveness,
73) void {
74 comptime assert(build_options.log_level == .debug);
75 var writer: Writer = .{
76 .zcu = zcu,
77 .gpa = zcu.comp.gpa,
78 .air = air,
79 .liveness = liveness,
80 .indent = 2,
81 .skip_body = true,
82 };
83 writer.writeInst(stream, inst) catch return;
84}
85
86pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
87 var buffer: [4096]u8 = undefined;
88 const stderr = std.debug.lockStderr(&buffer);
89 defer std.debug.unlockStderr();
90 const w = &stderr.file_writer.interface;
91 air.write(w, pt, liveness) catch return;
92}
93
94pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
95 var buffer: [4096]u8 = undefined;
96 const stderr = std.debug.lockStderr(&buffer);
97 defer std.debug.unlockStderr();
98 const w = &stderr.file_writer.interface;
99 air.writeInst(w, inst, pt, liveness) catch return;
100}
101
102const Writer = struct {
103 zcu: *Zcu,
104 gpa: Allocator,
105 air: Air,
106 liveness: ?Air.Liveness,
107 indent: usize,
108 skip_body: bool,
109
110 const Error = std.Io.Writer.Error;
111
112 fn writeBody(w: *Writer, s: *std.Io.Writer, body: []const Air.Inst.Index) Error!void {
113 for (body) |inst| {
114 try w.writeInst(s, inst);
115 try s.writeByte('\n');
116 }
117 }
118
119 fn writeInst(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
120 const tag = w.air.instructions.items(.tag)[@backingInt(inst)];
121 try s.splatByteAll(' ', w.indent);
122 try s.print("{f}{c}= {s}(", .{
123 inst,
124 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
125 @tagName(tag),
126 });
127 switch (tag) {
128 .add,
129 .add_optimized,
130 .add_safe,
131 .add_wrap,
132 .add_sat,
133 .sub,
134 .sub_optimized,
135 .sub_safe,
136 .sub_wrap,
137 .sub_sat,
138 .mul,
139 .mul_optimized,
140 .mul_safe,
141 .mul_wrap,
142 .mul_sat,
143 .div_float,
144 .div_trunc,
145 .div_floor,
146 .div_ceil,
147 .div_exact,
148 .rem,
149 .mod,
150 .bit_and,
151 .bit_or,
152 .xor,
153 .cmp_lt,
154 .cmp_lte,
155 .cmp_eq,
156 .cmp_gte,
157 .cmp_gt,
158 .cmp_neq,
159 .store,
160 .store_safe,
161 .array_elem_val,
162 .slice_elem_val,
163 .ptr_elem_val,
164 .shl,
165 .shl_exact,
166 .shl_sat,
167 .shr,
168 .shr_exact,
169 .set_union_tag,
170 .min,
171 .max,
172 .div_float_optimized,
173 .div_trunc_optimized,
174 .div_floor_optimized,
175 .div_ceil_optimized,
176 .div_exact_optimized,
177 .rem_optimized,
178 .mod_optimized,
179 .cmp_lt_optimized,
180 .cmp_lte_optimized,
181 .cmp_eq_optimized,
182 .cmp_gte_optimized,
183 .cmp_gt_optimized,
184 .cmp_neq_optimized,
185 .memcpy,
186 .memmove,
187 .memset,
188 .memset_safe,
189 .legalize_vec_elem_val,
190 => try w.writeBinOp(s, inst),
191
192 .is_null,
193 .is_non_null,
194 .is_null_ptr,
195 .is_non_null_ptr,
196 .is_err,
197 .is_non_err,
198 .is_err_ptr,
199 .is_non_err_ptr,
200 .ret,
201 .ret_safe,
202 .ret_load,
203 .is_named_enum_value,
204 .tag_name,
205 .error_name,
206 .sqrt,
207 .sin,
208 .cos,
209 .tan,
210 .exp,
211 .exp2,
212 .log,
213 .log2,
214 .log10,
215 .floor,
216 .ceil,
217 .round,
218 .trunc_float,
219 .neg,
220 .neg_optimized,
221 .cmp_lte_errors_len,
222 .set_err_return_trace,
223 .c_va_end,
224 => try w.writeUnOp(s, inst),
225
226 .trap,
227 .breakpoint,
228 .dbg_empty_stmt,
229 .unreach,
230 .ret_addr,
231 .frame_addr,
232 .save_err_return_trace_index,
233 => try w.writeNoOp(s, inst),
234
235 .alloc,
236 .ret_ptr,
237 .err_return_trace,
238 .c_va_start,
239 => try w.writeTy(s, inst),
240
241 .arg => try w.writeArg(s, inst),
242
243 .not,
244 .bit_cast,
245 .bit_cast_safe,
246 .ptr_cast,
247 .ptr_from_int,
248 .int_from_ptr,
249 .error_cast,
250 .error_from_int,
251 .int_from_error,
252 .union_from_enum,
253 .load,
254 .fptrunc,
255 .fpext,
256 .int_cast,
257 .int_cast_safe,
258 .trunc,
259 .optional_payload,
260 .optional_payload_ptr,
261 .optional_payload_ptr_set,
262 .errunion_payload_ptr_set,
263 .wrap_optional,
264 .unwrap_errunion_payload,
265 .unwrap_errunion_err,
266 .unwrap_errunion_payload_ptr,
267 .unwrap_errunion_err_ptr,
268 .wrap_errunion_payload,
269 .wrap_errunion_err,
270 .slice_ptr,
271 .slice_len,
272 .ptr_slice_len_ptr,
273 .ptr_slice_ptr_ptr,
274 .struct_field_ptr_index_0,
275 .struct_field_ptr_index_1,
276 .struct_field_ptr_index_2,
277 .struct_field_ptr_index_3,
278 .array_to_slice,
279 .array_to_vector,
280 .float_from_int,
281 .splat,
282 .int_from_float,
283 .int_from_float_optimized,
284 .int_from_float_safe,
285 .int_from_float_optimized_safe,
286 .get_union_tag,
287 .clz,
288 .ctz,
289 .popcount,
290 .byte_swap,
291 .bit_reverse,
292 .abs,
293 .error_set_has_value,
294 .addrspace_cast,
295 .c_va_arg,
296 .c_va_copy,
297 => try w.writeTyOp(s, inst),
298
299 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
300
301 .loop => try w.writeLoop(s, inst),
302
303 .slice,
304 .slice_elem_ptr,
305 .ptr_elem_ptr,
306 .ptr_add,
307 .ptr_sub,
308 .add_with_overflow,
309 .sub_with_overflow,
310 .mul_with_overflow,
311 .shl_with_overflow,
312 => try w.writeTyPlBin(s, inst),
313
314 .call,
315 .call_always_tail,
316 .call_never_tail,
317 .call_never_inline,
318 => try w.writeCall(s, inst),
319
320 .dbg_var_ptr,
321 .dbg_var_val,
322 .dbg_arg_inline,
323 => try w.writeDbgVar(s, inst),
324
325 .struct_field_ptr => try w.writeStructField(s, inst),
326 .agg_field_val => try w.writeStructField(s, inst),
327 .spirv_runtime_array_len => try w.writeStructField(s, inst),
328 .inferred_alloc => @panic("TODO"),
329 .inferred_alloc_comptime => @panic("TODO"),
330 .assembly => try w.writeAssembly(s, inst),
331 .dbg_stmt => try w.writeDbgStmt(s, inst),
332
333 .aggregate_init => try w.writeAggregateInit(s, inst),
334 .union_init => try w.writeUnionInit(s, inst),
335 .br => try w.writeBr(s, inst),
336 .switch_dispatch => try w.writeBr(s, inst),
337 .repeat => try w.writeRepeat(s, inst),
338 .cond_br => try w.writeCondBr(s, inst),
339 .@"try", .try_cold => try w.writeTry(s, inst),
340 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
341 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
342 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
343 .atomic_load => try w.writeAtomicLoad(s, inst),
344 .prefetch => try w.writePrefetch(s, inst),
345 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
346 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
347 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
348 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
349 .atomic_rmw => try w.writeAtomicRmw(s, inst),
350 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
351 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
352 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
353 .mul_add => try w.writeMulAdd(s, inst),
354 .select => try w.writeSelect(s, inst),
355 .shuffle_one => try w.writeShuffleOne(s, inst),
356 .shuffle_two => try w.writeShuffleTwo(s, inst),
357 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
358 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
359 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
360 .legalize_vec_store_elem => try w.writeLegalizeVecStoreElem(s, inst),
361 .legalize_compiler_rt_call => try w.writeLegalizeCompilerRtCall(s, inst),
362
363 .work_item_id,
364 .work_group_size,
365 .work_group_id,
366 => try w.writeWorkDimension(s, inst),
367 }
368 try s.writeByte(')');
369 }
370
371 fn writeBinOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
372 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
373 try w.writeOperand(s, inst, 0, bin_op.lhs);
374 try s.writeAll(", ");
375 try w.writeOperand(s, inst, 1, bin_op.rhs);
376 }
377
378 fn writeUnOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
379 const un_op = w.air.instructions.items(.data)[@backingInt(inst)].un_op;
380 try w.writeOperand(s, inst, 0, un_op);
381 }
382
383 fn writeNoOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
384 _ = w;
385 _ = s;
386 _ = inst;
387 // no-op, no argument to write
388 }
389
390 fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void {
391 return ty.print(s, w.zcu, null);
392 }
393
394 fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
395 const ty = w.air.instructions.items(.data)[@backingInt(inst)].ty;
396 try w.writeType(s, ty);
397 }
398
399 fn writeArg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
400 const arg = w.air.instructions.items(.data)[@backingInt(inst)].arg;
401 try w.writeType(s, arg.ty);
402 try s.print(", {d}", .{arg.zir_param_index});
403 }
404
405 fn writeTyOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
406 const ty_op = w.air.instructions.items(.data)[@backingInt(inst)].ty_op;
407 try w.writeType(s, ty_op.ty);
408 try s.writeAll(", ");
409 try w.writeOperand(s, inst, 0, ty_op.operand);
410 }
411
412 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
413 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
414 try w.writeType(s, ty_pl.ty);
415
416 const body = switch (tag) {
417 .block => w.air.unwrapBlock(inst).body,
418 .dbg_inline_block => body: {
419 const dbg_block = w.air.unwrapDbgBlock(inst);
420 try s.writeAll(", ");
421 try w.writeInstRef(s, Air.internedToRef(dbg_block.func), false);
422 break :body dbg_block.body;
423 },
424 else => unreachable,
425 };
426 if (w.skip_body) return s.writeAll(", ...");
427 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
428 liveness.getBlock(inst)
429 else
430 .{ .deaths = &.{} };
431
432 try s.writeAll(", {\n");
433 const old_indent = w.indent;
434 w.indent += 2;
435 try w.writeBody(s, body);
436 w.indent = old_indent;
437 try s.splatByteAll(' ', w.indent);
438 try s.writeAll("}");
439
440 for (liveness_block.deaths) |operand| {
441 try s.print(" {f}!", .{operand});
442 }
443 }
444
445 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
446 const block = w.air.unwrapBlock(inst);
447
448 try w.writeType(s, block.ty);
449 if (w.skip_body) return s.writeAll(", ...");
450 try s.writeAll(", {\n");
451 const old_indent = w.indent;
452 w.indent += 2;
453 try w.writeBody(s, block.body);
454 w.indent = old_indent;
455 try s.splatByteAll(' ', w.indent);
456 try s.writeAll("}");
457 }
458
459 fn writeAggregateInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
460 const zcu = w.zcu;
461 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
462 const vector_ty = ty_pl.ty;
463 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
464 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
465
466 try w.writeType(s, vector_ty);
467 try s.writeAll(", [");
468 for (elements, 0..) |elem, i| {
469 if (i != 0) try s.writeAll(", ");
470 try w.writeOperand(s, inst, i, elem);
471 }
472 try s.writeAll("]");
473 }
474
475 fn writeUnionInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
476 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
477 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
478
479 try s.print("{d}, ", .{extra.field_index});
480 try w.writeOperand(s, inst, 0, extra.init);
481 }
482
483 fn writeStructField(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
484 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
485 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
486
487 try w.writeOperand(s, inst, 0, extra.struct_operand);
488 try s.print(", {d}", .{extra.field_index});
489 }
490
491 fn writeTyPlBin(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
492 const data = w.air.instructions.items(.data);
493 const ty_pl = data[@backingInt(inst)].ty_pl;
494 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
495
496 const inst_ty = data[@backingInt(inst)].ty_pl.ty;
497 try w.writeType(s, inst_ty);
498 try s.writeAll(", ");
499 try w.writeOperand(s, inst, 0, extra.lhs);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 1, extra.rhs);
502 }
503
504 fn writeCmpxchg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
505 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
506 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
507
508 try w.writeOperand(s, inst, 0, extra.ptr);
509 try s.writeAll(", ");
510 try w.writeOperand(s, inst, 1, extra.expected_value);
511 try s.writeAll(", ");
512 try w.writeOperand(s, inst, 2, extra.new_value);
513 try s.print(", {s}, {s}", .{
514 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
515 });
516 }
517
518 fn writeMulAdd(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
519 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
520 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
521
522 try w.writeOperand(s, inst, 0, extra.lhs);
523 try s.writeAll(", ");
524 try w.writeOperand(s, inst, 1, extra.rhs);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 2, pl_op.operand);
527 }
528
529 fn writeLegalizeVecStoreElem(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
530 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
531 const bin = w.air.extraData(Air.Bin, pl_op.payload).data;
532
533 try w.writeOperand(s, inst, 0, pl_op.operand);
534 try s.writeAll(", ");
535 try w.writeOperand(s, inst, 1, bin.lhs);
536 try s.writeAll(", ");
537 try w.writeOperand(s, inst, 2, bin.rhs);
538 }
539
540 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
541 const rt_call = w.air.unwrapCompilerRtCall(inst);
542 const args = rt_call.args;
543
544 try s.print("{t}, [", .{rt_call.func});
545 for (args, 0..) |arg, i| {
546 if (i != 0) try s.writeAll(", ");
547 try w.writeOperand(s, inst, i, arg);
548 }
549 try s.writeByte(']');
550 }
551
552 fn writeShuffleOne(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
553 const unwrapped = w.air.unwrapShuffleOne(w.zcu, inst);
554 try w.writeType(s, unwrapped.result_ty);
555 try s.writeAll(", ");
556 try w.writeOperand(s, inst, 0, unwrapped.operand);
557 try s.writeAll(", [");
558 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
559 if (mask_idx > 0) try s.writeAll(", ");
560 switch (mask_elem.unwrap()) {
561 .elem => |idx| try s.print("elem {d}", .{idx}),
562 .value => |val| try s.print("val {f}", .{Value.fromInterned(val).fmtValue(w.zcu)}),
563 }
564 }
565 try s.writeByte(']');
566 }
567
568 fn writeShuffleTwo(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
569 const unwrapped = w.air.unwrapShuffleTwo(w.zcu, inst);
570 try w.writeType(s, unwrapped.result_ty);
571 try s.writeAll(", ");
572 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
573 try s.writeAll(", ");
574 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
575 try s.writeAll(", [");
576 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
577 if (mask_idx > 0) try s.writeAll(", ");
578 switch (mask_elem.unwrap()) {
579 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
580 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
581 .undef => try s.writeAll("undef"),
582 }
583 }
584 try s.writeByte(']');
585 }
586
587 fn writeSelect(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
588 const zcu = w.zcu;
589 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
590 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
591
592 const elem_ty = w.typeOfIndex(inst).childType(zcu);
593 try w.writeType(s, elem_ty);
594 try s.writeAll(", ");
595 try w.writeOperand(s, inst, 0, pl_op.operand);
596 try s.writeAll(", ");
597 try w.writeOperand(s, inst, 1, extra.lhs);
598 try s.writeAll(", ");
599 try w.writeOperand(s, inst, 2, extra.rhs);
600 }
601
602 fn writeReduce(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
603 const reduce = w.air.instructions.items(.data)[@backingInt(inst)].reduce;
604
605 try w.writeOperand(s, inst, 0, reduce.operand);
606 try s.print(", {s}", .{@tagName(reduce.operation)});
607 }
608
609 fn writeCmpVector(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
610 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
611 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
612
613 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
614 try w.writeOperand(s, inst, 0, extra.lhs);
615 try s.writeAll(", ");
616 try w.writeOperand(s, inst, 1, extra.rhs);
617 }
618
619 fn writeRuntimeNavPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
620 const ip = &w.zcu.intern_pool;
621 const ty_nav = w.air.instructions.items(.data)[@backingInt(inst)].ty_nav;
622 try w.writeType(s, ty_nav.ty);
623 try s.print(", '{f}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
624 }
625
626 fn writeAtomicLoad(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
627 const atomic_load = w.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
628
629 try w.writeOperand(s, inst, 0, atomic_load.ptr);
630 try s.print(", {s}", .{@tagName(atomic_load.order)});
631 }
632
633 fn writePrefetch(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
634 const prefetch = w.air.instructions.items(.data)[@backingInt(inst)].prefetch;
635
636 try w.writeOperand(s, inst, 0, prefetch.ptr);
637 try s.print(", {s}, {d}, {s}", .{
638 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
639 });
640 }
641
642 fn writeAtomicStore(
643 w: *Writer,
644 s: *std.Io.Writer,
645 inst: Air.Inst.Index,
646 order: std.lang.AtomicOrder,
647 ) Error!void {
648 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
649 try w.writeOperand(s, inst, 0, bin_op.lhs);
650 try s.writeAll(", ");
651 try w.writeOperand(s, inst, 1, bin_op.rhs);
652 try s.print(", {s}", .{@tagName(order)});
653 }
654
655 fn writeAtomicRmw(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
656 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
657 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
658
659 try w.writeOperand(s, inst, 0, pl_op.operand);
660 try s.writeAll(", ");
661 try w.writeOperand(s, inst, 1, extra.operand);
662 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
663 }
664
665 fn writeFieldParentPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
666 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
667 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
668
669 try w.writeOperand(s, inst, 0, extra.field_ptr);
670 try s.print(", {d}", .{extra.field_index});
671 }
672
673 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
674 const unwrapped_asm = w.air.unwrapAsm(inst);
675 const is_volatile = unwrapped_asm.is_volatile;
676 var op_index: usize = 0;
677
678 const ret_ty = w.typeOfIndex(inst);
679 try w.writeType(s, ret_ty);
680
681 if (is_volatile) {
682 try s.writeAll(", volatile");
683 }
684
685 var it = unwrapped_asm.iterateOutputs();
686 while (it.next()) |out| {
687 const name = out.name;
688 const constraint = out.constraint;
689 if (out.operand == .none) {
690 try s.print(", [{s}] -> {s}", .{ name, constraint });
691 } else {
692 try s.print(", [{s}] out {s} = (", .{ name, constraint });
693 try w.writeOperand(s, inst, op_index, out.operand);
694 op_index += 1;
695 try s.writeByte(')');
696 }
697 }
698
699 it = unwrapped_asm.iterateInputs();
700 while (it.next()) |in| {
701 const name = in.name;
702 const constraint = in.constraint;
703 try s.print(", [{s}] in {s} = (", .{ name, constraint });
704 try w.writeOperand(s, inst, op_index, in.operand);
705 op_index += 1;
706 try s.writeByte(')');
707 }
708
709 const zcu = w.zcu;
710 const ip = &zcu.intern_pool;
711 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
712 const clobbers_ty = clobbers_val.typeOf(zcu);
713 var clobbers_bigint_buf: Value.BigIntSpace = undefined;
714 const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
715 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
716 assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
717 const limb_bits = @bitSizeOf(std.math.big.Limb);
718 if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
719 switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
720 0 => continue, // field is false
721 1 => {}, // field is true
722 }
723 const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
724 assert(clobber.len != 0);
725 try s.writeAll(", ~{");
726 try s.writeAll(clobber);
727 try s.writeAll("}");
728 }
729 const asm_source = unwrapped_asm.source;
730 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
731 }
732
733 fn writeDbgStmt(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
734 const dbg_stmt = w.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt;
735 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
736 }
737
738 fn writeDbgVar(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
739 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
740 try w.writeOperand(s, inst, 0, pl_op.operand);
741 const name: Air.NullTerminatedString = @fromBackingInt(@intCast(pl_op.payload));
742 try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))});
743 }
744
745 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
746 const call = w.air.unwrapCall(inst);
747 const args = call.args;
748 try w.writeOperand(s, inst, 0, call.callee);
749 try s.writeAll(", [");
750 for (args, 0..) |arg, i| {
751 if (i != 0) try s.writeAll(", ");
752 try w.writeOperand(s, inst, 1 + i, arg);
753 }
754 try s.writeAll("]");
755 }
756
757 fn writeBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
758 const br = w.air.instructions.items(.data)[@backingInt(inst)].br;
759 try w.writeInstIndex(s, br.block_inst, false);
760 try s.writeAll(", ");
761 try w.writeOperand(s, inst, 0, br.operand);
762 }
763
764 fn writeRepeat(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
765 const repeat = w.air.instructions.items(.data)[@backingInt(inst)].repeat;
766 try w.writeInstIndex(s, repeat.loop_inst, false);
767 }
768
769 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
770 const unwrapped_try = w.air.unwrapTry(inst);
771 const body = unwrapped_try.else_body;
772 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
773 liveness.getCondBr(inst)
774 else
775 .{ .then_deaths = &.{}, .else_deaths = &.{} };
776
777 try w.writeOperand(s, inst, 0, unwrapped_try.error_union);
778 if (w.skip_body) return s.writeAll(", ...");
779 try s.writeAll(", {\n");
780 const old_indent = w.indent;
781 w.indent += 2;
782
783 if (liveness_condbr.else_deaths.len != 0) {
784 try s.splatByteAll(' ', w.indent);
785 for (liveness_condbr.else_deaths, 0..) |operand, i| {
786 if (i != 0) try s.writeAll(" ");
787 try s.print("{f}!", .{operand});
788 }
789 try s.writeAll("\n");
790 }
791 try w.writeBody(s, body);
792
793 w.indent = old_indent;
794 try s.splatByteAll(' ', w.indent);
795 try s.writeAll("}");
796
797 for (liveness_condbr.then_deaths) |operand| {
798 try s.print(" {f}!", .{operand});
799 }
800 }
801
802 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
803 const unwrapped_try = w.air.unwrapTryPtr(inst);
804 const body = unwrapped_try.else_body;
805 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
806 liveness.getCondBr(inst)
807 else
808 .{ .then_deaths = &.{}, .else_deaths = &.{} };
809
810 try w.writeOperand(s, inst, 0, unwrapped_try.error_union_ptr);
811
812 try s.writeAll(", ");
813 try w.writeType(s, unwrapped_try.error_union_payload_ptr_ty);
814 if (w.skip_body) return s.writeAll(", ...");
815 try s.writeAll(", {\n");
816 const old_indent = w.indent;
817 w.indent += 2;
818
819 if (liveness_condbr.else_deaths.len != 0) {
820 try s.splatByteAll(' ', w.indent);
821 for (liveness_condbr.else_deaths, 0..) |operand, i| {
822 if (i != 0) try s.writeAll(" ");
823 try s.print("{f}!", .{operand});
824 }
825 try s.writeAll("\n");
826 }
827 try w.writeBody(s, body);
828
829 w.indent = old_indent;
830 try s.splatByteAll(' ', w.indent);
831 try s.writeAll("}");
832
833 for (liveness_condbr.then_deaths) |operand| {
834 try s.print(" {f}!", .{operand});
835 }
836 }
837
838 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
839 const cond_br = w.air.unwrapCondBr(inst);
840 const then_body = cond_br.then_body;
841 const else_body = cond_br.else_body;
842 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
843 liveness.getCondBr(inst)
844 else
845 .{ .then_deaths = &.{}, .else_deaths = &.{} };
846
847 try w.writeOperand(s, inst, 0, cond_br.condition);
848 if (w.skip_body) return s.writeAll(", ...");
849 try s.writeAll(",");
850 if (cond_br.branch_hints.true != .none) {
851 try s.print(" {s}", .{@tagName(cond_br.branch_hints.true)});
852 }
853 if (cond_br.branch_hints.then_cov != .none) {
854 try s.print(" {s}", .{@tagName(cond_br.branch_hints.then_cov)});
855 }
856 try s.writeAll(" {\n");
857 const old_indent = w.indent;
858 w.indent += 2;
859
860 if (liveness_condbr.then_deaths.len != 0) {
861 try s.splatByteAll(' ', w.indent);
862 for (liveness_condbr.then_deaths, 0..) |operand, i| {
863 if (i != 0) try s.writeAll(" ");
864 try s.print("{f}!", .{operand});
865 }
866 try s.writeAll("\n");
867 }
868
869 try w.writeBody(s, then_body);
870 try s.splatByteAll(' ', old_indent);
871 try s.writeAll("},");
872 if (cond_br.branch_hints.false != .none) {
873 try s.print(" {s}", .{@tagName(cond_br.branch_hints.false)});
874 }
875 if (cond_br.branch_hints.else_cov != .none) {
876 try s.print(" {s}", .{@tagName(cond_br.branch_hints.else_cov)});
877 }
878 try s.writeAll(" {\n");
879
880 if (liveness_condbr.else_deaths.len != 0) {
881 try s.splatByteAll(' ', w.indent);
882 for (liveness_condbr.else_deaths, 0..) |operand, i| {
883 if (i != 0) try s.writeAll(" ");
884 try s.print("{f}!", .{operand});
885 }
886 try s.writeAll("\n");
887 }
888
889 try w.writeBody(s, else_body);
890 w.indent = old_indent;
891
892 try s.splatByteAll(' ', old_indent);
893 try s.writeAll("}");
894 }
895
896 fn writeSwitchBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
897 const switch_br = w.air.unwrapSwitch(inst);
898
899 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
900 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
901 @panic("out of memory")
902 else blk: {
903 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
904 @panic("out of memory");
905 @memset(slice, &.{});
906 break :blk .{ .deaths = slice };
907 };
908 defer w.gpa.free(liveness.deaths);
909
910 try w.writeOperand(s, inst, 0, switch_br.operand);
911 if (w.skip_body) return s.writeAll(", ...");
912 const old_indent = w.indent;
913 w.indent += 2;
914
915 var it = switch_br.iterateCases();
916 while (it.next()) |case| {
917 try s.writeAll(", [");
918 for (case.items, 0..) |item, item_i| {
919 if (item_i != 0) try s.writeAll(", ");
920 try w.writeInstRef(s, item, false);
921 }
922 for (case.ranges, 0..) |range, range_i| {
923 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
924 try w.writeInstRef(s, range[0], false);
925 try s.writeAll("...");
926 try w.writeInstRef(s, range[1], false);
927 }
928 try s.writeAll("] ");
929 const hint = switch_br.getHint(case.idx);
930 if (hint != .none) {
931 try s.print(".{s} ", .{@tagName(hint)});
932 }
933 try s.writeAll("=> {\n");
934 w.indent += 2;
935
936 const deaths = liveness.deaths[case.idx];
937 if (deaths.len != 0) {
938 try s.splatByteAll(' ', w.indent);
939 for (deaths, 0..) |operand, i| {
940 if (i != 0) try s.writeAll(" ");
941 try s.print("{f}!", .{operand});
942 }
943 try s.writeAll("\n");
944 }
945
946 try w.writeBody(s, case.body);
947 w.indent -= 2;
948 try s.splatByteAll(' ', w.indent);
949 try s.writeAll("}");
950 }
951
952 const else_body = it.elseBody();
953 if (else_body.len != 0) {
954 try s.writeAll(", else ");
955 const hint = switch_br.getElseHint();
956 if (hint != .none) {
957 try s.print(".{s} ", .{@tagName(hint)});
958 }
959 try s.writeAll("=> {\n");
960 w.indent += 2;
961
962 const deaths = liveness.deaths[liveness.deaths.len - 1];
963 if (deaths.len != 0) {
964 try s.splatByteAll(' ', w.indent);
965 for (deaths, 0..) |operand, i| {
966 if (i != 0) try s.writeAll(" ");
967 try s.print("{f}!", .{operand});
968 }
969 try s.writeAll("\n");
970 }
971
972 try w.writeBody(s, else_body);
973 w.indent -= 2;
974 try s.splatByteAll(' ', w.indent);
975 try s.writeAll("}");
976 }
977
978 try s.writeAll("\n");
979 try s.splatByteAll(' ', old_indent);
980 }
981
982 fn writeWasmMemorySize(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
983 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
984 try s.print("{d}", .{pl_op.payload});
985 }
986
987 fn writeWasmMemoryGrow(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
988 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
989 try s.print("{d}, ", .{pl_op.payload});
990 try w.writeOperand(s, inst, 0, pl_op.operand);
991 }
992
993 fn writeWorkDimension(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
994 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
995 try s.print("{d}", .{pl_op.payload});
996 }
997
998 fn writeOperand(
999 w: *Writer,
1000 s: *std.Io.Writer,
1001 inst: Air.Inst.Index,
1002 op_index: usize,
1003 operand: Air.Inst.Ref,
1004 ) Error!void {
1005 const small_tomb_bits = Air.Liveness.bpi - 1;
1006 const dies = if (w.liveness) |liveness| blk: {
1007 if (op_index < small_tomb_bits)
1008 break :blk liveness.operandDies(inst, @intCast(op_index));
1009 var extra_index = liveness.special.get(inst).?;
1010 var tomb_op_index: usize = small_tomb_bits;
1011 while (true) {
1012 const bits = liveness.extra[extra_index];
1013 if (op_index < tomb_op_index + 31) {
1014 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
1015 }
1016 if ((bits >> 31) != 0) break :blk false;
1017 extra_index += 1;
1018 tomb_op_index += 31;
1019 }
1020 } else false;
1021 return w.writeInstRef(s, operand, dies);
1022 }
1023
1024 fn writeInstRef(
1025 w: *Writer,
1026 s: *std.Io.Writer,
1027 operand: Air.Inst.Ref,
1028 dies: bool,
1029 ) Error!void {
1030 if (@backingInt(operand) < InternPool.static_len) {
1031 return s.print("@{}", .{operand});
1032 } else if (operand.toInterned()) |ip_index| {
1033 const zcu = w.zcu;
1034 const ty = Type.fromInterned(zcu.intern_pool.indexToKey(ip_index).typeOf());
1035 try s.print("<{f}, {f}>", .{
1036 ty.fmt(zcu),
1037 Value.fromInterned(ip_index).fmtValue(w.zcu),
1038 });
1039 } else {
1040 return w.writeInstIndex(s, operand.toIndex().?, dies);
1041 }
1042 }
1043
1044 fn writeInstIndex(
1045 w: *Writer,
1046 s: *std.Io.Writer,
1047 inst: Air.Inst.Index,
1048 dies: bool,
1049 ) Error!void {
1050 _ = w;
1051 try s.print("{f}", .{inst});
1052 if (dies) try s.writeByte('!');
1053 }
1054
1055 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1056 const zcu = w.zcu;
1057 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1058 }
1059};
src/Air/print.zig deleted-1048
...@@ -1,1048 +0,0 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const assert = std.debug.assert;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11
12pub fn write(air: Air, stream: *std.Io.Writer, zcu: *Zcu, liveness: ?Air.Liveness) !void {
13 comptime assert(build_options.enable_debug_extensions);
14 const instruction_bytes = air.instructions.len *
15 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
16 // the debug safety tag but we want to measure release size.
17 (@sizeOf(Air.Inst.Tag) + 8);
18 const extra_bytes = air.extra.items.len * @sizeOf(u32);
19 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
20 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
21 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
22 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
23 @sizeOf(Air.Liveness) + liveness_extra_bytes +
24 liveness_special_bytes + tomb_bytes;
25
26 // zig fmt: off
27 try stream.print(
28 \\# Total AIR+Liveness bytes: {Bi}
29 \\# AIR Instructions: {d} ({Bi})
30 \\# AIR Extra Data: {d} ({Bi})
31 \\# Liveness tomb_bits: {Bi}
32 \\# Liveness Extra Data: {d} ({Bi})
33 \\# Liveness special table: {d} ({Bi})
34 \\
35 , .{
36 total_bytes,
37 air.instructions.len, instruction_bytes,
38 air.extra.items.len, extra_bytes,
39 tomb_bytes,
40 if (liveness) |l| l.extra.len else 0, liveness_extra_bytes,
41 if (liveness) |l| l.special.count() else 0, liveness_special_bytes,
42 });
43 // zig fmt: on
44
45 var writer: Writer = .{
46 .zcu = zcu,
47 .gpa = zcu.comp.gpa,
48 .air = air,
49 .liveness = liveness,
50 .indent = 2,
51 .skip_body = false,
52 };
53 try writer.writeBody(stream, air.getMainBody());
54}
55
56pub fn writeInst(
57 air: Air,
58 stream: *std.Io.Writer,
59 inst: Air.Inst.Index,
60 zcu: *Zcu,
61 liveness: ?Air.Liveness,
62) void {
63 comptime assert(build_options.enable_debug_extensions);
64 var writer: Writer = .{
65 .zcu = zcu,
66 .gpa = zcu.comp.gpa,
67 .air = air,
68 .liveness = liveness,
69 .indent = 2,
70 .skip_body = true,
71 };
72 writer.writeInst(stream, inst) catch return;
73}
74
75pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
76 var buffer: [4096]u8 = undefined;
77 const stderr = std.debug.lockStderr(&buffer);
78 defer std.debug.unlockStderr();
79 const w = &stderr.file_writer.interface;
80 air.write(w, pt, liveness) catch return;
81}
82
83pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
84 var buffer: [4096]u8 = undefined;
85 const stderr = std.debug.lockStderr(&buffer);
86 defer std.debug.unlockStderr();
87 const w = &stderr.file_writer.interface;
88 air.writeInst(w, inst, pt, liveness) catch return;
89}
90
91const Writer = struct {
92 zcu: *Zcu,
93 gpa: Allocator,
94 air: Air,
95 liveness: ?Air.Liveness,
96 indent: usize,
97 skip_body: bool,
98
99 const Error = std.Io.Writer.Error;
100
101 fn writeBody(w: *Writer, s: *std.Io.Writer, body: []const Air.Inst.Index) Error!void {
102 for (body) |inst| {
103 try w.writeInst(s, inst);
104 try s.writeByte('\n');
105 }
106 }
107
108 fn writeInst(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
109 const tag = w.air.instructions.items(.tag)[@backingInt(inst)];
110 try s.splatByteAll(' ', w.indent);
111 try s.print("{f}{c}= {s}(", .{
112 inst,
113 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
114 @tagName(tag),
115 });
116 switch (tag) {
117 .add,
118 .add_optimized,
119 .add_safe,
120 .add_wrap,
121 .add_sat,
122 .sub,
123 .sub_optimized,
124 .sub_safe,
125 .sub_wrap,
126 .sub_sat,
127 .mul,
128 .mul_optimized,
129 .mul_safe,
130 .mul_wrap,
131 .mul_sat,
132 .div_float,
133 .div_trunc,
134 .div_floor,
135 .div_ceil,
136 .div_exact,
137 .rem,
138 .mod,
139 .bit_and,
140 .bit_or,
141 .xor,
142 .cmp_lt,
143 .cmp_lte,
144 .cmp_eq,
145 .cmp_gte,
146 .cmp_gt,
147 .cmp_neq,
148 .store,
149 .store_safe,
150 .array_elem_val,
151 .slice_elem_val,
152 .ptr_elem_val,
153 .shl,
154 .shl_exact,
155 .shl_sat,
156 .shr,
157 .shr_exact,
158 .set_union_tag,
159 .min,
160 .max,
161 .div_float_optimized,
162 .div_trunc_optimized,
163 .div_floor_optimized,
164 .div_ceil_optimized,
165 .div_exact_optimized,
166 .rem_optimized,
167 .mod_optimized,
168 .cmp_lt_optimized,
169 .cmp_lte_optimized,
170 .cmp_eq_optimized,
171 .cmp_gte_optimized,
172 .cmp_gt_optimized,
173 .cmp_neq_optimized,
174 .memcpy,
175 .memmove,
176 .memset,
177 .memset_safe,
178 .legalize_vec_elem_val,
179 => try w.writeBinOp(s, inst),
180
181 .is_null,
182 .is_non_null,
183 .is_null_ptr,
184 .is_non_null_ptr,
185 .is_err,
186 .is_non_err,
187 .is_err_ptr,
188 .is_non_err_ptr,
189 .ret,
190 .ret_safe,
191 .ret_load,
192 .is_named_enum_value,
193 .tag_name,
194 .error_name,
195 .sqrt,
196 .sin,
197 .cos,
198 .tan,
199 .exp,
200 .exp2,
201 .log,
202 .log2,
203 .log10,
204 .floor,
205 .ceil,
206 .round,
207 .trunc_float,
208 .neg,
209 .neg_optimized,
210 .cmp_lte_errors_len,
211 .set_err_return_trace,
212 .c_va_end,
213 => try w.writeUnOp(s, inst),
214
215 .trap,
216 .breakpoint,
217 .dbg_empty_stmt,
218 .unreach,
219 .ret_addr,
220 .frame_addr,
221 .save_err_return_trace_index,
222 => try w.writeNoOp(s, inst),
223
224 .alloc,
225 .ret_ptr,
226 .err_return_trace,
227 .c_va_start,
228 => try w.writeTy(s, inst),
229
230 .arg => try w.writeArg(s, inst),
231
232 .not,
233 .bit_cast,
234 .bit_cast_safe,
235 .ptr_cast,
236 .ptr_from_int,
237 .int_from_ptr,
238 .error_cast,
239 .error_from_int,
240 .int_from_error,
241 .union_from_enum,
242 .load,
243 .fptrunc,
244 .fpext,
245 .int_cast,
246 .int_cast_safe,
247 .trunc,
248 .optional_payload,
249 .optional_payload_ptr,
250 .optional_payload_ptr_set,
251 .errunion_payload_ptr_set,
252 .wrap_optional,
253 .unwrap_errunion_payload,
254 .unwrap_errunion_err,
255 .unwrap_errunion_payload_ptr,
256 .unwrap_errunion_err_ptr,
257 .wrap_errunion_payload,
258 .wrap_errunion_err,
259 .slice_ptr,
260 .slice_len,
261 .ptr_slice_len_ptr,
262 .ptr_slice_ptr_ptr,
263 .struct_field_ptr_index_0,
264 .struct_field_ptr_index_1,
265 .struct_field_ptr_index_2,
266 .struct_field_ptr_index_3,
267 .array_to_slice,
268 .array_to_vector,
269 .float_from_int,
270 .splat,
271 .int_from_float,
272 .int_from_float_optimized,
273 .int_from_float_safe,
274 .int_from_float_optimized_safe,
275 .get_union_tag,
276 .clz,
277 .ctz,
278 .popcount,
279 .byte_swap,
280 .bit_reverse,
281 .abs,
282 .error_set_has_value,
283 .addrspace_cast,
284 .c_va_arg,
285 .c_va_copy,
286 => try w.writeTyOp(s, inst),
287
288 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
289
290 .loop => try w.writeLoop(s, inst),
291
292 .slice,
293 .slice_elem_ptr,
294 .ptr_elem_ptr,
295 .ptr_add,
296 .ptr_sub,
297 .add_with_overflow,
298 .sub_with_overflow,
299 .mul_with_overflow,
300 .shl_with_overflow,
301 => try w.writeTyPlBin(s, inst),
302
303 .call,
304 .call_always_tail,
305 .call_never_tail,
306 .call_never_inline,
307 => try w.writeCall(s, inst),
308
309 .dbg_var_ptr,
310 .dbg_var_val,
311 .dbg_arg_inline,
312 => try w.writeDbgVar(s, inst),
313
314 .struct_field_ptr => try w.writeStructField(s, inst),
315 .agg_field_val => try w.writeStructField(s, inst),
316 .spirv_runtime_array_len => try w.writeStructField(s, inst),
317 .inferred_alloc => @panic("TODO"),
318 .inferred_alloc_comptime => @panic("TODO"),
319 .assembly => try w.writeAssembly(s, inst),
320 .dbg_stmt => try w.writeDbgStmt(s, inst),
321
322 .aggregate_init => try w.writeAggregateInit(s, inst),
323 .union_init => try w.writeUnionInit(s, inst),
324 .br => try w.writeBr(s, inst),
325 .switch_dispatch => try w.writeBr(s, inst),
326 .repeat => try w.writeRepeat(s, inst),
327 .cond_br => try w.writeCondBr(s, inst),
328 .@"try", .try_cold => try w.writeTry(s, inst),
329 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
330 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
331 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
332 .atomic_load => try w.writeAtomicLoad(s, inst),
333 .prefetch => try w.writePrefetch(s, inst),
334 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
335 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
336 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
337 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
338 .atomic_rmw => try w.writeAtomicRmw(s, inst),
339 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
340 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
341 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
342 .mul_add => try w.writeMulAdd(s, inst),
343 .select => try w.writeSelect(s, inst),
344 .shuffle_one => try w.writeShuffleOne(s, inst),
345 .shuffle_two => try w.writeShuffleTwo(s, inst),
346 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
347 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
348 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
349 .legalize_vec_store_elem => try w.writeLegalizeVecStoreElem(s, inst),
350 .legalize_compiler_rt_call => try w.writeLegalizeCompilerRtCall(s, inst),
351
352 .work_item_id,
353 .work_group_size,
354 .work_group_id,
355 => try w.writeWorkDimension(s, inst),
356 }
357 try s.writeByte(')');
358 }
359
360 fn writeBinOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
361 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
362 try w.writeOperand(s, inst, 0, bin_op.lhs);
363 try s.writeAll(", ");
364 try w.writeOperand(s, inst, 1, bin_op.rhs);
365 }
366
367 fn writeUnOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
368 const un_op = w.air.instructions.items(.data)[@backingInt(inst)].un_op;
369 try w.writeOperand(s, inst, 0, un_op);
370 }
371
372 fn writeNoOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
373 _ = w;
374 _ = s;
375 _ = inst;
376 // no-op, no argument to write
377 }
378
379 fn writeType(w: *Writer, s: *std.Io.Writer, ty: Type) !void {
380 return ty.print(s, w.zcu, null);
381 }
382
383 fn writeTy(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
384 const ty = w.air.instructions.items(.data)[@backingInt(inst)].ty;
385 try w.writeType(s, ty);
386 }
387
388 fn writeArg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
389 const arg = w.air.instructions.items(.data)[@backingInt(inst)].arg;
390 try w.writeType(s, arg.ty);
391 try s.print(", {d}", .{arg.zir_param_index});
392 }
393
394 fn writeTyOp(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
395 const ty_op = w.air.instructions.items(.data)[@backingInt(inst)].ty_op;
396 try w.writeType(s, ty_op.ty);
397 try s.writeAll(", ");
398 try w.writeOperand(s, inst, 0, ty_op.operand);
399 }
400
401 fn writeBlock(w: *Writer, s: *std.Io.Writer, tag: Air.Inst.Tag, inst: Air.Inst.Index) Error!void {
402 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
403 try w.writeType(s, ty_pl.ty);
404
405 const body = switch (tag) {
406 .block => w.air.unwrapBlock(inst).body,
407 .dbg_inline_block => body: {
408 const dbg_block = w.air.unwrapDbgBlock(inst);
409 try s.writeAll(", ");
410 try w.writeInstRef(s, Air.internedToRef(dbg_block.func), false);
411 break :body dbg_block.body;
412 },
413 else => unreachable,
414 };
415 if (w.skip_body) return s.writeAll(", ...");
416 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
417 liveness.getBlock(inst)
418 else
419 .{ .deaths = &.{} };
420
421 try s.writeAll(", {\n");
422 const old_indent = w.indent;
423 w.indent += 2;
424 try w.writeBody(s, body);
425 w.indent = old_indent;
426 try s.splatByteAll(' ', w.indent);
427 try s.writeAll("}");
428
429 for (liveness_block.deaths) |operand| {
430 try s.print(" {f}!", .{operand});
431 }
432 }
433
434 fn writeLoop(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
435 const block = w.air.unwrapBlock(inst);
436
437 try w.writeType(s, block.ty);
438 if (w.skip_body) return s.writeAll(", ...");
439 try s.writeAll(", {\n");
440 const old_indent = w.indent;
441 w.indent += 2;
442 try w.writeBody(s, block.body);
443 w.indent = old_indent;
444 try s.splatByteAll(' ', w.indent);
445 try s.writeAll("}");
446 }
447
448 fn writeAggregateInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
449 const zcu = w.zcu;
450 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
451 const vector_ty = ty_pl.ty;
452 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
453 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
454
455 try w.writeType(s, vector_ty);
456 try s.writeAll(", [");
457 for (elements, 0..) |elem, i| {
458 if (i != 0) try s.writeAll(", ");
459 try w.writeOperand(s, inst, i, elem);
460 }
461 try s.writeAll("]");
462 }
463
464 fn writeUnionInit(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
465 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
466 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
467
468 try s.print("{d}, ", .{extra.field_index});
469 try w.writeOperand(s, inst, 0, extra.init);
470 }
471
472 fn writeStructField(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
473 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
474 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
475
476 try w.writeOperand(s, inst, 0, extra.struct_operand);
477 try s.print(", {d}", .{extra.field_index});
478 }
479
480 fn writeTyPlBin(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
481 const data = w.air.instructions.items(.data);
482 const ty_pl = data[@backingInt(inst)].ty_pl;
483 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
484
485 const inst_ty = data[@backingInt(inst)].ty_pl.ty;
486 try w.writeType(s, inst_ty);
487 try s.writeAll(", ");
488 try w.writeOperand(s, inst, 0, extra.lhs);
489 try s.writeAll(", ");
490 try w.writeOperand(s, inst, 1, extra.rhs);
491 }
492
493 fn writeCmpxchg(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
494 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
495 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
496
497 try w.writeOperand(s, inst, 0, extra.ptr);
498 try s.writeAll(", ");
499 try w.writeOperand(s, inst, 1, extra.expected_value);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 2, extra.new_value);
502 try s.print(", {s}, {s}", .{
503 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
504 });
505 }
506
507 fn writeMulAdd(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
508 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
509 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
510
511 try w.writeOperand(s, inst, 0, extra.lhs);
512 try s.writeAll(", ");
513 try w.writeOperand(s, inst, 1, extra.rhs);
514 try s.writeAll(", ");
515 try w.writeOperand(s, inst, 2, pl_op.operand);
516 }
517
518 fn writeLegalizeVecStoreElem(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
519 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
520 const bin = w.air.extraData(Air.Bin, pl_op.payload).data;
521
522 try w.writeOperand(s, inst, 0, pl_op.operand);
523 try s.writeAll(", ");
524 try w.writeOperand(s, inst, 1, bin.lhs);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 2, bin.rhs);
527 }
528
529 fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
530 const rt_call = w.air.unwrapCompilerRtCall(inst);
531 const args = rt_call.args;
532
533 try s.print("{t}, [", .{rt_call.func});
534 for (args, 0..) |arg, i| {
535 if (i != 0) try s.writeAll(", ");
536 try w.writeOperand(s, inst, i, arg);
537 }
538 try s.writeByte(']');
539 }
540
541 fn writeShuffleOne(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
542 const unwrapped = w.air.unwrapShuffleOne(w.zcu, inst);
543 try w.writeType(s, unwrapped.result_ty);
544 try s.writeAll(", ");
545 try w.writeOperand(s, inst, 0, unwrapped.operand);
546 try s.writeAll(", [");
547 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
548 if (mask_idx > 0) try s.writeAll(", ");
549 switch (mask_elem.unwrap()) {
550 .elem => |idx| try s.print("elem {d}", .{idx}),
551 .value => |val| try s.print("val {f}", .{Value.fromInterned(val).fmtValue(w.zcu)}),
552 }
553 }
554 try s.writeByte(']');
555 }
556
557 fn writeShuffleTwo(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
558 const unwrapped = w.air.unwrapShuffleTwo(w.zcu, inst);
559 try w.writeType(s, unwrapped.result_ty);
560 try s.writeAll(", ");
561 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
562 try s.writeAll(", ");
563 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
564 try s.writeAll(", [");
565 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
566 if (mask_idx > 0) try s.writeAll(", ");
567 switch (mask_elem.unwrap()) {
568 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
569 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
570 .undef => try s.writeAll("undef"),
571 }
572 }
573 try s.writeByte(']');
574 }
575
576 fn writeSelect(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
577 const zcu = w.zcu;
578 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
579 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
580
581 const elem_ty = w.typeOfIndex(inst).childType(zcu);
582 try w.writeType(s, elem_ty);
583 try s.writeAll(", ");
584 try w.writeOperand(s, inst, 0, pl_op.operand);
585 try s.writeAll(", ");
586 try w.writeOperand(s, inst, 1, extra.lhs);
587 try s.writeAll(", ");
588 try w.writeOperand(s, inst, 2, extra.rhs);
589 }
590
591 fn writeReduce(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
592 const reduce = w.air.instructions.items(.data)[@backingInt(inst)].reduce;
593
594 try w.writeOperand(s, inst, 0, reduce.operand);
595 try s.print(", {s}", .{@tagName(reduce.operation)});
596 }
597
598 fn writeCmpVector(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
599 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
600 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
601
602 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
603 try w.writeOperand(s, inst, 0, extra.lhs);
604 try s.writeAll(", ");
605 try w.writeOperand(s, inst, 1, extra.rhs);
606 }
607
608 fn writeRuntimeNavPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
609 const ip = &w.zcu.intern_pool;
610 const ty_nav = w.air.instructions.items(.data)[@backingInt(inst)].ty_nav;
611 try w.writeType(s, ty_nav.ty);
612 try s.print(", '{f}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
613 }
614
615 fn writeAtomicLoad(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
616 const atomic_load = w.air.instructions.items(.data)[@backingInt(inst)].atomic_load;
617
618 try w.writeOperand(s, inst, 0, atomic_load.ptr);
619 try s.print(", {s}", .{@tagName(atomic_load.order)});
620 }
621
622 fn writePrefetch(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
623 const prefetch = w.air.instructions.items(.data)[@backingInt(inst)].prefetch;
624
625 try w.writeOperand(s, inst, 0, prefetch.ptr);
626 try s.print(", {s}, {d}, {s}", .{
627 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
628 });
629 }
630
631 fn writeAtomicStore(
632 w: *Writer,
633 s: *std.Io.Writer,
634 inst: Air.Inst.Index,
635 order: std.lang.AtomicOrder,
636 ) Error!void {
637 const bin_op = w.air.instructions.items(.data)[@backingInt(inst)].bin_op;
638 try w.writeOperand(s, inst, 0, bin_op.lhs);
639 try s.writeAll(", ");
640 try w.writeOperand(s, inst, 1, bin_op.rhs);
641 try s.print(", {s}", .{@tagName(order)});
642 }
643
644 fn writeAtomicRmw(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
645 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
646 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
647
648 try w.writeOperand(s, inst, 0, pl_op.operand);
649 try s.writeAll(", ");
650 try w.writeOperand(s, inst, 1, extra.operand);
651 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
652 }
653
654 fn writeFieldParentPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
655 const ty_pl = w.air.instructions.items(.data)[@backingInt(inst)].ty_pl;
656 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
657
658 try w.writeOperand(s, inst, 0, extra.field_ptr);
659 try s.print(", {d}", .{extra.field_index});
660 }
661
662 fn writeAssembly(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
663 const unwrapped_asm = w.air.unwrapAsm(inst);
664 const is_volatile = unwrapped_asm.is_volatile;
665 var op_index: usize = 0;
666
667 const ret_ty = w.typeOfIndex(inst);
668 try w.writeType(s, ret_ty);
669
670 if (is_volatile) {
671 try s.writeAll(", volatile");
672 }
673
674 var it = unwrapped_asm.iterateOutputs();
675 while (it.next()) |out| {
676 const name = out.name;
677 const constraint = out.constraint;
678 if (out.operand == .none) {
679 try s.print(", [{s}] -> {s}", .{ name, constraint });
680 } else {
681 try s.print(", [{s}] out {s} = (", .{ name, constraint });
682 try w.writeOperand(s, inst, op_index, out.operand);
683 op_index += 1;
684 try s.writeByte(')');
685 }
686 }
687
688 it = unwrapped_asm.iterateInputs();
689 while (it.next()) |in| {
690 const name = in.name;
691 const constraint = in.constraint;
692 try s.print(", [{s}] in {s} = (", .{ name, constraint });
693 try w.writeOperand(s, inst, op_index, in.operand);
694 op_index += 1;
695 try s.writeByte(')');
696 }
697
698 const zcu = w.zcu;
699 const ip = &zcu.intern_pool;
700 const clobbers_val: Value = .fromInterned(unwrapped_asm.clobbers);
701 const clobbers_ty = clobbers_val.typeOf(zcu);
702 var clobbers_bigint_buf: Value.BigIntSpace = undefined;
703 const clobbers_bigint = clobbers_val.toBigInt(&clobbers_bigint_buf, zcu);
704 for (0..clobbers_ty.structFieldCount(zcu)) |field_index| {
705 assert(clobbers_ty.fieldType(field_index, zcu).toIntern() == .bool_type);
706 const limb_bits = @bitSizeOf(std.math.big.Limb);
707 if (field_index / limb_bits >= clobbers_bigint.limbs.len) continue; // field is false
708 switch (@as(u1, @truncate(clobbers_bigint.limbs[field_index / limb_bits] >> @intCast(field_index % limb_bits)))) {
709 0 => continue, // field is false
710 1 => {}, // field is true
711 }
712 const clobber = clobbers_ty.structFieldName(field_index, zcu).toSlice(ip).?;
713 assert(clobber.len != 0);
714 try s.writeAll(", ~{");
715 try s.writeAll(clobber);
716 try s.writeAll("}");
717 }
718 const asm_source = unwrapped_asm.source;
719 try s.print(", \"{f}\"", .{std.zig.fmtString(asm_source)});
720 }
721
722 fn writeDbgStmt(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
723 const dbg_stmt = w.air.instructions.items(.data)[@backingInt(inst)].dbg_stmt;
724 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
725 }
726
727 fn writeDbgVar(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
728 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
729 try w.writeOperand(s, inst, 0, pl_op.operand);
730 const name: Air.NullTerminatedString = @fromBackingInt(@intCast(pl_op.payload));
731 try s.print(", \"{f}\"", .{std.zig.fmtString(name.toSlice(w.air))});
732 }
733
734 fn writeCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
735 const call = w.air.unwrapCall(inst);
736 const args = call.args;
737 try w.writeOperand(s, inst, 0, call.callee);
738 try s.writeAll(", [");
739 for (args, 0..) |arg, i| {
740 if (i != 0) try s.writeAll(", ");
741 try w.writeOperand(s, inst, 1 + i, arg);
742 }
743 try s.writeAll("]");
744 }
745
746 fn writeBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
747 const br = w.air.instructions.items(.data)[@backingInt(inst)].br;
748 try w.writeInstIndex(s, br.block_inst, false);
749 try s.writeAll(", ");
750 try w.writeOperand(s, inst, 0, br.operand);
751 }
752
753 fn writeRepeat(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
754 const repeat = w.air.instructions.items(.data)[@backingInt(inst)].repeat;
755 try w.writeInstIndex(s, repeat.loop_inst, false);
756 }
757
758 fn writeTry(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
759 const unwrapped_try = w.air.unwrapTry(inst);
760 const body = unwrapped_try.else_body;
761 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
762 liveness.getCondBr(inst)
763 else
764 .{ .then_deaths = &.{}, .else_deaths = &.{} };
765
766 try w.writeOperand(s, inst, 0, unwrapped_try.error_union);
767 if (w.skip_body) return s.writeAll(", ...");
768 try s.writeAll(", {\n");
769 const old_indent = w.indent;
770 w.indent += 2;
771
772 if (liveness_condbr.else_deaths.len != 0) {
773 try s.splatByteAll(' ', w.indent);
774 for (liveness_condbr.else_deaths, 0..) |operand, i| {
775 if (i != 0) try s.writeAll(" ");
776 try s.print("{f}!", .{operand});
777 }
778 try s.writeAll("\n");
779 }
780 try w.writeBody(s, body);
781
782 w.indent = old_indent;
783 try s.splatByteAll(' ', w.indent);
784 try s.writeAll("}");
785
786 for (liveness_condbr.then_deaths) |operand| {
787 try s.print(" {f}!", .{operand});
788 }
789 }
790
791 fn writeTryPtr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
792 const unwrapped_try = w.air.unwrapTryPtr(inst);
793 const body = unwrapped_try.else_body;
794 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
795 liveness.getCondBr(inst)
796 else
797 .{ .then_deaths = &.{}, .else_deaths = &.{} };
798
799 try w.writeOperand(s, inst, 0, unwrapped_try.error_union_ptr);
800
801 try s.writeAll(", ");
802 try w.writeType(s, unwrapped_try.error_union_payload_ptr_ty);
803 if (w.skip_body) return s.writeAll(", ...");
804 try s.writeAll(", {\n");
805 const old_indent = w.indent;
806 w.indent += 2;
807
808 if (liveness_condbr.else_deaths.len != 0) {
809 try s.splatByteAll(' ', w.indent);
810 for (liveness_condbr.else_deaths, 0..) |operand, i| {
811 if (i != 0) try s.writeAll(" ");
812 try s.print("{f}!", .{operand});
813 }
814 try s.writeAll("\n");
815 }
816 try w.writeBody(s, body);
817
818 w.indent = old_indent;
819 try s.splatByteAll(' ', w.indent);
820 try s.writeAll("}");
821
822 for (liveness_condbr.then_deaths) |operand| {
823 try s.print(" {f}!", .{operand});
824 }
825 }
826
827 fn writeCondBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
828 const cond_br = w.air.unwrapCondBr(inst);
829 const then_body = cond_br.then_body;
830 const else_body = cond_br.else_body;
831 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
832 liveness.getCondBr(inst)
833 else
834 .{ .then_deaths = &.{}, .else_deaths = &.{} };
835
836 try w.writeOperand(s, inst, 0, cond_br.condition);
837 if (w.skip_body) return s.writeAll(", ...");
838 try s.writeAll(",");
839 if (cond_br.branch_hints.true != .none) {
840 try s.print(" {s}", .{@tagName(cond_br.branch_hints.true)});
841 }
842 if (cond_br.branch_hints.then_cov != .none) {
843 try s.print(" {s}", .{@tagName(cond_br.branch_hints.then_cov)});
844 }
845 try s.writeAll(" {\n");
846 const old_indent = w.indent;
847 w.indent += 2;
848
849 if (liveness_condbr.then_deaths.len != 0) {
850 try s.splatByteAll(' ', w.indent);
851 for (liveness_condbr.then_deaths, 0..) |operand, i| {
852 if (i != 0) try s.writeAll(" ");
853 try s.print("{f}!", .{operand});
854 }
855 try s.writeAll("\n");
856 }
857
858 try w.writeBody(s, then_body);
859 try s.splatByteAll(' ', old_indent);
860 try s.writeAll("},");
861 if (cond_br.branch_hints.false != .none) {
862 try s.print(" {s}", .{@tagName(cond_br.branch_hints.false)});
863 }
864 if (cond_br.branch_hints.else_cov != .none) {
865 try s.print(" {s}", .{@tagName(cond_br.branch_hints.else_cov)});
866 }
867 try s.writeAll(" {\n");
868
869 if (liveness_condbr.else_deaths.len != 0) {
870 try s.splatByteAll(' ', w.indent);
871 for (liveness_condbr.else_deaths, 0..) |operand, i| {
872 if (i != 0) try s.writeAll(" ");
873 try s.print("{f}!", .{operand});
874 }
875 try s.writeAll("\n");
876 }
877
878 try w.writeBody(s, else_body);
879 w.indent = old_indent;
880
881 try s.splatByteAll(' ', old_indent);
882 try s.writeAll("}");
883 }
884
885 fn writeSwitchBr(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
886 const switch_br = w.air.unwrapSwitch(inst);
887
888 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
889 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
890 @panic("out of memory")
891 else blk: {
892 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
893 @panic("out of memory");
894 @memset(slice, &.{});
895 break :blk .{ .deaths = slice };
896 };
897 defer w.gpa.free(liveness.deaths);
898
899 try w.writeOperand(s, inst, 0, switch_br.operand);
900 if (w.skip_body) return s.writeAll(", ...");
901 const old_indent = w.indent;
902 w.indent += 2;
903
904 var it = switch_br.iterateCases();
905 while (it.next()) |case| {
906 try s.writeAll(", [");
907 for (case.items, 0..) |item, item_i| {
908 if (item_i != 0) try s.writeAll(", ");
909 try w.writeInstRef(s, item, false);
910 }
911 for (case.ranges, 0..) |range, range_i| {
912 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
913 try w.writeInstRef(s, range[0], false);
914 try s.writeAll("...");
915 try w.writeInstRef(s, range[1], false);
916 }
917 try s.writeAll("] ");
918 const hint = switch_br.getHint(case.idx);
919 if (hint != .none) {
920 try s.print(".{s} ", .{@tagName(hint)});
921 }
922 try s.writeAll("=> {\n");
923 w.indent += 2;
924
925 const deaths = liveness.deaths[case.idx];
926 if (deaths.len != 0) {
927 try s.splatByteAll(' ', w.indent);
928 for (deaths, 0..) |operand, i| {
929 if (i != 0) try s.writeAll(" ");
930 try s.print("{f}!", .{operand});
931 }
932 try s.writeAll("\n");
933 }
934
935 try w.writeBody(s, case.body);
936 w.indent -= 2;
937 try s.splatByteAll(' ', w.indent);
938 try s.writeAll("}");
939 }
940
941 const else_body = it.elseBody();
942 if (else_body.len != 0) {
943 try s.writeAll(", else ");
944 const hint = switch_br.getElseHint();
945 if (hint != .none) {
946 try s.print(".{s} ", .{@tagName(hint)});
947 }
948 try s.writeAll("=> {\n");
949 w.indent += 2;
950
951 const deaths = liveness.deaths[liveness.deaths.len - 1];
952 if (deaths.len != 0) {
953 try s.splatByteAll(' ', w.indent);
954 for (deaths, 0..) |operand, i| {
955 if (i != 0) try s.writeAll(" ");
956 try s.print("{f}!", .{operand});
957 }
958 try s.writeAll("\n");
959 }
960
961 try w.writeBody(s, else_body);
962 w.indent -= 2;
963 try s.splatByteAll(' ', w.indent);
964 try s.writeAll("}");
965 }
966
967 try s.writeAll("\n");
968 try s.splatByteAll(' ', old_indent);
969 }
970
971 fn writeWasmMemorySize(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
972 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
973 try s.print("{d}", .{pl_op.payload});
974 }
975
976 fn writeWasmMemoryGrow(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
977 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
978 try s.print("{d}, ", .{pl_op.payload});
979 try w.writeOperand(s, inst, 0, pl_op.operand);
980 }
981
982 fn writeWorkDimension(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
983 const pl_op = w.air.instructions.items(.data)[@backingInt(inst)].pl_op;
984 try s.print("{d}", .{pl_op.payload});
985 }
986
987 fn writeOperand(
988 w: *Writer,
989 s: *std.Io.Writer,
990 inst: Air.Inst.Index,
991 op_index: usize,
992 operand: Air.Inst.Ref,
993 ) Error!void {
994 const small_tomb_bits = Air.Liveness.bpi - 1;
995 const dies = if (w.liveness) |liveness| blk: {
996 if (op_index < small_tomb_bits)
997 break :blk liveness.operandDies(inst, @intCast(op_index));
998 var extra_index = liveness.special.get(inst).?;
999 var tomb_op_index: usize = small_tomb_bits;
1000 while (true) {
1001 const bits = liveness.extra[extra_index];
1002 if (op_index < tomb_op_index + 31) {
1003 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
1004 }
1005 if ((bits >> 31) != 0) break :blk false;
1006 extra_index += 1;
1007 tomb_op_index += 31;
1008 }
1009 } else false;
1010 return w.writeInstRef(s, operand, dies);
1011 }
1012
1013 fn writeInstRef(
1014 w: *Writer,
1015 s: *std.Io.Writer,
1016 operand: Air.Inst.Ref,
1017 dies: bool,
1018 ) Error!void {
1019 if (@backingInt(operand) < InternPool.static_len) {
1020 return s.print("@{}", .{operand});
1021 } else if (operand.toInterned()) |ip_index| {
1022 const zcu = w.zcu;
1023 const ty = Type.fromInterned(zcu.intern_pool.indexToKey(ip_index).typeOf());
1024 try s.print("<{f}, {f}>", .{
1025 ty.fmt(zcu),
1026 Value.fromInterned(ip_index).fmtValue(w.zcu),
1027 });
1028 } else {
1029 return w.writeInstIndex(s, operand.toIndex().?, dies);
1030 }
1031 }
1032
1033 fn writeInstIndex(
1034 w: *Writer,
1035 s: *std.Io.Writer,
1036 inst: Air.Inst.Index,
1037 dies: bool,
1038 ) Error!void {
1039 _ = w;
1040 try s.print("{f}", .{inst});
1041 if (dies) try s.writeByte('!');
1042 }
1043
1044 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1045 const zcu = w.zcu;
1046 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1047 }
1048};
src/Compilation.zig+202-219
...@@ -147,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma...@@ -147,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma
147 pub fn values(_: @This()) [0]void {147 pub fn values(_: @This()) [0]void {
148 return .{};148 return .{};
149 }149 }
150 pub fn clearRetainingCapacity(_: @This()) void {}
150 pub fn deinit(_: @This(), _: Allocator) void {}151 pub fn deinit(_: @This(), _: Allocator) void {}
151} = .{},152} = .{},
152153
...@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,...@@ -161,12 +162,6 @@ clang_passthrough_mode: bool,
161clang_preprocessor_mode: ClangPreprocessorMode,162clang_preprocessor_mode: ClangPreprocessorMode,
162/// Whether to print clang argvs to stdout.163/// Whether to print clang argvs to stdout.
163verbose_cc: bool,164verbose_cc: bool,
164verbose_air: bool,
165verbose_intern_pool: bool,
166verbose_generic_instances: bool,
167verbose_llvm_ir: ?[]const u8,
168verbose_llvm_bc: ?[]const u8,
169verbose_llvm_cpu_features: bool,
170verbose_link: bool,165verbose_link: bool,
171link_depfile: ?[]const u8,166link_depfile: ?[]const u8,
172disable_c_depfile: bool,167disable_c_depfile: bool,
...@@ -243,8 +238,6 @@ reference_trace: ?u32 = null,...@@ -243,8 +238,6 @@ reference_trace: ?u32 = null,
243/// This mutex guards all `Compilation` mutable state.238/// This mutex guards all `Compilation` mutable state.
244mutex: std.Io.Mutex = .init,239mutex: std.Io.Mutex = .init,
245240
246test_filters: []const []const u8,
247
248link_prog_node: std.Progress.Node = .none,241link_prog_node: std.Progress.Node = .none,
249242
250llvm_opt_bisect_limit: c_int,243llvm_opt_bisect_limit: c_int,
...@@ -1544,13 +1537,7 @@ pub const CreateOptions = struct {...@@ -1544,13 +1537,7 @@ pub const CreateOptions = struct {
1544 clang_passthrough_mode: bool = false,1537 clang_passthrough_mode: bool = false,
1545 verbose_cc: bool = false,1538 verbose_cc: bool = false,
1546 verbose_link: bool = false,1539 verbose_link: bool = false,
1547 verbose_air: bool = false,
1548 verbose_intern_pool: bool = false,
1549 verbose_generic_instances: bool = false,
1550 verbose_llvm_ir: ?[]const u8 = null,
1551 verbose_llvm_bc: ?[]const u8 = null,
1552 link_depfile: ?[]const u8 = null,1540 link_depfile: ?[]const u8 = null,
1553 verbose_llvm_cpu_features: bool = false,
1554 debug_compiler_runtime_libs: ?std.lang.Optimize = null,1541 debug_compiler_runtime_libs: ?std.lang.Optimize = null,
1555 debug_compile_errors: bool = false,1542 debug_compile_errors: bool = false,
1556 debug_incremental: bool = false,1543 debug_incremental: bool = false,
...@@ -1646,28 +1633,11 @@ pub const CreateOptions = struct {...@@ -1646,28 +1633,11 @@ pub const CreateOptions = struct {
1646 };1633 };
1647};1634};
16481635
1649fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void {
1650 assert(zcu.module_roots.count() != 0); // module_roots is populated
1651
1652 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| {
1653 if (mod == zcu.std_mod) continue; // redundant
1654 if (opt_mod_root_file.unwrap()) |mod_root_file| {
1655 if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant
1656 }
1657 cache_helpers.addModule(hash, mod);
1658 hash.add(mod.root.root);
1659 hash.addBytes(mod.root.sub_path);
1660 hash.addBytes(mod.root_src_path);
1661 hash.addListOfBytes(mod.deps.keys());
1662 }
1663}
1664
1665const RtStrat = enum { none, lib, obj, zcu };1636const RtStrat = enum { none, lib, obj, zcu };
16661637
1667pub const CreateDiagnostic = union(enum) {1638pub const CreateDiagnostic = union(enum) {
1668 export_table_import_table_conflict,1639 export_table_import_table_conflict,
1669 emit_h_without_zcu,1640 emit_h_without_zcu,
1670 illegal_zig_import,
1671 cross_libc_unavailable,1641 cross_libc_unavailable,
1672 find_native_libc: std.zig.LibCInstallation.FindError,1642 find_native_libc: std.zig.LibCInstallation.FindError,
1673 libc_installation_missing_cc_dir,1643 libc_installation_missing_cc_dir,
...@@ -1683,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) {...@@ -1683,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) {
1683 switch (diag) {1653 switch (diag) {
1684 .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"),1654 .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"),
1685 .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"),1655 .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"),
1686 .illegal_zig_import => try w.writeAll("this compiler implementation does not support importing the root source file of a provided module"),
1687 .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"),1656 .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"),
1688 .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}),1657 .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}),
1689 .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"),1658 .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"),
...@@ -1731,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1731,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1731 const use_llvm = options.config.use_llvm;1700 const use_llvm = options.config.use_llvm;
1732 const target = &options.root_mod.resolved_target.result;1701 const target = &options.root_mod.resolved_target.result;
17331702
1734 const comp: *Compilation = comp: {1703 const comp = comp: {
1735 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.1704 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.
1736 // It's initialized later after we prepare the initialization options.1705 // It's initialized later after we prepare the initialization options.
1737 const root_name = try arena.dupeSentinel(u8, options.root_name, 0);1706 const root_name = try arena.dupeSentinel(u8, options.root_name, 0);
...@@ -1932,21 +1901,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1932,21 +1901,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1932 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);1901 try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod);
1933 }1902 }
19341903
1935 if (options.verbose_llvm_cpu_features) {
1936 if (options.root_mod.resolved_target.llvm_cpu_features) |cf| {
1937 const stderr = try io.lockStderr(&.{}, null);
1938 defer io.unlockStderr();
1939 const w = &stderr.file_writer.interface;
1940 printVerboseLlvmCpuFeatures(w, arena, options.root_name, target, cf) catch |err| switch (err) {
1941 error.WriteFailed => switch (stderr.file_writer.err.?) {
1942 error.Canceled => |e| return e,
1943 else => {},
1944 },
1945 error.OutOfMemory => |e| return e,
1946 };
1947 }
1948 }
1949
1950 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);1904 const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1);
1951 const main_mod = options.main_mod orelse options.root_mod;1905 const main_mod = options.main_mod orelse options.root_mod;
19521906
...@@ -2014,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2014,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2014 // TODO audit this and make sure everything is in it1968 // TODO audit this and make sure everything is in it
20151969
2016 const comp = try arena.create(Compilation);1970 const comp = try arena.create(Compilation);
2017 const opt_zcu: ?*Zcu = if (have_zcu) blk: {1971 const opt_zcu = if (have_zcu) blk: {
2018 // Pre-open the directory handles for cached ZIR code so that it does not need1972 // Pre-open the directory handles for cached ZIR code so that it does not need
2019 // to redundantly happen for each AstGen operation.1973 // to redundantly happen for each AstGen operation.
2020 const zir_sub_dir = "z";1974 const zir_sub_dir = "z";
...@@ -2067,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2067,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2067 zcu.* = .{2021 zcu.* = .{
2068 .gpa = gpa,2022 .gpa = gpa,
2069 .comp = comp,2023 .comp = comp,
2070 .main_mod = main_mod,2024 .llvm_object = null,
2025
2071 .root_mod = options.root_mod,2026 .root_mod = options.root_mod,
2027 .main_mod = main_mod,
2072 .std_mod = std_mod,2028 .std_mod = std_mod,
2029 .sema_prog_node = .none,
2030 .codegen_prog_node = .none,
2031 .pending_codegen_jobs = .init(0),
2032
2033 .cur_sema_prog_node = .none,
2034
2073 .global_zir_cache = global_zir_cache,2035 .global_zir_cache = global_zir_cache,
2074 .local_zir_cache = local_zir_cache,2036 .local_zir_cache = local_zir_cache,
2037
2038 .all_exports = .empty,
2039 .free_exports = .empty,
2040 .single_exports = .empty,
2041 .multi_exports = .empty,
2042
2043 .module_roots = .empty,
2044 .builtin_modules = .empty,
2045
2046 .import_table = .empty,
2047 .alive_files = .empty,
2048 .embed_table = .empty,
2049
2050 .intern_pool = .empty,
2051
2052 .compile_logs = .empty,
2053 .compile_log_lines = .empty,
2054 .free_compile_log_lines = .empty,
2055
2056 .illegal_module_root = null,
2057 .multi_module_err = null,
2058 .failed_imports = .empty,
2059 .failed_files = .empty,
2060 .skip_analysis_this_update = false,
2061 .analysis_in_progress = .empty,
2062 .failed_analysis = .empty,
2063 .transitive_failed_analysis = .empty,
2064 .dependency_loops = .empty,
2065 .dependency_loop_nodes = .empty,
2066 .failed_codegen = .empty,
2067 .failed_types = .empty,
2068 .failed_exports = .empty,
2069
2075 .error_limit = error_limit,2070 .error_limit = error_limit,
2076 .llvm_object = null,2071
2072 .outdated_lock = if (std.debug.runtime_safety) .init,
2073 .potentially_outdated = .empty,
2074 .outdated = .empty,
2075 .outdated_ready = .{
2076 .funcs = .empty,
2077 .other = .empty,
2078 },
2079 .retryable_failures = .empty,
2080
2077 .analysis_roots_buffer = undefined,2081 .analysis_roots_buffer = undefined,
2078 .analysis_roots_len = 0,2082 .analysis_roots_len = 0,
2083 .resolved_references = null,
2084
2085 .test_filters = options.test_filters,
2086 .test_functions = .empty,
2087
2088 .global_assembly = .empty,
2089
2090 .reference_table = .empty,
2091 .all_references = .empty,
2092 .free_references = .empty,
2093
2094 .inline_reference_frames = .empty,
2095 .free_inline_reference_frames = .empty,
2096
2097 .type_reference_table = .empty,
2098 .all_type_references = .empty,
2099 .free_type_references = .empty,
2100
2101 .std_lang_decl_values = .initFill(.none),
2102
2103 .incremental_debug_state = if (build_options.enable_debug_extensions) .init,
2104
2105 .cur_analysis_timer = null,
2106
2079 .codegen_task_pool = try .init(arena),2107 .codegen_task_pool = try .init(arena),
2108
2109 .generation = 0,
2110
2080 .anon_name_counter = 0,2111 .anon_name_counter = 0,
2081 };2112 };
2082 try zcu.init(gpa, io, options.thread_limit);
2083 break :blk zcu;2113 break :blk zcu;
2084 } else blk: {2114 } else blk: {
2085 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu);2115 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu);
...@@ -2111,19 +2141,12 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2111,19 +2141,12 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2111 .clang_passthrough_mode = options.clang_passthrough_mode,2141 .clang_passthrough_mode = options.clang_passthrough_mode,
2112 .clang_preprocessor_mode = options.clang_preprocessor_mode,2142 .clang_preprocessor_mode = options.clang_preprocessor_mode,
2113 .verbose_cc = options.verbose_cc,2143 .verbose_cc = options.verbose_cc,
2114 .verbose_air = options.verbose_air,
2115 .verbose_intern_pool = options.verbose_intern_pool,
2116 .verbose_generic_instances = options.verbose_generic_instances,
2117 .verbose_llvm_ir = options.verbose_llvm_ir,
2118 .verbose_llvm_bc = options.verbose_llvm_bc,
2119 .link_depfile = options.link_depfile,
2120 .verbose_llvm_cpu_features = options.verbose_llvm_cpu_features,
2121 .verbose_link = options.verbose_link,2144 .verbose_link = options.verbose_link,
2145 .link_depfile = options.link_depfile,
2122 .disable_c_depfile = options.disable_c_depfile,2146 .disable_c_depfile = options.disable_c_depfile,
2123 .reference_trace = options.reference_trace,2147 .reference_trace = options.reference_trace,
2124 .time_report = if (options.time_report) .init else null,2148 .time_report = if (options.time_report) .init else null,
2125 .stack_report = options.stack_report,2149 .stack_report = options.stack_report,
2126 .test_filters = options.test_filters,
2127 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,2150 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
2128 .debug_compile_errors = options.debug_compile_errors,2151 .debug_compile_errors = options.debug_compile_errors,
2129 .debug_incremental = options.debug_incremental,2152 .debug_incremental = options.debug_incremental,
...@@ -2175,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2175,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2175 comp.config.any_sanitize_c = any_sanitize_c;2198 comp.config.any_sanitize_c = any_sanitize_c;
2176 comp.config.any_fuzz = any_fuzz;2199 comp.config.any_fuzz = any_fuzz;
21772200
2178 if (opt_zcu) |zcu| {2201 // Initialize the `zcu` after the fields on `comp` have been initialized.
2179 // Finish initializing the `zcu` after the fields on `comp` have been initialized.2202 if (opt_zcu) |zcu| zcu.init();
2180 zcu.initAfterCompilation();
2181
2182 // Populate `zcu.module_roots`.
2183 const active = zcu.acquire();
2184 defer active.release();
2185 active.pt.populateModuleRootTable() catch |err| switch (err) {
2186 error.OutOfMemory => |e| return e,
2187 error.IllegalZigImport => return diag.fail(.illegal_zig_import),
2188 };
2189 }
21902203
2191 const lf_open_opts: link.File.OpenOptions = .{2204 const lf_open_opts: link.File.OpenOptions = .{
2192 .linker_script = options.linker_script,2205 .linker_script = options.linker_script,
...@@ -2282,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2282,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2282 hash.add(options.config.is_test);2295 hash.add(options.config.is_test);
2283 hash.addListOfBytes(options.test_filters);2296 hash.addListOfBytes(options.test_filters);
2284 hash.add(options.skip_linker_dependencies);2297 hash.add(options.skip_linker_dependencies);
2285 hash.add(options.emit_h != .no);2298 //hash.add(options.emit_h != .no);
2286 hash.add(error_limit);2299 hash.add(error_limit);
22872300
2288 // Here we put the root source file path name, but *not* with addFile.2301 try comp.addModuleTableToCacheHash(&hash);
2289 // We want the hash to be the same regardless of the contents of the
2290 // source file, because incremental compilation will handle it, but we
2291 // do want to namespace different source file names because they are
2292 // likely different compilations and therefore this would be likely to
2293 // cause cache hits.
2294 if (comp.zcu) |zcu| {
2295 try addModuleTableToCacheHash(zcu, &hash);
2296 } else {
2297 cache_helpers.addModule(&hash, options.root_mod);
2298 }
22992302
2300 // In the case of incremental cache mode, this `artifact_directory`2303 // In the case of incremental cache mode, this `artifact_directory`
2301 // is computed based on a hash of non-linker inputs, and it is where all2304 // is computed based on a hash of non-linker inputs, and it is where all
...@@ -2347,21 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2347,21 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2347 comp.cache_use = .{ .whole = whole };2350 comp.cache_use = .{ .whole = whole };
2348 },2351 },
2349 }2352 }
2350
2351 if (use_llvm and
2352 (comp.emit_bin != null or
2353 comp.emit_asm != null or
2354 comp.emit_llvm_ir != null or
2355 comp.emit_llvm_bc != null or
2356 comp.verbose_llvm_ir != null or
2357 comp.verbose_llvm_bc != null))
2358 {
2359 if (opt_zcu) |zcu| {
2360 dev.check(.llvm_backend);
2361 zcu.llvm_object = try LlvmObject.create(arena, zcu);
2362 }
2363 }
2364
2365 break :comp comp;2353 break :comp comp;
2366 };2354 };
2367 errdefer comp.destroy();2355 errdefer comp.destroy();
...@@ -2566,19 +2554,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2566,19 +2554,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2566 return comp;2554 return comp;
2567}2555}
25682556
2569fn printVerboseLlvmCpuFeatures(
2570 w: *Writer,
2571 arena: Allocator,
2572 root_name: []const u8,
2573 target: *const std.Target,
2574 cf: [*:0]const u8,
2575) (Writer.Error || Allocator.Error)!void {
2576 try w.print("compilation: {s}\n", .{root_name});
2577 try w.print(" target: {s}\n", .{try target.zigTriple(arena)});
2578 try w.print(" cpu: {s}\n", .{target.cpu.model.name});
2579 try w.print(" features: {s}\n", .{cf});
2580}
2581
2582pub fn destroy(comp: *Compilation) void {2557pub fn destroy(comp: *Compilation) void {
2583 const gpa = comp.gpa;2558 const gpa = comp.gpa;
2584 const io = comp.io;2559 const io = comp.io;
...@@ -2643,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void {...@@ -2643,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void {
2643 }2618 }
2644 comp.win32_resources.deinit(gpa);2619 comp.win32_resources.deinit(gpa);
26452620
2646 for (comp.failed_win32_resources.values()) |*value| {2621 for (comp.failed_win32_resources.values()) |*bundle| {
2647 value.deinit(gpa);2622 bundle.deinit(gpa);
2648 }2623 }
2649 comp.failed_win32_resources.deinit(gpa);2624 comp.failed_win32_resources.deinit(gpa);
26502625
...@@ -2668,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void {...@@ -2668,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void {
2668 comp.misc_failures = .{};2643 comp.misc_failures = .{};
2669}2644}
26702645
2671pub fn getTarget(self: *const Compilation) *const Target {2646pub fn getTarget(comp: *const Compilation) *const Target {
2672 return &self.root_mod.resolved_target.result;2647 return &comp.root_mod.resolved_target.result;
2673}2648}
26742649
2675/// Only legal to call when cache mode is incremental and a link file is present.2650/// Only legal to call when cache mode is incremental and a link file is present.
...@@ -2688,6 +2663,18 @@ pub fn hotCodeSwap(...@@ -2688,6 +2663,18 @@ pub fn hotCodeSwap(
2688fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {2663fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2689 const io = comp.io;2664 const io = comp.io;
26902665
2666 if (comp.bin_file) |lf| {
2667 lf.endProgress();
2668 comp.link_prog_node.end();
2669 comp.link_prog_node = .none;
2670 switch (comp.cache_use) {
2671 .none, .whole => {
2672 lf.destroy();
2673 comp.bin_file = null;
2674 },
2675 .incremental => {},
2676 }
2677 }
2691 switch (comp.cache_use) {2678 switch (comp.cache_use) {
2692 .none => |none| {2679 .none => |none| {
2693 if (none.tmp_artifact_directory) |*tmp_dir| {2680 if (none.tmp_artifact_directory) |*tmp_dir| {
...@@ -2704,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2704,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2704 // replicated in the output binary (the output instead contains a reference to that2691 // replicated in the output binary (the output instead contains a reference to that
2705 // file which debug tooling can look through). So, in that particular case, we need2692 // file which debug tooling can look through). So, in that particular case, we need
2706 // to keep this directory around so that the output binary can be debugged.2693 // to keep this directory around so that the output binary can be debugged.
2707 if (comp.bin_file != null and comp.getTarget().ofmt == .macho and comp.config.debug_format != .strip) {2694 if (comp.bin_file == null or comp.getTarget().ofmt != .macho or comp.config.debug_format == .strip) {
2708 // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU2695 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
2709 // object file must remain on-disk for its debug info.2696 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| {
2710 return;2697 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{
2698 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err,
2699 });
2700 };
2711 }2701 }
2712 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
2713 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| {
2714 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{
2715 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err,
2716 });
2717 };
2718 }2702 }
2719 },2703 },
2720 .incremental => return,2704 .incremental => return,
...@@ -2723,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2723,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2723 man.deinit();2707 man.deinit();
2724 whole.cache_manifest = null;2708 whole.cache_manifest = null;
2725 }2709 }
2726 if (comp.bin_file) |lf| {
2727 lf.destroy();
2728 comp.bin_file = null;
2729 }
2730 if (whole.tmp_artifact_directory) |*tmp_dir| {2710 if (whole.tmp_artifact_directory) |*tmp_dir| {
2731 tmp_dir.handle.close(io);2711 tmp_dir.handle.close(io);
2732 whole.tmp_artifact_directory = null;2712 whole.tmp_artifact_directory = null;
...@@ -2739,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2739,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2739 }2719 }
2740 },2720 },
2741 }2721 }
2722 assert(!comp.config.incremental); // always uses incremental cache mode
2723 if (comp.zcu) |zcu| {
2724 if (zcu.llvm_object) |llvm_object| {
2725 llvm_object.deinit();
2726 zcu.llvm_object = null;
2727 }
2728 }
2742}2729}
27432730
2744pub const UpdateError = error{2731pub const UpdateError = error{
...@@ -2760,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2760,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2760 defer arena_allocator.deinit();2747 defer arena_allocator.deinit();
2761 const arena = arena_allocator.allocator();2748 const arena = arena_allocator.allocator();
27622749
2763 comp.clearMiscFailures();2750 reset: {
2764 comp.last_update_was_cache_hit = false;2751 comp.clearMiscFailures();
2765 if (comp.time_report) |*tr| {2752 comp.last_update_was_cache_hit = false;
2766 tr.deinit(gpa); // this is information about an old update2753 if (comp.time_report) |*tr| {
2767 tr.* = .init;2754 tr.deinit(comp.gpa);
2755 tr.* = .init;
2756 }
2757 if (comp.file_system_inputs) |file_system_inputs| file_system_inputs.clearRetainingCapacity();
2758
2759 if (comp.zcu) |zcu| {
2760 zcu.skip_analysis_this_update = false;
2761 if (zcu.generation > 0) break :reset;
2762 try zcu.reset(arena);
2763 }
2764 for (comp.failed_c_objects.values()) |bundle| bundle.destroy(comp.gpa);
2765 comp.failed_c_objects.clearRetainingCapacity();
2766 for (comp.failed_win32_resources.values()) |*bundle| bundle.deinit(comp.gpa);
2767 comp.failed_win32_resources.clearRetainingCapacity();
2768 }2768 }
27692769
2770 var tmp_dir_rand_int: u64 = undefined;2770 var tmp_dir_rand_int: u64 = undefined;
...@@ -2909,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2909,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2909 if (comp.zcu) |zcu| {2909 if (comp.zcu) |zcu| {
2910 assert(zcu.cur_analysis_timer == null);2910 assert(zcu.cur_analysis_timer == null);
29112911
2912 zcu.skip_analysis_this_update = false;
2913
2914 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate!2912 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate!
2915 for (zcu.embed_table.keys()) |embed_file| {2913 for (zcu.embed_table.keys()) |embed_file| {
2916 try comp.appendFileSystemInput(embed_file.path);2914 try comp.appendFileSystemInput(embed_file.path);
2917 }2915 }
2918
2919 zcu.analysis_roots_len = 0;
2920
2921 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod;
2922 zcu.analysis_roots_len += 1;
2923
2924 // Normally we rely on importing std to in turn import the root source file in the start code.
2925 // However, the main module is distinct from the root module in tests, so that won't happen there.
2926 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) {
2927 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod;
2928 zcu.analysis_roots_len += 1;
2929 }
2930
2931 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2932 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod;
2933 zcu.analysis_roots_len += 1;
2934 }
2935
2936 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2937 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod;
2938 zcu.analysis_roots_len += 1;
2939 }
2940
2941 if (zcu.root_mod.deps.get("zigc")) |zigc_mod| {
2942 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod;
2943 zcu.analysis_roots_len += 1;
2944 }
2945 }2916 }
29462917
2947 // The linker progress node is set up here instead of in `performAllTheWork`, because2918 // The linker progress node is set up here instead of in `performAllTheWork`, because
...@@ -2963,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2963,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2963 comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total);2934 comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total);
2964 lf.startProgress(comp.link_prog_node);2935 lf.startProgress(comp.link_prog_node);
2965 }2936 }
2966 defer if (comp.bin_file) |lf| {
2967 lf.endProgress();
2968 comp.link_prog_node.end();
2969 comp.link_prog_node = .none;
2970 };
29712937
2972 try comp.performAllTheWork(main_progress_node, arena);2938 try comp.performAllTheWork(main_progress_node, arena);
29732939
...@@ -2991,14 +2957,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2991,14 +2957,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2991 try pt.processExports();2957 try pt.processExports();
2992 }2958 }
29932959
2994 if (build_options.enable_debug_extensions and comp.verbose_intern_pool) {2960 {
2995 std.debug.print("intern pool stats for {q}:\n", .{comp.root_name});2961 var d: InternPool.Dump = .{
2996 zcu.intern_pool.dump();2962 .name = comp.root_name,
2997 }2963 .arena = arena,
29982964 .ip = &zcu.intern_pool,
2999 if (build_options.enable_debug_extensions and comp.verbose_generic_instances) {2965 .err = null,
3000 std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) });2966 };
3001 zcu.intern_pool.dumpGenericInstances(gpa);2967 std.log.scoped(.@"ip-stats").debug("{f}", .{&d});
2968 if (d.err) |err| return err;
2969 std.log.scoped(.@"ip-values").debug("{f}", .{std.fmt.alt(&d, .formatAll)});
2970 if (d.err) |err| return err;
2971 std.log.scoped(.@"ip-generic-instances").debug("{f}", .{std.fmt.alt(&d, .formatGenericInstances)});
2972 if (d.err) |err| return err;
3002 }2973 }
3003 }2974 }
30042975
...@@ -3008,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3008,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3008 comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err});2979 comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err});
3009 };2980 };
30102981
3011 if (anyErrors(comp)) {2982 if (comp.anyErrors()) {
3012 // Skip flushing and keep source files loaded for error reporting.2983 // Skip flushing and keep source files loaded for error reporting.
3013 return;2984 return;
3014 }2985 }
...@@ -3022,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3022,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3022 }2993 }
30232994
3024 switch (comp.cache_use) {2995 switch (comp.cache_use) {
3025 .none, .incremental => try flush(comp, arena),2996 .none, .incremental => try comp.flush(arena),
3026 .whole => |whole| {2997 .whole => |whole| {
3027 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);2998 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
3028 if (comp.parent_whole_cache) |pwc| {2999 if (comp.parent_whole_cache) |pwc| {
...@@ -3103,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3103,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3103 };3074 };
3104 }3075 }
31053076
3106 try flush(comp, arena);3077 try comp.flush(arena);
31073078
3108 // Calling `flush` may have produced errors, in which case the3079 // Calling `flush` may have produced errors, in which case the
3109 // cache manifest must not be written.3080 // cache manifest must not be written.
3110 if (anyErrors(comp)) return;3081 if (comp.anyErrors()) return;
31113082
3112 // Release the lock and close the file before writing the manifest.3083 // Release the lock and close the file before writing the manifest.
3113 // This avoids the potential of another process getting a cache hit and3084 // This avoids the potential of another process getting a cache hit and
...@@ -3207,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3207,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3207 defer tid.release(io);3178 defer tid.release(io);
3208 if (comp.zcu) |zcu| {3179 if (comp.zcu) |zcu| {
3209 if (zcu.llvm_object) |llvm_object| {3180 if (zcu.llvm_object) |llvm_object| {
3210
3211 // Emit the ZCU object from LLVM now; it's required to flush the output file.3181 // Emit the ZCU object from LLVM now; it's required to flush the output file.
3212 // If there's an output file, it wants to decide where the LLVM object goes!3182 // If there's an output file, it wants to decide where the LLVM object goes!
3213 const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0);3183 const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0);
...@@ -3220,28 +3190,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3220,28 +3190,29 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3220 comp.time_report.?.stats.real_ns_llvm_emit = ns;3190 comp.time_report.?.stats.real_ns_llvm_emit = ns;
3221 };3191 };
32223192
3223 const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: {3193 const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) {
3224 break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename);3194 .llvmbc, .llvmir => null,
3225 } else null;3195 else => if (comp.bin_file != null)
3196 try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename)
3197 else
3198 null,
3199 };
32263200
3227 const active = zcu.activate(tid);3201 const active = zcu.activate(tid);
3228 defer active.deactivate();3202 defer active.deactivate();
3229 llvm_object.emit(active.pt, .{3203 llvm_object.emit(active.pt, .{
3230 .pre_ir_path = comp.verbose_llvm_ir,
3231 .pre_bc_path = comp.verbose_llvm_bc,
3232
3233 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,3204 .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null,
3234 .asm_path = p: {3205 .asm_path = p: {
3235 const raw = comp.emit_asm orelse break :p null;3206 const raw = comp.emit_asm orelse break :p null;
3236 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3207 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3237 break :p try p.toStringZ(arena);3208 break :p try p.toStringZ(arena);
3238 },3209 },
3239 .post_ir_path = p: {3210 .opt_ir_path = p: {
3240 const raw = comp.emit_llvm_ir orelse break :p null;3211 const raw = comp.emit_llvm_ir orelse break :p null;
3241 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3212 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3242 break :p try p.toStringZ(arena);3213 break :p try p.toStringZ(arena);
3243 },3214 },
3244 .post_bc_path = p: {3215 .opt_bc_path = p: {
3245 const raw = comp.emit_llvm_bc orelse break :p null;3216 const raw = comp.emit_llvm_bc orelse break :p null;
3246 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);3217 const p = try comp.resolveEmitPathFlush(arena, .artifact, raw);
3247 break :p try p.toStringZ(arena);3218 break :p try p.toStringZ(arena);
...@@ -3267,7 +3238,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3267,7 +3238,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3267 error.Canceled, error.OutOfMemory => |e| return e,3238 error.Canceled, error.OutOfMemory => |e| return e,
3268 error.AlreadyReported => return,3239 error.AlreadyReported => return,
3269 };3240 };
3270 }3241 } else return;
3271 }3242 }
3272 }3243 }
3273 if (comp.bin_file) |lf| {3244 if (comp.bin_file) |lf| {
...@@ -3341,23 +3312,42 @@ fn renameTmpIntoCache(...@@ -3341,23 +3312,42 @@ fn renameTmpIntoCache(
3341/// anything from the link cache manifest.3312/// anything from the link cache manifest.
3342pub const link_hash_implementation_version = 14;3313pub const link_hash_implementation_version = 14;
33433314
3344fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {3315fn addModuleTableToCacheHash(comp: *Compilation, hash: *Cache.HashHelper) Allocator.Error!void {
3345 comptime assert(link_hash_implementation_version == 14);3316 const gpa = comp.gpa;
3317 var mods: std.array_hash_map.Auto(*Module, void) = .empty;
3318 defer mods.deinit(gpa);
3319
3320 try mods.putNoClobber(gpa, comp.root_mod, {});
3321 if (comp.zcu) |zcu| try mods.put(gpa, zcu.main_mod, {});
3322
3323 var mod_index: usize = 0;
3324 while (mod_index < mods.count()) : (mod_index += 1) {
3325 const mod = mods.keys()[mod_index];
33463326
3347 if (comp.zcu) |zcu| {
3348 // No need to hash the actual file contents here because it is3327 // No need to hash the actual file contents here because it is
3349 // redundant with the logic in `PerThread.update` which iterates over3328 // redundant with the logic in `PerThread.update` which iterates over
3350 // `zcu.alive_files` and adds those files discovered via `@import` to3329 // `zcu.alive_files` and adds those files discovered via `@import` to
3351 // the whole cache manifest.3330 // the whole cache manifest.
3352 try addModuleTableToCacheHash(zcu, &man.hash);3331 cache_helpers.addModule(hash, mod);
3332 hash.add(mod.root.root);
3333 hash.addBytes(mod.root.sub_path);
3334 hash.addBytes(mod.root_src_path);
3335 hash.addListOfBytes(mod.deps.keys());
3336
3337 for (mod.deps.values()) |dep_mod| try mods.put(gpa, dep_mod, {});
3338 }
3339}
3340
3341fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
3342 comptime assert(link_hash_implementation_version == 14);
3343
3344 try comp.addModuleTableToCacheHash(&man.hash);
33533345
3346 if (comp.zcu) |zcu| {
3354 // Synchronize with other matching comments: ZigOnlyHashStuff3347 // Synchronize with other matching comments: ZigOnlyHashStuff
3355 man.hash.addListOfBytes(comp.test_filters);3348 man.hash.addListOfBytes(zcu.test_filters);
3356 man.hash.add(comp.skip_linker_dependencies);
3357 //man.hash.add(zcu.emit_h != .no);3349 //man.hash.add(zcu.emit_h != .no);
3358 man.hash.add(zcu.error_limit);3350 man.hash.add(zcu.error_limit);
3359 } else {
3360 cache_helpers.addModule(&man.hash, comp.root_mod);
3361 }3351 }
33623352
3363 try link.hashInputs(man, comp.link_inputs);3353 try link.hashInputs(man, comp.link_inputs);
...@@ -3826,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void {...@@ -3826,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void {
3826}3816}
38273817
3828/// This function is temporally single-threaded.3818/// This function is temporally single-threaded.
3829pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {3819pub fn getAllErrorsAlloc(comp: *Compilation) Allocator.Error!ErrorBundle {
3830 const gpa = comp.gpa;3820 const gpa = comp.gpa;
3831 const io = comp.io;3821 const io = comp.io;
38323822
...@@ -3869,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -3869,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
3869 }3859 }
38703860
3871 if (comp.zcu) |zcu| zcu_errors: {3861 if (comp.zcu) |zcu| zcu_errors: {
3862 if (zcu.illegal_module_root) |mod| {
3863 try bundle.addRootErrorMessage(.{
3864 .msg = try bundle.printString(
3865 "this compiler implementation does not support using '{f}/{s}' as the root of module '{s}'",
3866 .{ mod.root.fmt(comp), mod.root_src_path, mod.fully_qualified_name },
3867 ),
3868 .notes_len = 0,
3869 });
3870 }
3872 if (zcu.multi_module_err != null) {3871 if (zcu.multi_module_err != null) {
3873 try zcu.addFileInMultipleModulesError(&bundle);3872 try zcu.addFileInMultipleModulesError(&bundle);
3874 break :zcu_errors;3873 break :zcu_errors;
...@@ -4397,7 +4396,9 @@ fn performAllTheWork(...@@ -4397,7 +4396,9 @@ fn performAllTheWork(
4397 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu);4396 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu);
4398 if (comp.zcu) |zcu| {4397 if (comp.zcu) |zcu| {
4399 // Regardless of errors, `comp.zcu` needs to update its generation number.4398 // Regardless of errors, `comp.zcu` needs to update its generation number.
4400 defer zcu.generation += 1;4399 defer if (comp.config.incremental) {
4400 zcu.generation += 1;
4401 };
4401 const active = zcu.acquire();4402 const active = zcu.acquire();
4402 defer active.release();4403 defer active.release();
4403 try active.pt.update(main_progress_node, &decl_work_timer);4404 try active.pt.update(main_progress_node, &decl_work_timer);
...@@ -4903,12 +4904,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU...@@ -4903,12 +4904,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) SubU
4903 .emit_bin = .yes_cache,4904 .emit_bin = .yes_cache,
4904 .verbose_cc = comp.verbose_cc,4905 .verbose_cc = comp.verbose_cc,
4905 .verbose_link = comp.verbose_link,4906 .verbose_link = comp.verbose_link,
4906 .verbose_air = comp.verbose_air,
4907 .verbose_intern_pool = comp.verbose_intern_pool,
4908 .verbose_generic_instances = comp.verbose_intern_pool,
4909 .verbose_llvm_ir = comp.verbose_llvm_ir,
4910 .verbose_llvm_bc = comp.verbose_llvm_bc,
4911 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
4912 .environ_map = comp.environ_map,4907 .environ_map = comp.environ_map,
4913 }) catch |err| switch (err) {4908 }) catch |err| switch (err) {
4914 error.CreateFail => {4909 error.CreateFail => {
...@@ -7415,12 +7410,6 @@ fn buildOutputFromZig(...@@ -7415,12 +7410,6 @@ fn buildOutputFromZig(
7415 .data_sections = true,7410 .data_sections = true,
7416 .verbose_cc = comp.verbose_cc,7411 .verbose_cc = comp.verbose_cc,
7417 .verbose_link = comp.verbose_link,7412 .verbose_link = comp.verbose_link,
7418 .verbose_air = comp.verbose_air,
7419 .verbose_intern_pool = comp.verbose_intern_pool,
7420 .verbose_generic_instances = comp.verbose_intern_pool,
7421 .verbose_llvm_ir = comp.verbose_llvm_ir,
7422 .verbose_llvm_bc = comp.verbose_llvm_bc,
7423 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
7424 .clang_passthrough_mode = comp.clang_passthrough_mode,7413 .clang_passthrough_mode = comp.clang_passthrough_mode,
7425 .skip_linker_dependencies = true,7414 .skip_linker_dependencies = true,
7426 .environ_map = comp.environ_map,7415 .environ_map = comp.environ_map,
...@@ -7552,12 +7541,6 @@ pub fn build_crt_file(...@@ -7552,12 +7541,6 @@ pub fn build_crt_file(
7552 .c_source_files = c_source_files,7541 .c_source_files = c_source_files,
7553 .verbose_cc = comp.verbose_cc,7542 .verbose_cc = comp.verbose_cc,
7554 .verbose_link = comp.verbose_link,7543 .verbose_link = comp.verbose_link,
7555 .verbose_air = comp.verbose_air,
7556 .verbose_intern_pool = comp.verbose_intern_pool,
7557 .verbose_generic_instances = comp.verbose_generic_instances,
7558 .verbose_llvm_ir = comp.verbose_llvm_ir,
7559 .verbose_llvm_bc = comp.verbose_llvm_bc,
7560 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
7561 .clang_passthrough_mode = comp.clang_passthrough_mode,7544 .clang_passthrough_mode = comp.clang_passthrough_mode,
7562 .skip_linker_dependencies = true,7545 .skip_linker_dependencies = true,
7563 .environ_map = comp.environ_map,7546 .environ_map = comp.environ_map,
src/Compilation/Config.zig+4-4
...@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config {
190 // *If* the LLVM backend were to be selected, should Zig use the LLVM190 // *If* the LLVM backend were to be selected, should Zig use the LLVM
191 // library to build the LLVM module?191 // library to build the LLVM module?
192 const use_lib_llvm = b: {192 const use_lib_llvm = b: {
193 if (!build_options.have_llvm) {193 if (!build_options.have_llvm or target.ofmt == .llvmbc or target.ofmt == .llvmir) {
194 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;194 if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable;
195 break :b false;195 break :b false;
196 }196 }
...@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config {
324 if (!options.have_zcu) break :b false;324 if (!options.have_zcu) break :b false;
325325
326 // If emitting to LLVM bitcode object format, must use LLVM backend.326 // If emitting to LLVM bitcode object format, must use LLVM backend.
327 if (options.emit_llvm_ir or options.emit_llvm_bc) {327 if (target.ofmt == .llvmbc or target.ofmt == .llvmir or options.emit_llvm_bc or options.emit_llvm_ir) {
328 if (options.use_llvm == false)328 if (options.use_llvm == false)
329 return error.EmittingLlvmModuleRequiresLlvmBackend;329 return error.EmittingLlvmModuleRequiresLlvmBackend;
330 if (!target_util.hasLlvmSupport(target, target.ofmt))330 if (!target_util.hasLlvmSupport(target, target.ofmt))
...@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config {
379 const backend = target_util.zigBackend(target, use_llvm);379 const backend = target_util.zigBackend(target, use_llvm);
380380
381 if (options.emit_bin and options.have_zcu) {381 if (options.emit_bin and options.have_zcu) {
382 if (!use_lib_llvm and use_llvm) {382 if (target.ofmt != .llvmbc and target.ofmt != .llvmir and !use_lib_llvm and use_llvm) {
383 // Explicit request to use LLVM to produce an object file, but without383 // Explicit request to use LLVM to produce an object file, but without
384 // using LLVM libraries. Impossible.384 // using LLVM libraries. Impossible.
385 return error.EmittingBinaryRequiresLlvmLibrary;385 return error.EmittingBinaryRequiresLlvmLibrary;
...@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config {
513 break :b switch (target.ofmt) {513 break :b switch (target.ofmt) {
514 .elf, .macho, .wasm => .{ .dwarf = .@"32" },514 .elf, .macho, .wasm => .{ .dwarf = .@"32" },
515 .coff => .code_view,515 .coff => .code_view,
516 .c => switch (target.os.tag) {516 .c, .llvmbc, .llvmir => switch (target.os.tag) {
517 .windows, .uefi => .code_view,517 .windows, .uefi => .code_view,
518 else => .{ .dwarf = .@"32" },518 else => .{ .dwarf = .@"32" },
519 },519 },
src/InternPool.zig+36-25
...@@ -5255,6 +5255,7 @@ pub const Tag = enum(u8) {...@@ -5255,6 +5255,7 @@ pub const Tag = enum(u8) {
5255 type_hash: ?u64,5255 type_hash: ?u64,
5256 captures_len: ?u32,5256 captures_len: ?u32,
5257 captures: ?[]CaptureValue,5257 captures: ?[]CaptureValue,
5258 reified_field_name: ?[]NullTerminatedString,
5258 field_types: []Index,5259 field_types: []Index,
5259 field_aligns: ?[]Alignment,5260 field_aligns: ?[]Alignment,
5260 },5261 },
...@@ -5263,6 +5264,8 @@ pub const Tag = enum(u8) {...@@ -5263,6 +5264,8 @@ pub const Tag = enum(u8) {
5263 .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",5264 .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",
5264 .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",5265 .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",
5265 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",5266 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
5267 .@"trailing.reified_field_name.?" = .@"payload.flags.any_captures == .reified",
5268 .@"trailing.reified_field_name.?.len" = .@"payload.fields_len",
5266 .@"trailing.field_types.len" = .@"payload.fields_len",5269 .@"trailing.field_types.len" = .@"payload.fields_len",
5267 .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns",5270 .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns",
5268 .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) & ~@as(u32, 3)",5271 .@"trailing.field_aligns.?.len" = .@"(payload.fields_len + 3) & ~@as(u32, 3)",
...@@ -10588,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {...@@ -10588,17 +10591,36 @@ pub fn errorUnionPayload(ip: *const InternPool, ty: Index) Index {
10588 return ip.indexToKey(ty).error_union_type.payload_type;10591 return ip.indexToKey(ty).error_union_type.payload_type;
10589}10592}
1059010593
10591pub fn dump(ip: *const InternPool) void {10594pub const Dump = struct {
10592 var buffer: [4096]u8 = undefined;10595 name: []const u8,
10593 const stderr = std.debug.lockStderr(&buffer);10596 arena: std.mem.Allocator,
10594 defer std.debug.unlockStderr();10597 ip: *const InternPool,
10595 const w = &stderr.file_writer.interface;10598 err: ?Allocator.Error,
10596 dumpDependencyStatsFallible(ip, w) catch return;10599
10597 dumpStatsFallible(ip, w, std.heap.page_allocator) catch return;10600 pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10598 dumpAllFallible(ip, w) catch return;10601 try w.print("{q}:\n", .{d.name});
10599}10602 try d.ip.dumpDependencyStatsFallible(w);
10603 d.ip.dumpStatsFallible(d.arena, w) catch |err| switch (err) {
10604 error.WriteFailed => |e| return e,
10605 error.OutOfMemory => |e| {
10606 d.err = e;
10607 return error.WriteFailed;
10608 },
10609 };
10610 }
10611
10612 pub fn formatAll(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10613 try w.print("{q}:\n", .{d.name});
10614 try d.ip.dumpAllFallible(w);
10615 }
1060010616
10601fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {10617 pub fn formatGenericInstances(d: *Dump, w: *Io.Writer) Io.Writer.Error!void {
10618 try w.print("{q}:\n", .{d.name});
10619 d.ip.dumpGenericInstancesFallible(d.arena, w) catch return;
10620 }
10621};
10622
10623fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
10602 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;10624 const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len;
10603 const src_hash_deps_len = ip.src_hash_deps.count();10625 const src_hash_deps_len = ip.src_hash_deps.count();
10604 const nav_val_deps_len = ip.nav_val_deps.count();10626 const nav_val_deps_len = ip.nav_val_deps.count();
...@@ -10665,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {...@@ -10665,7 +10687,7 @@ fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) !void {
10665 });10687 });
10666}10688}
1066710689
10668fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void {10690fn dumpStatsFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) (Allocator.Error || Io.Writer.Error)!void {
10669 var items_len: usize = 0;10691 var items_len: usize = 0;
10670 var extra_len: usize = 0;10692 var extra_len: usize = 0;
10671 var limbs_len: usize = 0;10693 var limbs_len: usize = 0;
...@@ -10965,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -10965,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
10965 }10987 }
10966}10988}
1096710989
10968fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {10990fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void {
10969 for (ip.locals, 0..) |*local, tid| {10991 for (ip.locals, 0..) |*local, tid| {
10970 // Early check for length 0, because `view()` is invalid if capacity is 010992 // Early check for length 0, because `view()` is invalid if capacity is 0
10971 if (local.mutate.items.len == 0) continue;10993 if (local.mutate.items.len == 0) continue;
...@@ -11068,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {...@@ -11068,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
11068 }11090 }
11069}11091}
1107011092
11071pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) void {11093pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void {
11072 var buffer: [4096]u8 = undefined;
11073 const stderr = std.debug.lockStderr(&buffer);
11074 defer std.debug.unlockStderr();
11075 const w = &stderr.file_writer.interface;
11076 ip.dumpGenericInstancesFallible(allocator, w) catch return;
11077}
11078
11079pub fn dumpGenericInstancesFallible(ip: *const InternPool, allocator: Allocator, w: *Io.Writer) !void {
11080 var arena_allocator = std.heap.ArenaAllocator.init(allocator);
11081 defer arena_allocator.deinit();
11082 const arena = arena_allocator.allocator();
11083
11084 var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;11094 var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty;
11085 for (ip.locals, 0..) |*local, tid| {11095 for (ip.locals, 0..) |*local, tid| {
11096 if (local.mutate.items.len == 0) continue;
11086 const items = local.shared.items.view().slice();11097 const items = local.shared.items.view().slice();
11087 const extra_list = local.shared.extra;11098 const extra_list = local.shared.extra;
11088 for (11099 for (
src/Module.zig+8-11
...@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,...@@ -26,6 +26,7 @@ fully_qualified_name: []const u8,
26deps: Deps = .{},26deps: Deps = .{},
2727
28resolved_target: ResolvedTarget,28resolved_target: ResolvedTarget,
29llvm_cpu_features: ?[:0]const u8,
29optimize_mode: std.lang.Optimize,30optimize_mode: std.lang.Optimize,
30code_model: std.lang.CodeModel,31code_model: std.lang.CodeModel,
31single_threaded: bool,32single_threaded: bool,
...@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {...@@ -94,7 +95,6 @@ pub const ResolvedTarget = struct {
94 is_native_os: bool,95 is_native_os: bool,
95 is_native_abi: bool,96 is_native_abi: bool,
96 is_explicit_dynamic_linker: bool,97 is_explicit_dynamic_linker: bool,
97 llvm_cpu_features: ?[*:0]const u8 = null,
98};98};
9999
100pub const CreateError = error{100pub const CreateError = error{
...@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {...@@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
362 break :b 0;362 break :b 0;
363 };363 };
364364
365 const llvm_cpu_features: ?[*:0]const u8 = b: {365 const llvm_cpu_features: ?[:0]const u8 = b: {
366 if (resolved_target.llvm_cpu_features) |x| break :b x;
367 if (!options.global.use_llvm) break :b null;366 if (!options.global.use_llvm) break :b null;
367 if (options.inherited.resolved_target == null) break :b options.parent.?.llvm_cpu_features;
368368
369 // Append disabled features after enabled ones, so that their effects aren't overwritten.
369 var buf = std.array_list.Managed(u8).init(arena);370 var buf = std.array_list.Managed(u8).init(arena);
370 var disabled_features = std.array_list.Managed(u8).init(arena);371 var disabled_features = std.array_list.Managed(u8).init(arena);
371 defer disabled_features.deinit();
372
373 // Append disabled features after enabled ones, so that their effects aren't overwritten.
374 for (target.cpu.arch.allFeaturesList()) |feature| {372 for (target.cpu.arch.allFeaturesList()) |feature| {
375 if (feature.llvm_name) |llvm_name| {373 if (feature.llvm_name) |llvm_name| {
376 // Ignore these until we figure out how to handle the concept of omitting features.374 // 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 {...@@ -401,10 +399,9 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
401399
402 try buf.appendSlice(disabled_features.items);400 try buf.appendSlice(disabled_features.items);
403 if (buf.items.len == 0) break :b "";401 if (buf.items.len == 0) break :b "";
404 assert(std.mem.endsWith(u8, buf.items, ","));402 assert(buf.items[buf.items.len - 1] == ',');
405 buf.items[buf.items.len - 1] = 0;403 buf.items[buf.items.len - 1] = 0;
406 buf.shrinkAndFree(buf.items.len);404 break :b buf.items[0 .. buf.items.len - 1 :0];
407 break :b buf.items[0 .. buf.items.len - 1 :0].ptr;
408 };405 };
409406
410 const mod = try arena.create(Module);407 const mod = try arena.create(Module);
...@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {...@@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module {
417 .is_native_os = resolved_target.is_native_os,414 .is_native_os = resolved_target.is_native_os,
418 .is_native_abi = resolved_target.is_native_abi,415 .is_native_abi = resolved_target.is_native_abi,
419 .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,416 .is_explicit_dynamic_linker = resolved_target.is_explicit_dynamic_linker,
420 .llvm_cpu_features = llvm_cpu_features,
421 },417 },
418 .llvm_cpu_features = llvm_cpu_features,
422 .optimize_mode = optimize_mode,419 .optimize_mode = optimize_mode,
423 .single_threaded = single_threaded,420 .single_threaded = single_threaded,
424 .error_tracing = error_tracing,421 .error_tracing = error_tracing,
...@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)...@@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories)
494 .is_native_os = false,491 .is_native_os = false,
495 .is_native_abi = false,492 .is_native_abi = false,
496 .is_explicit_dynamic_linker = false,493 .is_explicit_dynamic_linker = false,
497 .llvm_cpu_features = null,
498 },494 },
495 .llvm_cpu_features = null,
499 .optimize_mode = opts.optimize_mode,496 .optimize_mode = opts.optimize_mode,
500 .single_threaded = opts.single_threaded,497 .single_threaded = opts.single_threaded,
501 .error_tracing = opts.error_tracing,498 .error_tracing = opts.error_tracing,
src/Sema.zig+22-6
...@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(...@@ -1126,6 +1126,8 @@ fn analyzeBodyInner(
1126 crash_info.push(sema, block, body);1126 crash_info.push(sema, block, body);
1127 defer crash_info.pop();1127 defer crash_info.pop();
11281128
1129 const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
1130
1129 // We use a while (true) loop here to avoid a redundant way of breaking out of1131 // We use a while (true) loop here to avoid a redundant way of breaking out of
1130 // the loop. The only way to break out of the loop is with a `noreturn`1132 // the loop. The only way to break out of the loop is with a `noreturn`
1131 // instruction.1133 // instruction.
...@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(...@@ -1134,11 +1136,7 @@ fn analyzeBodyInner(
1134 crash_info.setBodyIndex(i);1136 crash_info.setBodyIndex(i);
1135 const inst = body[i];1137 const inst = body[i];
11361138
1137 // This log is a bit expensive, and LLVM fails to optimize it away.1139 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
1138 if (build_options.enable_logging) {
1139 const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path;
1140 std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst });
1141 }
11421140
1143 const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {1141 const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) {
1144 // zig fmt: off1142 // zig fmt: off
...@@ -27920,7 +27918,25 @@ fn elemValSlice(...@@ -27920,7 +27918,25 @@ fn elemValSlice(
27920 }27918 }
27921 }27919 }
2792227920
27923 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);27921 switch (elem_ty.classify(zcu)) {
27922 .no_possible_value => switch (elem_ty.zigTypeTag(zcu)) {
27923 .@"opaque" => return sema.fail(block, src, "cannot load opaque type '{f}'", .{elem_ty.fmt(zcu)}),
27924 else => {
27925 // Loading an uninstantiable type always invokes Illegal Behavior.
27926 if (block.isComptime()) {
27927 return sema.fail(block, src, "cannot load uninstantiable type '{f}'", .{elem_ty.fmt(zcu)});
27928 } else if (block.wantSafety()) {
27929 try sema.safetyPanic(block, src, .load_uninstantiable_type);
27930 return .unreachable_value;
27931 } else {
27932 _ = try block.addNoOp(.unreach);
27933 return .unreachable_value;
27934 }
27935 },
27936 },
27937 .one_possible_value => return .fromValue((try elem_ty.onePossibleValue(pt)).?),
27938 .runtime, .partially_comptime, .fully_comptime => {},
27939 }
2792427940
27925 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src);27941 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src);
27926 try sema.validateRuntimeValue(block, slice_src, slice);27942 try sema.validateRuntimeValue(block, slice_src, slice);
src/Zcu.zig+250-156
...@@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit;...@@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit;
40const BuiltinFn = std.zig.BuiltinFn;40const BuiltinFn = std.zig.BuiltinFn;
41const codegen = @import("codegen.zig");41const codegen = @import("codegen.zig");
42const LlvmObject = @import("codegen/llvm.zig").Object;42const LlvmObject = @import("codegen/llvm.zig").Object;
43const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
43const dev = @import("dev.zig");44const dev = @import("dev.zig");
44const Zoir = std.zig.Zoir;45const Zoir = std.zig.Zoir;
45const ZonGen = std.zig.ZonGen;46const ZonGen = std.zig.ZonGen;
...@@ -69,18 +70,18 @@ root_mod: *Module,...@@ -69,18 +70,18 @@ root_mod: *Module,
69/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.70/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
70main_mod: *Module,71main_mod: *Module,
71std_mod: *Module,72std_mod: *Module,
72sema_prog_node: std.Progress.Node = .none,73sema_prog_node: std.Progress.Node,
73codegen_prog_node: std.Progress.Node = .none,74codegen_prog_node: std.Progress.Node,
74/// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value75/// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value
75/// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this76/// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this
76/// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is77/// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is
77/// completed (since semantic analysis could trigger more codegen work).78/// completed (since semantic analysis could trigger more codegen work).
78pending_codegen_jobs: std.atomic.Value(u32) = .init(0),79pending_codegen_jobs: std.atomic.Value(u32),
7980
80/// This is the progress node *under* `sema_prog_node` which is currently running.81/// This is the progress node *under* `sema_prog_node` which is currently running.
81/// When we have to pause to analyze something else, we just temporarily rename this node.82/// When we have to pause to analyze something else, we just temporarily rename this node.
82/// Eventually, when we thread semantic analysis, we will want one of these per thread.83/// Eventually, when we thread semantic analysis, we will want one of these per thread.
83cur_sema_prog_node: std.Progress.Node = .none,84cur_sema_prog_node: std.Progress.Node,
8485
85/// Used by AstGen worker to load and store ZIR cache.86/// Used by AstGen worker to load and store ZIR cache.
86global_zir_cache: Cache.Directory,87global_zir_cache: Cache.Directory,
...@@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory,...@@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory,
8990
90/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;91/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
91/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.92/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
92all_exports: std.ArrayList(Export) = .empty,93all_exports: std.ArrayList(Export),
93/// This is a list of free indices in `all_exports`. These indices may be reused by exports from94/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
94/// future semantic analysis.95/// future semantic analysis.
95free_exports: std.ArrayList(Export.Index) = .empty,96free_exports: std.ArrayList(Export.Index),
96/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of97/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
97/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`98/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
98/// whose analysis triggered the export.99/// whose analysis triggered the export.
99single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty,100single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index),
100/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.101/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
101/// The exports are `all_exports.items[index..][0..len]`.102/// The exports are `all_exports.items[index..][0..len]`.
102multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct {103multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct {
103 index: u32,104 index: u32,
104 len: u32,105 len: u32,
105}) = .empty,106}),
106
107/// Key is the digest returned by `Builtin.hash`; value is the corresponding module.
108builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module) = .empty,
109107
110/// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones.108/// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones.
111/// Modules whose root file is not a Zig or ZON file have the value `.none`.109/// Modules whose root file is not a Zig or ZON file have the value `.none`.
112module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional) = .empty,110module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional),
111/// Key is the digest returned by `Builtin.hash`; value is the corresponding module.
112builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module),
113113
114/// The set of all the Zig source files in the Zig Compilation Unit. Tracked in114/// The set of all the Zig source files in the Zig Compilation Unit. Tracked in
115/// order to iterate over it and check which source files have been modified on115/// 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(...@@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom(
132 pub const eql = @compileError("all accesses should be through ImportTableAdapter");132 pub const eql = @compileError("all accesses should be through ImportTableAdapter");
133 },133 },
134 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918134 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
135) = .empty,135),
136
137/// The set of all files in `import_table` which are "alive" this update, meaning136/// The set of all files in `import_table` which are "alive" this update, meaning
138/// they are reachable by traversing imports starting from an analysis root. This137/// they are reachable by traversing imports starting from an analysis root. This
139/// is usually all files in `import_table`, but some could be omitted if an incremental138/// is usually all files in `import_table`, but some could be omitted if an incremental
140/// update removes an import, or if a module specified on the CLI is never imported.139/// update removes an import, or if a module specified on the CLI is never imported.
141/// Reconstructed on every update, after AstGen and before Sema.140/// Reconstructed on every update, after AstGen and before Sema.
142/// Value is why the file is alive.141/// Value is why the file is alive.
143alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty,142alive_files: std.array_hash_map.Auto(File.Index, File.Reference),
144
145/// If this is populated, a "file exists in multiple modules" error should be emitted.
146/// This causes file errors to not be shown, because we don't really know which files
147/// should be alive (because the user has messed up their imports somewhere!).
148/// Cleared and recomputed every update, after AstGen and before Sema.
149multi_module_err: ?struct {
150 file: File.Index,
151 modules: [2]*Module,
152 refs: [2]File.Reference,
153} = null,
154
155/// The set of all the files which have been loaded with `@embedFile` in the Module.143/// The set of all the files which have been loaded with `@embedFile` in the Module.
156/// We keep track of this in order to iterate over it and check which files have been144/// We keep track of this in order to iterate over it and check which files have been
157/// modified on the file system when an update is requested, as well as to cache145/// modified on the file system when an update is requested, as well as to cache
...@@ -162,49 +150,19 @@ multi_module_err: ?struct {...@@ -162,49 +150,19 @@ multi_module_err: ?struct {
162///150///
163/// This table owns all of the `*EmbedFile` memory, which is allocated into gpa.151/// This table owns all of the `*EmbedFile` memory, which is allocated into gpa.
164embed_table: std.array_hash_map.Custom(152embed_table: std.array_hash_map.Custom(
165 *EmbedFile,153 EmbedFile,
166 void,154 void,
167 struct {155 struct {
168 pub const hash = @compileError("all accesses should be through EmbedTableAdapter");156 pub const hash = @compileError("all accesses should be through EmbedTableAdapter");
169 pub const eql = @compileError("all accesses should be through EmbedTableAdapter");157 pub const eql = @compileError("all accesses should be through EmbedTableAdapter");
170 },158 },
171 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918159 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
172) = .empty,160),
173161
174/// Stores all Type and Value objects.162/// Stores all Type and Value objects.
175/// The idea is that this will be periodically garbage-collected, but such logic163/// The idea is that this will be periodically garbage-collected, but such logic
176/// is not yet implemented.164/// is not yet implemented.
177intern_pool: InternPool = .empty,165intern_pool: InternPool,
178
179/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
180/// (index 0), and non-`null` for all others.
181analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason) = .empty,
182/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
183failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty,
184/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
185transitive_failed_analysis: std.array_hash_map.Auto(
186 AnalUnit,
187 if (build_options.enable_debug_extensions) TransitiveFailureReason else void,
188) = .empty,
189/// This `Nav` succeeded analysis, but failed codegen.
190/// This may be a simple "value" `Nav`, or it may be a function.
191/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
192/// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as
193/// codegen and linking run on a separate thread.
194failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty,
195failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg) = .empty,
196
197/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
198/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
199/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
200/// this map simply exists to allow easily iterating all dependency loops exactly once.
201dependency_loops: std.array_hash_map.Auto(AnalUnit, void) = .empty,
202/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
203/// All units in here form loops. To iterate loops, see `dependency_loops`.
204dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct {
205 unit: AnalUnit,
206 reason: DependencyReason,
207}) = .empty,
208166
209/// Keep track of `@compileLog`s per `AnalUnit`.167/// Keep track of `@compileLog`s per `AnalUnit`.
210/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.168/// 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 {...@@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct {
220 .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),178 .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),
221 };179 };
222 }180 }
223}) = .empty,181}),
224compile_log_lines: std.ArrayList(CompileLogLine) = .empty,182compile_log_lines: std.ArrayList(CompileLogLine),
225free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty,183free_compile_log_lines: std.ArrayList(CompileLogLine.Index),
226/// This tracks files which triggered errors when generating AST/ZIR/ZOIR.184
227/// If not `null`, the value is a retryable error (the file status is guaranteed185illegal_module_root: ?*Module,
228/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure`186/// If this is populated, a "file exists in multiple modules" error should be emitted.
229/// or `.success`, and there are ZIR/ZOIR errors which should be printed.187/// This causes file errors to not be shown, because we don't really know which files
230/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source188/// should be alive (because the user has messed up their imports somewhere!).
231/// location is always the entire file. The `[]u8` memory is owned by the map189/// Cleared and recomputed every update, after AstGen and before Sema.
232/// and allocated into `gpa`.190multi_module_err: ?struct {
233failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty,191 file: File.Index,
192 modules: [2]*Module,
193 refs: [2]File.Reference,
194},
234/// AstGen is not aware of modules, and so cannot determine whether an import195/// AstGen is not aware of modules, and so cannot determine whether an import
235/// string makes sense. That is the job of a traversal after AstGen.196/// string makes sense. That is the job of a traversal after AstGen.
236///197///
...@@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct {...@@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct {
257 import_string: Zir.NullTerminatedString,218 import_string: Zir.NullTerminatedString,
258 import_token: Ast.TokenIndex,219 import_token: Ast.TokenIndex,
259 kind: enum { file_outside_module_root, illegal_zig_import },220 kind: enum { file_outside_module_root, illegal_zig_import },
260}) = .empty,221}),
261failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty,222/// This tracks files which triggered errors when generating AST/ZIR/ZOIR.
262/// If analysis failed due to a cimport error, the corresponding Clang errors223/// If not `null`, the value is a retryable error (the file status is guaranteed
263/// are stored here.224/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure`
264cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty,225/// or `.success`, and there are ZIR/ZOIR errors which should be printed.
226/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source
227/// location is always the entire file. The `[]u8` memory is owned by the map
228/// and allocated into `gpa`.
229failed_files: std.array_hash_map.Auto(File.Index, ?[]u8),
230/// If `true`, then semantic analysis must not occur on this update due to AstGen errors.
231/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped.
232/// Reset to `false` at the start of each update in `Compilation.update`.
233skip_analysis_this_update: bool,
234/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
235/// (index 0), and non-`null` for all others.
236analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason),
237/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
238failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg),
239/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
240transitive_failed_analysis: std.array_hash_map.Auto(
241 AnalUnit,
242 if (build_options.enable_debug_extensions) TransitiveFailureReason else void,
243),
244/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
245/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
246/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
247/// this map simply exists to allow easily iterating all dependency loops exactly once.
248dependency_loops: std.array_hash_map.Auto(AnalUnit, void),
249/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
250/// All units in here form loops. To iterate loops, see `dependency_loops`.
251dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct {
252 unit: AnalUnit,
253 reason: DependencyReason,
254}),
255/// This `Nav` succeeded analysis, but failed codegen.
256/// This may be a simple "value" `Nav`, or it may be a function.
257/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
258/// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as
259/// codegen and linking run on a separate thread.
260failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg),
261failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg),
262failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg),
265263
266/// Maximum amount of distinct error values, set by --error-limit264/// Maximum amount of distinct error values, set by --error-limit
267error_limit: ErrorInt,265error_limit: ErrorInt,
...@@ -269,14 +267,14 @@ error_limit: ErrorInt,...@@ -269,14 +267,14 @@ error_limit: ErrorInt,
269/// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock267/// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock
270/// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the268/// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the
271/// lock is not needed and is compiled out.269/// lock is not needed and is compiled out.
272outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init,270outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void,
273/// Value is the number of PO dependencies of this AnalUnit.271/// Value is the number of PO dependencies of this AnalUnit.
274/// This value will decrease as we perform semantic analysis to learn what is outdated.272/// This value will decrease as we perform semantic analysis to learn what is outdated.
275/// If any of these PO deps is outdated, this value will be moved to `outdated`.273/// If any of these PO deps is outdated, this value will be moved to `outdated`.
276potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty,274potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32),
277/// Value is the number of PO dependencies of this AnalUnit.275/// Value is the number of PO dependencies of this AnalUnit.
278/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.276/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
279outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty,277outdated: std.array_hash_map.Auto(AnalUnit, u32),
280/// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0.278/// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0.
281/// Such `AnalUnit`s are ready for immediate re-analysis.279/// Such `AnalUnit`s are ready for immediate re-analysis.
282/// See `findOutdatedToAnalyze` for details.280/// See `findOutdatedToAnalyze` for details.
...@@ -286,69 +284,64 @@ outdated_ready: struct {...@@ -286,69 +284,64 @@ outdated_ready: struct {
286 funcs: std.array_hash_map.Auto(InternPool.Index, void),284 funcs: std.array_hash_map.Auto(InternPool.Index, void),
287 /// Does not contain `.func` units.285 /// Does not contain `.func` units.
288 other: std.array_hash_map.Auto(AnalUnit, void),286 other: std.array_hash_map.Auto(AnalUnit, void),
289} = .{ .funcs = .empty, .other = .empty },287},
290/// This contains a list of AnalUnit whose analysis or codegen failed, but the288/// This contains a list of AnalUnit whose analysis or codegen failed, but the
291/// failure was something like running out of disk space, and trying again may289/// failure was something like running out of disk space, and trying again may
292/// succeed. On the next update, we will flush this list, marking all members of290/// succeed. On the next update, we will flush this list, marking all members of
293/// it as outdated.291/// it as outdated.
294retryable_failures: std.ArrayList(AnalUnit) = .empty,292retryable_failures: std.ArrayList(AnalUnit),
295293
296/// These are the modules which we initially queue for analysis in `Compilation.update`.294/// These are the modules which we initially queue for analysis in `Compilation.update`.
297/// `resolveReferences` will use these as the root of its reachability traversal.295/// `resolveReferences` will use these as the root of its reachability traversal.
298analysis_roots_buffer: [5]*Module,296analysis_roots_buffer: [5]*Module,
299analysis_roots_len: usize = 0,297analysis_roots_len: usize,
300/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and298/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
301/// reset to `null` when any semantic analysis occurs (since this invalidates the data).299/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
302/// Allocated into `gpa`.300/// Allocated into `gpa`.
303resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null,301resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference),
304
305/// If `true`, then semantic analysis must not occur on this update due to AstGen errors.
306/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped.
307/// Reset to `false` at the start of each update in `Compilation.update`.
308skip_analysis_this_update: bool = false,
309302
310test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty,303test_filters: []const []const u8,
304test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void),
311305
312global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty,306global_assembly: std.array_hash_map.Auto(AnalUnit, []u8),
313307
314/// Key is the `AnalUnit` *performing* the reference. This representation allows308/// Key is the `AnalUnit` *performing* the reference. This representation allows
315/// incremental updates to quickly delete references caused by a specific `AnalUnit`.309/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
316/// Value is index into `all_references` of the first reference triggered by the unit.310/// Value is index into `all_references` of the first reference triggered by the unit.
317/// The `next` field on the `Reference` forms a linked list of all references311/// The `next` field on the `Reference` forms a linked list of all references
318/// triggered by the key `AnalUnit`.312/// triggered by the key `AnalUnit`.
319reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty,313reference_table: std.array_hash_map.Auto(AnalUnit, u32),
320all_references: std.ArrayList(Reference) = .empty,314all_references: std.ArrayList(Reference),
321/// Freelist of indices in `all_references`.315/// Freelist of indices in `all_references`.
322free_references: std.ArrayList(u32) = .empty,316free_references: std.ArrayList(u32),
323317
324inline_reference_frames: std.ArrayList(InlineReferenceFrame) = .empty,318inline_reference_frames: std.ArrayList(InlineReferenceFrame),
325free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty,319free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index),
326320
327/// Key is the `AnalUnit` *performing* the reference. This representation allows321/// Key is the `AnalUnit` *performing* the reference. This representation allows
328/// incremental updates to quickly delete references caused by a specific `AnalUnit`.322/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
329/// Value is index into `all_type_reference` of the first reference triggered by the unit.323/// Value is index into `all_type_reference` of the first reference triggered by the unit.
330/// The `next` field on the `TypeReference` forms a linked list of all type references324/// The `next` field on the `TypeReference` forms a linked list of all type references
331/// triggered by the key `AnalUnit`.325/// triggered by the key `AnalUnit`.
332type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty,326type_reference_table: std.array_hash_map.Auto(AnalUnit, u32),
333all_type_references: std.ArrayList(TypeReference) = .empty,327all_type_references: std.ArrayList(TypeReference),
334/// Freelist of indices in `all_type_references`.328/// Freelist of indices in `all_type_references`.
335free_type_references: std.ArrayList(u32) = .empty,329free_type_references: std.ArrayList(u32),
336330
337/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.331/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.
338std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none),332std_lang_decl_values: StdLangDecl.Memoized,
339333
340incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void =334incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void,
341 if (build_options.enable_debug_extensions) .init else {},
342335
343/// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit,336/// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit,
344/// this timer must be temporarily paused and resumed later.337/// this timer must be temporarily paused and resumed later.
345cur_analysis_timer: ?Compilation.Timer = null,338cur_analysis_timer: ?Compilation.Timer,
346339
347codegen_task_pool: CodegenTaskPool,340codegen_task_pool: CodegenTaskPool,
348341
349generation: u32 = 0,342generation: u32,
350343
351/// Only access from the Sema thread.344/// Only accessed from the Sema thread.
352anon_name_counter: u32,345anon_name_counter: u32,
353346
354pub const DependencyReason = struct {347pub const DependencyReason = struct {
...@@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct {...@@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct {
434 _ = ctx;427 _ = ctx;
435 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path));428 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path));
436 }429 }
437 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool {430 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: EmbedFile, b_index: usize) bool {
438 _ = ctx;431 _ = ctx;
439 _ = b_index;432 _ = b_index;
440 const b_path = b_file.path;433 const b_path = b_file.path;
...@@ -1250,10 +1243,15 @@ pub const EmbedFile = struct {...@@ -1250,10 +1243,15 @@ pub const EmbedFile = struct {
12501243
1251 pub const Index = enum(u32) {1244 pub const Index = enum(u32) {
1252 _,1245 _,
1253 pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile {1246 pub fn get(idx: Index, zcu: *const Zcu) *const EmbedFile {
1254 return zcu.embed_table.keys()[@backingInt(idx)];1247 return &zcu.embed_table.keys()[@backingInt(idx)];
1255 }1248 }
1256 };1249 };
1250
1251 pub fn deinit(ef: *EmbedFile, gpa: Allocator) void {
1252 ef.path.deinit(gpa);
1253 ef.* = undefined;
1254 }
1257};1255};
12581256
1259/// This struct holds data necessary to construct API-facing `AllErrors.Message`.1257/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
...@@ -2894,16 +2892,130 @@ pub const CompileError = error{...@@ -2894,16 +2892,130 @@ pub const CompileError = error{
2894 ComptimeBreak,2892 ComptimeBreak,
2895};2893};
28962894
2897pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {
2898 try zcu.intern_pool.init(gpa, io, thread_count);
2899}
2900
2901/// It is valid to not call this function before `deinit` in error paths.2895/// It is valid to not call this function before `deinit` in error paths.
2902/// Requires the fields on `zcu.comp` to already be initialized.2896/// Requires the fields on `zcu.comp` to already be initialized.
2903pub fn initAfterCompilation(zcu: *Zcu) void {2897pub fn init(zcu: *Zcu) void {
2904 zcu.initTracyPlots();2898 zcu.initTracyPlots();
2905}2899}
29062900
2901pub fn reset(zcu: *Zcu, arena: Allocator) Allocator.Error!void {
2902 const comp = zcu.comp;
2903 const gpa = comp.gpa;
2904 const io = comp.io;
2905
2906 zcu.all_exports.clearRetainingCapacity();
2907 zcu.free_exports.clearRetainingCapacity();
2908 zcu.single_exports.clearRetainingCapacity();
2909 zcu.multi_exports.clearRetainingCapacity();
2910
2911 zcu.module_roots.clearRetainingCapacity();
2912 // builtin modules can still be reused from a previous non-incremental update
2913
2914 for (zcu.import_table.keys()) |file| zcu.destroyFile(file);
2915 zcu.import_table.clearRetainingCapacity();
2916 zcu.alive_files.clearRetainingCapacity();
2917 for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa);
2918 zcu.embed_table.clearRetainingCapacity();
2919
2920 zcu.compile_logs.clearRetainingCapacity();
2921 zcu.compile_log_lines.clearRetainingCapacity();
2922 zcu.free_compile_log_lines.clearRetainingCapacity();
2923
2924 zcu.illegal_module_root = null;
2925 zcu.multi_module_err = null;
2926 zcu.failed_imports.clearRetainingCapacity();
2927 for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg);
2928 zcu.failed_files.clearRetainingCapacity();
2929 zcu.analysis_in_progress.clearRetainingCapacity();
2930 for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa);
2931 zcu.failed_analysis.clearRetainingCapacity();
2932 zcu.transitive_failed_analysis.clearRetainingCapacity();
2933 zcu.dependency_loops.clearRetainingCapacity();
2934 zcu.dependency_loop_nodes.clearRetainingCapacity();
2935 for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa);
2936 zcu.failed_codegen.clearRetainingCapacity();
2937 for (zcu.failed_types.values()) |msg| msg.destroy(gpa);
2938 zcu.failed_types.clearRetainingCapacity();
2939 for (zcu.failed_exports.values()) |msg| msg.destroy(gpa);
2940 zcu.failed_exports.clearRetainingCapacity();
2941
2942 assert(zcu.potentially_outdated.count() == 0);
2943 assert(zcu.outdated.count() == 0);
2944 assert(zcu.outdated_ready.funcs.count() == 0);
2945 assert(zcu.outdated_ready.other.count() == 0);
2946 zcu.retryable_failures.clearRetainingCapacity();
2947
2948 zcu.analysis_roots_len = 0;
2949 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod;
2950 zcu.analysis_roots_len += 1;
2951 // Normally we rely on importing std to in turn import the root source file in the start code.
2952 // However, the main module is distinct from the root module in tests, so that won't happen there.
2953 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) {
2954 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod;
2955 zcu.analysis_roots_len += 1;
2956 }
2957 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2958 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod;
2959 zcu.analysis_roots_len += 1;
2960 }
2961 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2962 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod;
2963 zcu.analysis_roots_len += 1;
2964 }
2965 if (zcu.root_mod.deps.get("zigc")) |zigc_mod| {
2966 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod;
2967 zcu.analysis_roots_len += 1;
2968 }
2969 zcu.clearCachedResolvedReferences();
2970
2971 zcu.test_functions.clearRetainingCapacity();
2972
2973 zcu.global_assembly.clearRetainingCapacity();
2974
2975 zcu.reference_table.clearRetainingCapacity();
2976 zcu.all_references.clearRetainingCapacity();
2977 zcu.free_references.clearRetainingCapacity();
2978
2979 zcu.inline_reference_frames.clearRetainingCapacity();
2980 zcu.free_inline_reference_frames.clearRetainingCapacity();
2981
2982 zcu.type_reference_table.clearRetainingCapacity();
2983 zcu.all_type_references.clearRetainingCapacity();
2984 zcu.free_type_references.clearRetainingCapacity();
2985
2986 zcu.std_lang_decl_values = .initFill(.none);
2987
2988 for (zcu.codegen_task_pool.task_funcs) |task_func| assert(task_func == .none);
2989
2990 assert(zcu.generation == 0);
2991
2992 zcu.anon_name_counter = 0;
2993
2994 zcu.intern_pool.deinit(gpa, io);
2995 zcu.intern_pool = .empty;
2996 try zcu.intern_pool.init(gpa, io, comp.thread_limit);
2997
2998 {
2999 const active = zcu.acquire();
3000 defer active.release();
3001 try active.pt.populateModuleRootTable();
3002 }
3003
3004 assert(zcu.llvm_object == null);
3005 if (comp.config.use_llvm and
3006 (comp.emit_bin != null or
3007 comp.emit_asm != null or
3008 comp.emit_llvm_ir != null or
3009 comp.emit_llvm_bc != null or
3010 log_llvm_ir: {
3011 break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
3012 }))
3013 {
3014 dev.check(.llvm_backend);
3015 zcu.llvm_object = try .create(if (comp.config.incremental) comp.arena else arena, zcu);
3016 }
3017}
3018
2907pub fn deinit(zcu: *Zcu) void {3019pub fn deinit(zcu: *Zcu) void {
2908 const comp = zcu.comp;3020 const comp = zcu.comp;
2909 const io = comp.io;3021 const io = comp.io;
...@@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void {
2911 {3023 {
2912 if (zcu.llvm_object) |llvm_object| llvm_object.deinit();3024 if (zcu.llvm_object) |llvm_object| llvm_object.deinit();
29133025
2914 zcu.builtin_modules.deinit(gpa);3026 zcu.global_zir_cache.handle.close(io);
3027 zcu.local_zir_cache.handle.close(io);
3028
3029 zcu.all_exports.deinit(gpa);
3030 zcu.free_exports.deinit(gpa);
3031 zcu.single_exports.deinit(gpa);
3032 zcu.multi_exports.deinit(gpa);
3033
2915 zcu.module_roots.deinit(gpa);3034 zcu.module_roots.deinit(gpa);
2916 for (zcu.import_table.keys()) |file_index| {3035 zcu.builtin_modules.deinit(gpa);
2917 zcu.destroyFile(file_index);3036
2918 }3037 for (zcu.import_table.keys()) |file| zcu.destroyFile(file);
2919 zcu.import_table.deinit(gpa);3038 zcu.import_table.deinit(gpa);
2920 zcu.alive_files.deinit(gpa);3039 zcu.alive_files.deinit(gpa);
29213040 for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa);
2922 for (zcu.embed_table.keys()) |embed_file| {
2923 embed_file.path.deinit(gpa);
2924 gpa.destroy(embed_file);
2925 }
2926 zcu.embed_table.deinit(gpa);3041 zcu.embed_table.deinit(gpa);
29273042
2928 zcu.local_zir_cache.handle.close(io);3043 zcu.compile_logs.deinit(gpa);
2929 zcu.global_zir_cache.handle.close(io);3044 zcu.compile_log_lines.deinit(gpa);
3045 zcu.free_compile_log_lines.deinit(gpa);
29303046
2931 for (zcu.failed_analysis.values()) |value| value.destroy(gpa);3047 zcu.failed_imports.deinit(gpa);
2932 for (zcu.failed_codegen.values()) |value| value.destroy(gpa);3048 for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg);
2933 for (zcu.failed_types.values()) |value| value.destroy(gpa);3049 zcu.failed_files.deinit(gpa);
2934 zcu.analysis_in_progress.deinit(gpa);3050 zcu.analysis_in_progress.deinit(gpa);
3051 for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa);
2935 zcu.failed_analysis.deinit(gpa);3052 zcu.failed_analysis.deinit(gpa);
2936 zcu.transitive_failed_analysis.deinit(gpa);3053 zcu.transitive_failed_analysis.deinit(gpa);
2937 zcu.dependency_loops.deinit(gpa);3054 zcu.dependency_loops.deinit(gpa);
2938 zcu.dependency_loop_nodes.deinit(gpa);3055 zcu.dependency_loop_nodes.deinit(gpa);
3056 for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa);
2939 zcu.failed_codegen.deinit(gpa);3057 zcu.failed_codegen.deinit(gpa);
3058 for (zcu.failed_types.values()) |msg| msg.destroy(gpa);
2940 zcu.failed_types.deinit(gpa);3059 zcu.failed_types.deinit(gpa);
29413060 for (zcu.failed_exports.values()) |msg| msg.destroy(gpa);
2942 for (zcu.failed_files.values()) |value| {
2943 if (value) |msg| gpa.free(msg);
2944 }
2945 zcu.failed_files.deinit(gpa);
2946 zcu.failed_imports.deinit(gpa);
2947
2948 for (zcu.failed_exports.values()) |value| {
2949 value.destroy(gpa);
2950 }
2951 zcu.failed_exports.deinit(gpa);3061 zcu.failed_exports.deinit(gpa);
29523062
2953 for (zcu.cimport_errors.values()) |*errs| {
2954 errs.deinit(gpa);
2955 }
2956 zcu.cimport_errors.deinit(gpa);
2957
2958 zcu.compile_logs.deinit(gpa);
2959 zcu.compile_log_lines.deinit(gpa);
2960 zcu.free_compile_log_lines.deinit(gpa);
2961
2962 zcu.all_exports.deinit(gpa);
2963 zcu.free_exports.deinit(gpa);
2964 zcu.single_exports.deinit(gpa);
2965 zcu.multi_exports.deinit(gpa);
2966
2967 zcu.potentially_outdated.deinit(gpa);3063 zcu.potentially_outdated.deinit(gpa);
2968 zcu.outdated.deinit(gpa);3064 zcu.outdated.deinit(gpa);
2969 zcu.outdated_ready.funcs.deinit(gpa);3065 zcu.outdated_ready.funcs.deinit(gpa);
2970 zcu.outdated_ready.other.deinit(gpa);3066 zcu.outdated_ready.other.deinit(gpa);
2971 zcu.retryable_failures.deinit(gpa);3067 zcu.retryable_failures.deinit(gpa);
29723068
3069 if (zcu.resolved_references) |*r| r.deinit(gpa);
3070
2973 zcu.test_functions.deinit(gpa);3071 zcu.test_functions.deinit(gpa);
29743072
2975 for (zcu.global_assembly.values()) |s| {3073 for (zcu.global_assembly.values()) |s| gpa.free(s);
2976 gpa.free(s);
2977 }
2978 zcu.global_assembly.deinit(gpa);3074 zcu.global_assembly.deinit(gpa);
29793075
2980 zcu.reference_table.deinit(gpa);3076 zcu.reference_table.deinit(gpa);
...@@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void {
2988 zcu.all_type_references.deinit(gpa);3084 zcu.all_type_references.deinit(gpa);
2989 zcu.free_type_references.deinit(gpa);3085 zcu.free_type_references.deinit(gpa);
29903086
2991 if (zcu.resolved_references) |*r| r.deinit(gpa);
2992
2993 if (comp.debugIncremental()) {3087 if (comp.debugIncremental()) {
2994 zcu.incremental_debug_state.deinit(gpa);3088 zcu.incremental_debug_state.deinit(gpa);
2995 }3089 }
...@@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4352 .unnamed_test => true,4446 .unnamed_test => true,
4353 .@"test", .decltest => a: {4447 .@"test", .decltest => a: {
4354 const fqn_slice = nav.fqn.toSlice(ip);4448 const fqn_slice = nav.fqn.toSlice(ip);
4355 if (comp.test_filters.len > 0) {4449 if (zcu.test_filters.len > 0) {
4356 for (comp.test_filters) |test_filter| {4450 for (zcu.test_filters) |test_filter| {
4357 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;4451 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;
4358 } else break :a false;4452 } else break :a false;
4359 }4453 }
src/Zcu/PerThread.zig+66-82
...@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");...@@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig");
25const AnalUnit = InternPool.AnalUnit;25const AnalUnit = InternPool.AnalUnit;
26const Module = @import("../Module.zig");26const Module = @import("../Module.zig");
27const Sema = @import("../Sema.zig");27const Sema = @import("../Sema.zig");
28const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
28const target_util = @import("../target.zig");29const target_util = @import("../target.zig");
29const tracy = @import("../tracy.zig");30const tracy = @import("../tracy.zig");
30const trace = tracy.trace;31const trace = tracy.trace;
...@@ -147,6 +148,12 @@ pub fn update(...@@ -147,6 +148,12 @@ pub fn update(
147 comp.link_queue.finishZcuQueue(comp);148 comp.link_queue.finishZcuQueue(comp);
148 }149 }
149150
151 if (zcu.illegal_module_root) |_| {
152 // We cannot run AstGen because we failed to set up the module roots. We can return early
153 // because this is a guaranteed compile error.
154 return;
155 }
156
150 {157 {
151 const tracy_trace = traceNamed(@src(), "astgen");158 const tracy_trace = traceNamed(@src(), "astgen");
152 defer tracy_trace.end();159 defer tracy_trace.end();
...@@ -202,11 +209,9 @@ pub fn update(...@@ -202,11 +209,9 @@ pub fn update(
202 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here209 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
203 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one210 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
204 // `@embedFile` can't trigger analysis of a new `@embedFile`!211 // `@embedFile` can't trigger analysis of a new `@embedFile`!
205 for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {212 for (0.., zcu.embed_table.keys()) |ef_index_usize, *ef| {
206 const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize));213 const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize));
207 astgen_group.async(io, workerUpdateEmbedFile, .{214 astgen_group.async(io, workerUpdateEmbedFile, .{ comp, ef_index, ef });
208 comp, ef_index, ef,
209 });
210 }215 }
211216
212 try astgen_group.await(io);217 try astgen_group.await(io);
...@@ -218,8 +223,8 @@ pub fn update(...@@ -218,8 +223,8 @@ pub fn update(
218 // they belong to.223 // they belong to.
219 const any_fatal_files = try pt.computeAliveFiles();224 const any_fatal_files = try pt.computeAliveFiles();
220225
221 // If the cache mode is `whole`, add every alive source file to the manifest.
222 switch (comp.cache_use) {226 switch (comp.cache_use) {
227 .none => {},
223 .whole => |whole| if (whole.cache_manifest) |man| {228 .whole => |whole| if (whole.cache_manifest) |man| {
224 for (zcu.alive_files.keys()) |file_index| {229 for (zcu.alive_files.keys()) |file_index| {
225 const file = zcu.fileByIndex(file_index);230 const file = zcu.fileByIndex(file_index);
...@@ -249,7 +254,11 @@ pub fn update(...@@ -249,7 +254,11 @@ pub fn update(
249 };254 };
250 }255 }
251 },256 },
252 .none, .incremental => {},257 .incremental => {
258 // Do not include file contents in the cache manifest because we
259 // want the hash to be the same regardless of the contents of the
260 // source files so that incremental can do its thing.
261 },
253 }262 }
254263
255 if (comp.time_report) |*tr| {264 if (comp.time_report) |*tr| {
...@@ -2303,10 +2312,9 @@ fn analyzeFuncBody(...@@ -2303,10 +2312,9 @@ fn analyzeFuncBody(
23032312
2304 const comp = zcu.comp;2313 const comp = zcu.comp;
23052314
2306 const dump_air = build_options.enable_debug_extensions and comp.verbose_air;2315 if (comp.bin_file != null or zcu.llvm_object != null or log_air: {
2307 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);2316 break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air");
23082317 }) {
2309 if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) {
2310 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);2318 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
2311 comp.link_prog_node.increaseEstimatedTotalItems(1);2319 comp.link_prog_node.increaseEstimatedTotalItems(1);
23122320
...@@ -2494,11 +2502,7 @@ pub fn doImport(...@@ -2494,11 +2502,7 @@ pub fn doImport(
2494}2502}
2495/// This is called once during `Compilation.create` and never again. "builtin" modules don't yet2503/// This is called once during `Compilation.create` and never again. "builtin" modules don't yet
2496/// exist, so are not added to `module_roots` here. They must be added when they are created.2504/// exist, so are not added to `module_roots` here. They must be added when they are created.
2497pub fn populateModuleRootTable(pt: Zcu.PerThread) error{2505pub fn populateModuleRootTable(pt: Zcu.PerThread) Allocator.Error!void {
2498 OutOfMemory,
2499 /// One of the specified modules had its root source file at an illegal path.
2500 IllegalZigImport,
2501}!void {
2502 const zcu = pt.zcu;2506 const zcu = pt.zcu;
2503 const comp = zcu.comp;2507 const comp = zcu.comp;
2504 const gpa = comp.gpa;2508 const gpa = comp.gpa;
...@@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{...@@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
2507 // We'll initially add [mod, undefined] pairs, and when we reach the pair while2511 // We'll initially add [mod, undefined] pairs, and when we reach the pair while
2508 // iterating, rewrite the undefined value.2512 // iterating, rewrite the undefined value.
2509 const roots = &zcu.module_roots;2513 const roots = &zcu.module_roots;
2510 roots.clearRetainingCapacity();2514 assert(roots.count() == 0);
25112515
2512 // Start with:2516 // Start with:
2513 // * `std_mod`, which is the main root of analysis2517 // * `std_mod`, which is the main root of analysis
...@@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{...@@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
2542 errdefer path.deinit(gpa);2546 errdefer path.deinit(gpa);
25432547
2544 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {2548 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {
2545 return error.IllegalZigImport;2549 // One of the specified modules had its root source file at an illegal path.
2550 zcu.illegal_module_root = mod;
2551 return;
2546 }2552 }
25472553
2548 const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu });2554 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...@@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct
2781 const gpa = comp.gpa;2787 const gpa = comp.gpa;
2782 const io = comp.io;2788 const io = comp.io;
27832789
2784 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());2790 const mod: *Module = mod: {
2785 if (gop.found_existing) return .{ // the `File` is up-to-date2791 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());
2786 .file = zcu.module_roots.get(gop.value_ptr.*).?.unwrap().?,2792 if (!gop.found_existing) {
2787 .module_root = gop.value_ptr.*,2793 errdefer _ = zcu.builtin_modules.pop();
2794 gop.value_ptr.* = try .createBuiltin(comp.arena, opts, comp.dirs);
2795 }
2796 const mod = gop.value_ptr.*;
2797 assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin
2798 break :mod mod;
2788 };2799 };
2789 errdefer _ = zcu.builtin_modules.pop();
27902800
2791 const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs);2801 if (zcu.module_roots.get(mod)) |file| {
2792 assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin2802 // We have already loaded this builtin.zig before!
2803 return .{ .file = file.unwrap().?, .module_root = mod };
2804 }
27932805
2794 const path = try mod.root.join(gpa, comp.dirs, "builtin.zig");2806 const path = try mod.root.join(gpa, comp.dirs, "builtin.zig");
2795 errdefer path.deinit(gpa);2807 errdefer path.deinit(gpa);
...@@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct...@@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct
2827 .root_type = .none,2839 .root_type = .none,
2828 });2840 });
28292841
2830 gop.value_ptr.* = mod;
2831 file_gop.key_ptr.* = file_index;2842 file_gop.key_ptr.* = file_index;
2832 zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional());2843 zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional());
2833 try opts.populateFile(gpa, file);2844 try opts.populateFile(gpa, file);
...@@ -2883,22 +2894,19 @@ pub fn embedFile(...@@ -2883,22 +2894,19 @@ pub fn embedFile(
2883 return @fromBackingInt(@intCast(gop.index));2894 return @fromBackingInt(@intCast(gop.index));
2884 }2895 }
2885 errdefer _ = zcu.embed_table.pop();2896 errdefer _ = zcu.embed_table.pop();
2886 gop.key_ptr.* = try pt.newEmbedFile(path);2897 try pt.initEmbedFile(gop.key_ptr, path);
2887 return @fromBackingInt(@intCast(gop.index));2898 return @fromBackingInt(@intCast(gop.index));
2888 }2899 }
28892900
2890 const embed_file: *Zcu.EmbedFile, const embed_file_idx: Zcu.EmbedFile.Index = ef: {2901 const embed_file, const embed_file_idx: Zcu.EmbedFile.Index = ef: {
2891 const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string);2902 const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string);
2892 errdefer path.deinit(gpa);2903 errdefer path.deinit(gpa);
2893 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});2904 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});
2894 if (gop.found_existing) {2905 if (!gop.found_existing) {
2895 path.deinit(gpa); // we're not using this key
2896 break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) };
2897 } else {
2898 errdefer _ = zcu.embed_table.pop();2906 errdefer _ = zcu.embed_table.pop();
2899 gop.key_ptr.* = try pt.newEmbedFile(path);2907 try pt.initEmbedFile(gop.key_ptr, path);
2900 break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) };2908 } else path.deinit(gpa); // we're not using this key
2901 }2909 break :ef .{ gop.key_ptr, @fromBackingInt(@intCast(gop.index)) };
2902 };2910 };
29032911
2904 switch (embed_file.path.isNested(cur_file.mod.?.root)) {2912 switch (embed_file.path.isNested(cur_file.mod.?.root)) {
...@@ -2913,7 +2921,7 @@ pub fn updateEmbedFile(...@@ -2913,7 +2921,7 @@ pub fn updateEmbedFile(
2913 pt: Zcu.PerThread,2921 pt: Zcu.PerThread,
2914 ef: *Zcu.EmbedFile,2922 ef: *Zcu.EmbedFile,
2915 /// If not `null`, the interned file data is stored here, if it was loaded.2923 /// If not `null`, the interned file data is stored here, if it was loaded.
2916 /// `newEmbedFile` uses this to add the file to the `whole` cache manifest.2924 /// `initEmbedFile` uses this to add the file to the `whole` cache manifest.
2917 ip_str_out: ?*?InternPool.String,2925 ip_str_out: ?*?InternPool.String,
2918) Allocator.Error!void {2926) Allocator.Error!void {
2919 pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) {2927 pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) {
...@@ -3000,17 +3008,13 @@ fn updateEmbedFileInner(...@@ -3000,17 +3008,13 @@ fn updateEmbedFileInner(
3000}3008}
30013009
3002/// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success.3010/// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success.
3003fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.EmbedFile {3011fn initEmbedFile(pt: Zcu.PerThread, ef: *Zcu.EmbedFile, path: Compilation.Path) EmbedFileError!void {
3004 const zcu = pt.zcu;3012 const zcu = pt.zcu;
3005 const comp = zcu.comp;3013 const comp = zcu.comp;
3006 const io = comp.io;3014 const io = comp.io;
3007 const gpa = comp.gpa;
3008 const ip = &zcu.intern_pool;3015 const ip = &zcu.intern_pool;
30093016
3010 const new_file = try gpa.create(Zcu.EmbedFile);3017 ef.* = .{
3011 errdefer gpa.destroy(new_file);
3012
3013 new_file.* = .{
3014 .path = path,3018 .path = path,
3015 .val = .none,3019 .val = .none,
3016 .err = null,3020 .err = null,
...@@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E...@@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E
3018 };3022 };
30193023
3020 var opt_ip_str: ?InternPool.String = null;3024 var opt_ip_str: ?InternPool.String = null;
3021 try pt.updateEmbedFile(new_file, &opt_ip_str);3025 try pt.updateEmbedFile(ef, &opt_ip_str);
30223026
3023 try comp.appendFileSystemInput(path);3027 try comp.appendFileSystemInput(path);
30243028
...@@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E...@@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E
3031 const man = whole.cache_manifest orelse break :cache;3035 const man = whole.cache_manifest orelse break :cache;
3032 const ip_str = opt_ip_str orelse break :cache; // this will be a compile error3036 const ip_str = opt_ip_str orelse break :cache; // this will be a compile error
30333037
3034 const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu);3038 const array_len = Value.fromInterned(ef.val).typeOf(zcu).childType(zcu).arrayLen(zcu);
3035 const contents = ip_str.toSlice(array_len, ip);3039 const contents = ip_str.toSlice(array_len, ip);
30363040
3037 try whole.cache_manifest_mutex.lock(io);3041 try whole.cache_manifest_mutex.lock(io);
3038 defer whole.cache_manifest_mutex.unlock(io);3042 defer whole.cache_manifest_mutex.unlock(io);
30393043
3040 path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, new_file.stat) catch |err| switch (err) {3044 path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, ef.stat) catch |err| switch (err) {
3041 error.FileSystemFailure => unreachable, // contents and stat are both provided3045 error.FileSystemFailure => unreachable, // contents and stat are both provided
3042 else => |e| return e,3046 else => |e| return e,
3043 };3047 };
3044 }3048 }
3045
3046 return new_file;
3047}3049}
30483050
3049pub fn scanNamespace(3051pub fn scanNamespace(
...@@ -3242,9 +3244,9 @@ const ScanDeclIter = struct {...@@ -3242,9 +3244,9 @@ const ScanDeclIter = struct {
3242 // Perhaps we should add all test indiscriminately and filter at the end of the update.3244 // Perhaps we should add all test indiscriminately and filter at the end of the update.
3243 if (!comp.config.is_test) break :a false;3245 if (!comp.config.is_test) break :a false;
3244 if (file.mod != zcu.main_mod) break :a false;3246 if (file.mod != zcu.main_mod) break :a false;
3245 if (is_named and comp.test_filters.len > 0) {3247 if (is_named and zcu.test_filters.len > 0) {
3246 const fqn_slice = fqn.toSlice(ip);3248 const fqn_slice = fqn.toSlice(ip);
3247 for (comp.test_filters) |test_filter| {3249 for (zcu.test_filters) |test_filter| {
3248 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;3250 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;
3249 } else break :a false;3251 } else break :a false;
3250 }3252 }
...@@ -4522,32 +4524,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4522,32 +4524,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
4522 tracy_trace.addText(fqn.toSlice(ip));4524 tracy_trace.addText(fqn.toSlice(ip));
4523 tracy_trace.addTextFmt("func_ip_index={d}", .{func_index});4525 tracy_trace.addTextFmt("func_ip_index={d}", .{func_index});
45244526
4525 Air.Verify.run(pt, func_index, air);4527 var liveness: ?Air.Liveness = null;
4528 defer if (liveness) |*l| l.deinit(gpa);
4529
4530 const ap: Air.Print = .{
4531 .zcu = zcu,
4532 .fqn = fqn,
4533 .air = air,
4534 .liveness = &liveness,
4535 };
4536 std.log.scoped(.@"illegal-air").debug("{f}", .{&ap});
45264537
4527 if (codegen.legalizeFeatures(pt, nav)) |features| {4538 if (codegen.legalizeFeatures(pt, nav)) |features| {
4528 try air.legalize(pt, features);4539 // Verify the AIR again pre-legalization.
4529 // Verify the AIR again post-legalization.
4530 Air.Verify.run(pt, func_index, air);4540 Air.Verify.run(pt, func_index, air);
4541 try air.legalize(pt, features);
4531 }4542 }
45324543
4533 var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav))4544 std.log.scoped(.@"legal-air").debug("{f}", .{&ap});
4534 try .analyze(zcu, air.*, ip)4545 Air.Verify.run(pt, func_index, air);
4535 else
4536 null;
4537 defer if (liveness) |*l| l.deinit(gpa);
4538
4539 if (build_options.enable_debug_extensions and comp.verbose_air) p: {
4540 const io = comp.io;
4541 const stderr = try io.lockStderr(&.{}, null);
4542 defer io.unlockStderr();
4543 printVerboseAir(pt, liveness, fqn, air, &stderr.file_writer.interface) catch |err| switch (err) {
4544 error.WriteFailed => switch (stderr.file_writer.err.?) {
4545 error.Canceled => |e| return e,
4546 else => break :p,
4547 },
4548 };
4549 }
45504546
4547 if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip);
4548 std.log.scoped(.air).debug("{f}", .{&ap});
4551 if (std.debug.runtime_safety) verify_liveness: {4549 if (std.debug.runtime_safety) verify_liveness: {
4552 var verify: Air.Liveness.Verify = .{4550 var verify: Air.Liveness.Verify = .{
4553 .gpa = gpa,4551 .gpa = gpa,
...@@ -4577,17 +4575,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e...@@ -4577,17 +4575,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e
45774575
4578 return codegen.generateFunction(lf, pt, func_index, air, &liveness);4576 return codegen.generateFunction(lf, pt, func_index, air, &liveness);
4579}4577}
4580
4581fn printVerboseAir(
4582 pt: Zcu.PerThread,
4583 liveness: ?Air.Liveness,
4584 fqn: InternPool.NullTerminatedString,
4585 air: *const Air,
4586 w: *Io.Writer,
4587) Io.Writer.Error!void {
4588 const zcu = pt.zcu;
4589 const ip = &zcu.intern_pool;
4590 try w.print("# Begin Function AIR: {f}:\n", .{fqn.fmt(ip)});
4591 try air.write(w, zcu, liveness);
4592 try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});
4593}
src/codegen/llvm.zig+66-59
...@@ -10,6 +10,7 @@ const build_options = @import("build_options");...@@ -10,6 +10,7 @@ const build_options = @import("build_options");
10const Air = @import("../Air.zig");10const Air = @import("../Air.zig");
11const codegen = @import("../codegen.zig");11const codegen = @import("../codegen.zig");
12const Compilation = @import("../Compilation.zig");12const Compilation = @import("../Compilation.zig");
13const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled;
13const InternPool = @import("../InternPool.zig");14const InternPool = @import("../InternPool.zig");
14const link = @import("../link.zig");15const link = @import("../link.zig");
15const Module = @import("../Module.zig");16const Module = @import("../Module.zig");
...@@ -331,12 +332,10 @@ pub const Object = struct {...@@ -331,12 +332,10 @@ pub const Object = struct {
331 }332 }
332333
333 pub const EmitOptions = struct {334 pub const EmitOptions = struct {
334 pre_ir_path: ?[]const u8,
335 pre_bc_path: ?[]const u8,
336 bin_path: ?[:0]const u8,335 bin_path: ?[:0]const u8,
337 asm_path: ?[:0]const u8,336 asm_path: ?[:0]const u8,
338 post_ir_path: ?[:0]const u8,337 opt_ir_path: ?[:0]const u8,
339 post_bc_path: ?[:0]const u8,338 opt_bc_path: ?[:0]const u8,
340339
341 is_debug: bool,340 is_debug: bool,
342 is_small: bool,341 is_small: bool,
...@@ -351,6 +350,7 @@ pub const Object = struct {...@@ -351,6 +350,7 @@ pub const Object = struct {
351 const comp = zcu.comp;350 const comp = zcu.comp;
352 const io = comp.io;351 const io = comp.io;
353 const diags = &comp.link_diags;352 const diags = &comp.link_diags;
353 const target = &comp.root_mod.resolved_target.result;
354354
355 {355 {
356 if (o.errors_len_variable != .none) {356 if (o.errors_len_variable != .none) {
...@@ -403,7 +403,7 @@ pub const Object = struct {...@@ -403,7 +403,7 @@ pub const Object = struct {
403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));403 const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7));
404 const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));404 const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8));
405405
406 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| {406 if (target_util.llvmMachineAbi(target)) |abi| {
407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{407 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
408 behavior_error,408 behavior_error,
409 (try o.builder.metadataString("target-abi")).toMetadata(),409 (try o.builder.metadataString("target-abi")).toMetadata(),
...@@ -411,7 +411,7 @@ pub const Object = struct {...@@ -411,7 +411,7 @@ pub const Object = struct {
411 }));411 }));
412 }412 }
413413
414 const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result);414 const pic_level = target_util.picLevel(target);
415 if (comp.root_mod.pic) {415 if (comp.root_mod.pic) {
416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{416 module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{
417 behavior_min,417 behavior_min,
...@@ -434,7 +434,7 @@ pub const Object = struct {...@@ -434,7 +434,7 @@ pub const Object = struct {
434 (try o.builder.metadataString("Code Model")).toMetadata(),434 (try o.builder.metadataString("Code Model")).toMetadata(),
435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(435 try o.builder.metadataConstant(try o.builder.intConst(.i32, @as(
436 i32,436 i32,
437 switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {437 switch (codeModel(comp.root_mod.code_model, target)) {
438 .default => unreachable,438 .default => unreachable,
439 .tiny => 0,439 .tiny => 0,
440 .small => 1,440 .small => 1,
...@@ -480,7 +480,6 @@ pub const Object = struct {...@@ -480,7 +480,6 @@ pub const Object = struct {
480 }480 }
481 }481 }
482482
483 const target = &comp.root_mod.resolved_target.result;
484 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {483 if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) {
485 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall484 // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall
486 // v4, which is essentially a requirement on Windows. See corresponding logic in485 // v4, which is essentially a requirement on Windows. See corresponding logic in
...@@ -515,21 +514,26 @@ pub const Object = struct {...@@ -515,21 +514,26 @@ pub const Object = struct {
515514
516 const emit_asm_msg = options.asm_path orelse "(none)";515 const emit_asm_msg = options.asm_path orelse "(none)";
517 const emit_bin_msg = options.bin_path orelse "(none)";516 const emit_bin_msg = options.bin_path orelse "(none)";
518 const post_llvm_ir_msg = options.post_ir_path orelse "(none)";517 const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)";
519 const post_llvm_bc_msg = options.post_bc_path orelse "(none)";518 const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)";
520 log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{519 log.debug("emit LLVM object asm={s} bin={s} ir={s} bc={s}", .{
521 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg,520 emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg,
522 });521 });
522 const log_opt_llvm_ir = debugLogScopeEnabled("opt-llvm-ir");
523523
524 const context, const module = emit: {524 const context, const module = emit: {
525 if (options.pre_ir_path) |path| {525 {
526 if (std.mem.eql(u8, path, "-")) {526 var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null };
527 o.builder.dump(io);527 std.log.scoped(.@"llvm-ir").debug("{f}", .{&p});
528 } else {528 if (p.err) |err| return err;
529 o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| {529 }
530 log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err });530
531 };531 if (target.ofmt == .llvmir) {
532 }532 const path = comp.bin_file.?.emit;
533 o.builder.printToFilePath(io, path.root_dir.handle, path.sub_path) catch |err| {
534 return diags.fail("failed emitting LLVM module to {qf}: {t}", .{ path, err });
535 };
536 return;
533 }537 }
534538
535 const bitcode = try o.builder.toBitcode(o.gpa, .{539 const bitcode = try o.builder.toBitcode(o.gpa, .{
...@@ -538,23 +542,26 @@ pub const Object = struct {...@@ -538,23 +542,26 @@ pub const Object = struct {
538 });542 });
539 defer o.gpa.free(bitcode);543 defer o.gpa.free(bitcode);
540544
541 if (options.pre_bc_path) |path| {545 if (target.ofmt == .llvmbc) {
542 var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err|546 const path = comp.bin_file.?.emit;
543 return diags.fail("failed to create '{s}': {t}", .{ path, err });547 var file = path.root_dir.handle.createFile(io, path.sub_path, .{}) catch |err|
548 return diags.fail("failed to create {qf}: {t}", .{ path, err });
544 defer file.close(io);549 defer file.close(io);
545550
546 file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err|551 file.writeStreamingAll(io, @ptrCast(bitcode)) catch |err|
547 return diags.fail("failed to write to '{s}': {t}", .{ path, err });552 return diags.fail("failed to write to {qf}: {t}", .{ path, err });
553 return;
548 }554 }
549555
550 if (options.asm_path == null and options.bin_path == null and556 if (options.asm_path == null and options.bin_path == null and
551 options.post_ir_path == null and options.post_bc_path == null) return;557 options.opt_ir_path == null and options.opt_bc_path == null and
558 !log_opt_llvm_ir) return;
552559
553 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {560 if (!build_options.have_llvm or !comp.config.use_lib_llvm) {
554 return diags.fail("emitting without libllvm not implemented", .{});561 return diags.fail("emitting without libllvm not implemented", .{});
555 }562 }
556563
557 initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch);564 initializeLLVMTarget(io, target.cpu.arch);
558565
559 const context: *bindings.Context = .create();566 const context: *bindings.Context = .create();
560 errdefer context.dispose();567 errdefer context.dispose();
...@@ -577,9 +584,9 @@ pub const Object = struct {...@@ -577,9 +584,9 @@ pub const Object = struct {
577 };584 };
578 defer context.dispose();585 defer context.dispose();
579586
580 var target: *bindings.Target = undefined;587 var llvm_target: *bindings.Target = undefined;
581 var error_message: [*:0]const u8 = undefined;588 var error_message: [*:0]const u8 = undefined;
582 if (bindings.Target.getFromTriple(target_triple_sentinel, &target, &error_message).toBool()) {589 if (bindings.Target.getFromTriple(target_triple_sentinel, &llvm_target, &error_message).toBool()) {
583 defer bindings.disposeMessage(error_message);590 defer bindings.disposeMessage(error_message);
584 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });591 return diags.fail("LLVM failed to parse '{s}': {s}", .{ target_triple_sentinel, error_message });
585 }592 }
...@@ -598,7 +605,7 @@ pub const Object = struct {...@@ -598,7 +605,7 @@ pub const Object = struct {
598 else605 else
599 .Static;606 .Static;
600607
601 const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, &comp.root_mod.resolved_target.result)) {608 const code_model: bindings.CodeModel = switch (codeModel(comp.root_mod.code_model, target)) {
602 .default => .Default,609 .default => .Default,
603 .tiny => .Tiny,610 .tiny => .Tiny,
604 .small => .Small,611 .small => .Small,
...@@ -607,24 +614,22 @@ pub const Object = struct {...@@ -607,24 +614,22 @@ pub const Object = struct {
607 .large => .Large,614 .large => .Large,
608 };615 };
609616
610 const float_abi: bindings.TargetMachine.FloatABI = if (comp.root_mod.resolved_target.result.abi.float() == .hard)
611 .Hard
612 else
613 .Soft;
614
615 var target_machine = bindings.TargetMachine.create(617 var target_machine = bindings.TargetMachine.create(
616 target,618 llvm_target,
617 target_triple_sentinel,619 target_triple_sentinel,
618 if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,620 if (target.cpu.model.llvm_name) |s| s.ptr else null,
619 comp.root_mod.resolved_target.llvm_cpu_features.?,621 comp.root_mod.llvm_cpu_features.?,
620 opt_level,622 opt_level,
621 reloc_mode,623 reloc_mode,
622 code_model,624 code_model,
623 comp.function_sections,625 comp.function_sections,
624 comp.data_sections,626 comp.data_sections,
625 float_abi,627 switch (target.abi.float()) {
626 if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null,628 .hard => .Hard,
627 target_util.useEmulatedTls(&comp.root_mod.resolved_target.result),629 .soft => .Soft,
630 },
631 if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
632 target_util.useEmulatedTls(target),
628 );633 );
629 errdefer target_machine.dispose();634 errdefer target_machine.dispose();
630635
...@@ -634,7 +639,10 @@ pub const Object = struct {...@@ -634,7 +639,10 @@ pub const Object = struct {
634639
635 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.640 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
636 // So we call the entire pipeline multiple times if this is requested.641 // So we call the entire pipeline multiple times if this is requested.
637 // var error_message: [*:0]const u8 = undefined;642 var time_report_c_str: ?[*:0]u8 = null;
643 defer if (time_report_c_str) |time_report| bindings.disposeMessage(time_report);
644 var llvm_ir_c_str: ?[*:0]u8 = null;
645 defer if (llvm_ir_c_str) |llvm_ir| bindings.disposeMessage(llvm_ir);
638 var lowered_options: bindings.TargetMachine.EmitOptions = .{646 var lowered_options: bindings.TargetMachine.EmitOptions = .{
639 .is_debug = options.is_debug,647 .is_debug = options.is_debug,
640 .is_small = options.is_small,648 .is_small = options.is_small,
...@@ -648,11 +656,12 @@ pub const Object = struct {...@@ -648,11 +656,12 @@ pub const Object = struct {
648 .allow_fast_isel = true,656 .allow_fast_isel = true,
649 // LLVM's RISC-V backend for some reason enables the machine outliner by default even657 // LLVM's RISC-V backend for some reason enables the machine outliner by default even
650 // though it's clearly not ready and produces multiple miscompilations in our std tests.658 // though it's clearly not ready and produces multiple miscompilations in our std tests.
651 .allow_machine_outliner = !comp.root_mod.resolved_target.result.cpu.arch.isRISCV(),659 .allow_machine_outliner = !target.cpu.arch.isRISCV(),
652 .asm_filename = null,660 .asm_filename = null,
653 .bin_filename = if (options.bin_path) |x| x.ptr else null,661 .bin_filename = if (options.bin_path) |x| x.ptr else null,
654 .llvm_ir_filename = if (options.post_ir_path) |x| x.ptr else null,662 .llvm_ir_filename = if (options.opt_ir_path) |x| x.ptr else null,
655 .bitcode_filename = if (options.post_bc_path) |x| x.ptr else null,663 .bitcode_filename = if (options.opt_bc_path) |x| x.ptr else null,
664 .llvm_ir_out = if (log_opt_llvm_ir) &llvm_ir_c_str else null,
656665
657 // `.coverage` value is only used when `.sancov` is enabled.666 // `.coverage` value is only used when `.sancov` is enabled.
658 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,667 .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard,
...@@ -684,33 +693,31 @@ pub const Object = struct {...@@ -684,33 +693,31 @@ pub const Object = struct {
684 };693 };
685 if (options.asm_path != null and options.bin_path != null) {694 if (options.asm_path != null and options.bin_path != null) {
686 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {695 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
687 defer bindings.disposeMessage(error_message);
688 return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{696 return diags.fail("LLVM failed to emit bin={s} ir={s}: {s}", .{
689 emit_bin_msg, post_llvm_ir_msg, error_message,697 emit_bin_msg, opt_llvm_ir_msg, error_message,
690 });698 });
691 }699 }
692 lowered_options.bin_filename = null;700 lowered_options.bin_filename = null;
693 lowered_options.llvm_ir_filename = null;701 lowered_options.llvm_ir_filename = null;
694 lowered_options.bitcode_filename = null;702 lowered_options.bitcode_filename = null;
703 lowered_options.llvm_ir_out = null;
695 }704 }
696705 if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str;
697 var time_report_c_str: [*:0]u8 = undefined;
698 if (options.time_report != null) {
699 lowered_options.time_report_out = &time_report_c_str;
700 }
701
702 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;706 lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null;
703 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {707 if (target_machine.emitToFile(module, &error_message, &lowered_options)) {
704 defer bindings.disposeMessage(error_message);708 defer bindings.disposeMessage(error_message);
705 return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{709 return diags.fail("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
706 emit_asm_msg, emit_bin_msg, post_llvm_ir_msg, post_llvm_bc_msg, error_message,710 emit_asm_msg, emit_bin_msg, opt_llvm_ir_msg, opt_llvm_bc_msg, error_message,
707 });711 });
708 }712 }
709 if (options.time_report) |tr| {713 if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{
710 defer std.c.free(time_report_c_str);714 llvm_ir_c_str orelse return error.OutOfMemory,
711 const time_report_data = std.mem.span(time_report_c_str);715 });
712 assert(tr.llvm_pass_timings.len == 0);716 if (options.time_report) |time_report| {
713 tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data);717 assert(time_report.llvm_pass_timings.len == 0);
718 time_report.llvm_pass_timings = try comp.gpa.dupe(u8, std.mem.span(
719 time_report_c_str orelse return error.OutOfMemory,
720 ));
714 }721 }
715 }722 }
716723
...@@ -2184,10 +2191,10 @@ pub const Object = struct {...@@ -2184,10 +2191,10 @@ pub const Object = struct {
2184 .value = try o.builder.string(s),2191 .value = try o.builder.string(s),
2185 } }, &o.builder);2192 } }, &o.builder);
2186 }2193 }
2187 if (owner_mod.resolved_target.llvm_cpu_features) |s| {2194 if (owner_mod.llvm_cpu_features) |s| {
2188 try attributes.addFnAttr(.{ .string = .{2195 try attributes.addFnAttr(.{ .string = .{
2189 .kind = try o.builder.string("target-features"),2196 .kind = try o.builder.string("target-features"),
2190 .value = try o.builder.string(std.mem.span(s)),2197 .value = try o.builder.string(s),
2191 } }, &o.builder);2198 } }, &o.builder);
2192 }2199 }
21932200
src/codegen/llvm/bindings.zig+3-2
...@@ -51,7 +51,7 @@ pub const Module = opaque {...@@ -51,7 +51,7 @@ pub const Module = opaque {
51};51};
5252
53pub const disposeMessage = LLVMDisposeMessage;53pub const disposeMessage = LLVMDisposeMessage;
54extern fn LLVMDisposeMessage(Message: [*:0]const u8) void;54extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void;
5555
56pub const TargetMachine = opaque {56pub const TargetMachine = opaque {
57 pub const FloatABI = enum(c_int) {57 pub const FloatABI = enum(c_int) {
...@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {...@@ -85,7 +85,7 @@ pub const TargetMachine = opaque {
85 pub const EmitOptions = extern struct {85 pub const EmitOptions = extern struct {
86 is_debug: bool,86 is_debug: bool,
87 is_small: bool,87 is_small: bool,
88 time_report_out: ?*[*:0]u8,88 time_report_out: ?*?[*:0]u8,
89 tsan: bool,89 tsan: bool,
90 sancov: bool,90 sancov: bool,
91 lto: LtoPhase,91 lto: LtoPhase,
...@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {...@@ -95,6 +95,7 @@ pub const TargetMachine = opaque {
95 bin_filename: ?[*:0]const u8,95 bin_filename: ?[*:0]const u8,
96 llvm_ir_filename: ?[*:0]const u8,96 llvm_ir_filename: ?[*:0]const u8,
97 bitcode_filename: ?[*:0]const u8,97 bitcode_filename: ?[*:0]const u8,
98 llvm_ir_out: ?*?[*:0]u8,
98 coverage: Coverage,99 coverage: Coverage,
99100
100 pub const LtoPhase = enum(c_int) {101 pub const LtoPhase = enum(c_int) {
src/codegen/riscv64/CodeGen.zig+1-1
...@@ -27,7 +27,7 @@ const Target = std.Target;...@@ -27,7 +27,7 @@ const Target = std.Target;
27const log = std.log.scoped(.riscv_codegen);27const log = std.log.scoped(.riscv_codegen);
28const tracking_log = std.log.scoped(.tracking);28const tracking_log = std.log.scoped(.tracking);
29const verbose_tracking_log = std.log.scoped(.verbose_tracking);29const verbose_tracking_log = std.log.scoped(.verbose_tracking);
30const wip_mir_log = std.log.scoped(.wip_mir);30const wip_mir_log = std.log.scoped(.@"wip-mir");
31const Alignment = InternPool.Alignment;31const Alignment = InternPool.Alignment;
3232
33const bits = @import("bits.zig");33const bits = @import("bits.zig");
src/codegen/x86_64/CodeGen.zig+1-1
...@@ -5,7 +5,7 @@ const link = @import("../../link.zig");...@@ -5,7 +5,7 @@ const link = @import("../../link.zig");
5const log = std.log.scoped(.codegen);5const log = std.log.scoped(.codegen);
6const tracking_log = std.log.scoped(.tracking);6const tracking_log = std.log.scoped(.tracking);
7const verbose_tracking_log = std.log.scoped(.verbose_tracking);7const verbose_tracking_log = std.log.scoped(.verbose_tracking);
8const wip_mir_log = std.log.scoped(.wip_mir);8const wip_mir_log = std.log.scoped(.@"wip-mir");
9const Writer = std.Io.Writer;9const Writer = std.Io.Writer;
1010
11const Air = @import("../../Air.zig");11const Air = @import("../../Air.zig");
src/dev.zig+2
...@@ -112,6 +112,7 @@ pub const Env = enum {...@@ -112,6 +112,7 @@ pub const Env = enum {
112 .loongarch_backend,112 .loongarch_backend,
113 .spork8_backend,113 .spork8_backend,
114 .lld_linker,114 .lld_linker,
115 .llvm_linker,
115 .coff_linker,116 .coff_linker,
116 .elf_linker,117 .elf_linker,
117 .elf2_linker,118 .elf2_linker,
...@@ -333,6 +334,7 @@ pub const Feature = enum {...@@ -333,6 +334,7 @@ pub const Feature = enum {
333 spork8_backend,334 spork8_backend,
334335
335 lld_linker,336 lld_linker,
337 llvm_linker,
336 coff_linker,338 coff_linker,
337 elf_linker,339 elf_linker,
338 elf2_linker,340 elf2_linker,
src/libs/freebsd.zig-4
...@@ -1120,10 +1120,6 @@ fn buildSharedLib(...@@ -1120,10 +1120,6 @@ fn buildSharedLib(
1120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },1120 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
1121 .verbose_cc = comp.verbose_cc,1121 .verbose_cc = comp.verbose_cc,
1122 .verbose_link = comp.verbose_link,1122 .verbose_link = comp.verbose_link,
1123 .verbose_air = comp.verbose_air,
1124 .verbose_llvm_ir = comp.verbose_llvm_ir,
1125 .verbose_llvm_bc = comp.verbose_llvm_bc,
1126 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
1127 .clang_passthrough_mode = comp.clang_passthrough_mode,1123 .clang_passthrough_mode = comp.clang_passthrough_mode,
1128 .version = version,1124 .version = version,
1129 .version_script = .{1125 .version_script = .{
src/libs/glibc.zig-4
...@@ -1268,10 +1268,6 @@ fn buildSharedLib(...@@ -1268,10 +1268,6 @@ fn buildSharedLib(
1268 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },1268 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
1269 .verbose_cc = comp.verbose_cc,1269 .verbose_cc = comp.verbose_cc,
1270 .verbose_link = comp.verbose_link,1270 .verbose_link = comp.verbose_link,
1271 .verbose_air = comp.verbose_air,
1272 .verbose_llvm_ir = comp.verbose_llvm_ir,
1273 .verbose_llvm_bc = comp.verbose_llvm_bc,
1274 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
1275 .clang_passthrough_mode = comp.clang_passthrough_mode,1271 .clang_passthrough_mode = comp.clang_passthrough_mode,
1276 .version = version,1272 .version = version,
1277 .version_script = .{1273 .version_script = .{
src/libs/libcxx.zig-8
...@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!...@@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
260 .c_source_files = c_source_files.items,260 .c_source_files = c_source_files.items,
261 .verbose_cc = comp.verbose_cc,261 .verbose_cc = comp.verbose_cc,
262 .verbose_link = comp.verbose_link,262 .verbose_link = comp.verbose_link,
263 .verbose_air = comp.verbose_air,
264 .verbose_llvm_ir = comp.verbose_llvm_ir,
265 .verbose_llvm_bc = comp.verbose_llvm_bc,
266 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
267 .clang_passthrough_mode = comp.clang_passthrough_mode,263 .clang_passthrough_mode = comp.clang_passthrough_mode,
268 .skip_linker_dependencies = true,264 .skip_linker_dependencies = true,
269 .environ_map = comp.environ_map,265 .environ_map = comp.environ_map,
...@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
445 .c_source_files = c_source_files.items,441 .c_source_files = c_source_files.items,
446 .verbose_cc = comp.verbose_cc,442 .verbose_cc = comp.verbose_cc,
447 .verbose_link = comp.verbose_link,443 .verbose_link = comp.verbose_link,
448 .verbose_air = comp.verbose_air,
449 .verbose_llvm_ir = comp.verbose_llvm_ir,
450 .verbose_llvm_bc = comp.verbose_llvm_bc,
451 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
452 .clang_passthrough_mode = comp.clang_passthrough_mode,444 .clang_passthrough_mode = comp.clang_passthrough_mode,
453 .skip_linker_dependencies = true,445 .skip_linker_dependencies = true,
454 .environ_map = comp.environ_map,446 .environ_map = comp.environ_map,
src/libs/libtsan.zig-4
...@@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -295,10 +295,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
295 .c_source_files = c_source_files.items,295 .c_source_files = c_source_files.items,
296 .verbose_cc = comp.verbose_cc,296 .verbose_cc = comp.verbose_cc,
297 .verbose_link = comp.verbose_link,297 .verbose_link = comp.verbose_link,
298 .verbose_air = comp.verbose_air,
299 .verbose_llvm_ir = comp.verbose_llvm_ir,
300 .verbose_llvm_bc = comp.verbose_llvm_bc,
301 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
302 .clang_passthrough_mode = comp.clang_passthrough_mode,298 .clang_passthrough_mode = comp.clang_passthrough_mode,
303 .skip_linker_dependencies = skip_linker_dependencies,299 .skip_linker_dependencies = skip_linker_dependencies,
304 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,300 .linker_allow_shlib_undefined = linker_allow_shlib_undefined,
src/libs/libunwind.zig-4
...@@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -157,10 +157,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
157 .c_source_files = &c_source_files,157 .c_source_files = &c_source_files,
158 .verbose_cc = comp.verbose_cc,158 .verbose_cc = comp.verbose_cc,
159 .verbose_link = comp.verbose_link,159 .verbose_link = comp.verbose_link,
160 .verbose_air = comp.verbose_air,
161 .verbose_llvm_ir = comp.verbose_llvm_ir,
162 .verbose_llvm_bc = comp.verbose_llvm_bc,
163 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
164 .clang_passthrough_mode = comp.clang_passthrough_mode,160 .clang_passthrough_mode = comp.clang_passthrough_mode,
165 .skip_linker_dependencies = true,161 .skip_linker_dependencies = true,
166 .environ_map = comp.environ_map,162 .environ_map = comp.environ_map,
src/libs/musl.zig-3
...@@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -246,9 +246,6 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
246 .emit_bin = .yes_cache,246 .emit_bin = .yes_cache,
247 .verbose_cc = comp.verbose_cc,247 .verbose_cc = comp.verbose_cc,
248 .verbose_link = comp.verbose_link,248 .verbose_link = comp.verbose_link,
249 .verbose_air = comp.verbose_air,
250 .verbose_llvm_ir = comp.verbose_llvm_ir,
251 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
252 .clang_passthrough_mode = comp.clang_passthrough_mode,249 .clang_passthrough_mode = comp.clang_passthrough_mode,
253 .c_source_files = &.{250 .c_source_files = &.{
254 .{251 .{
src/libs/netbsd.zig-4
...@@ -771,10 +771,6 @@ fn buildSharedLib(...@@ -771,10 +771,6 @@ fn buildSharedLib(
771 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },771 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
772 .verbose_cc = comp.verbose_cc,772 .verbose_cc = comp.verbose_cc,
773 .verbose_link = comp.verbose_link,773 .verbose_link = comp.verbose_link,
774 .verbose_air = comp.verbose_air,
775 .verbose_llvm_ir = comp.verbose_llvm_ir,
776 .verbose_llvm_bc = comp.verbose_llvm_bc,
777 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
778 .clang_passthrough_mode = comp.clang_passthrough_mode,774 .clang_passthrough_mode = comp.clang_passthrough_mode,
779 .version = version,775 .version = version,
780 .soname = soname,776 .soname = soname,
src/libs/openbsd.zig-4
...@@ -691,10 +691,6 @@ fn buildSharedLib(...@@ -691,10 +691,6 @@ fn buildSharedLib(
691 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },691 .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) },
692 .verbose_cc = comp.verbose_cc,692 .verbose_cc = comp.verbose_cc,
693 .verbose_link = comp.verbose_link,693 .verbose_link = comp.verbose_link,
694 .verbose_air = comp.verbose_air,
695 .verbose_llvm_ir = comp.verbose_llvm_ir,
696 .verbose_llvm_bc = comp.verbose_llvm_bc,
697 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
698 .clang_passthrough_mode = comp.clang_passthrough_mode,694 .clang_passthrough_mode = comp.clang_passthrough_mode,
699 .soname = soname,695 .soname = soname,
700 .c_source_files = &c_source_files,696 .c_source_files = &c_source_files,
src/link.zig+35-4
...@@ -550,6 +550,7 @@ pub const File = struct {...@@ -550,6 +550,7 @@ pub const File = struct {
550 return &ptr.base;550 return &ptr.base;
551 },551 },
552 .lld => unreachable, // not known from ofmt552 .lld => unreachable, // not known from ofmt
553 .llvm => |tag| return createDummy(arena, tag, comp, emit),
553 }554 }
554 }555 }
555556
...@@ -573,9 +574,26 @@ pub const File = struct {...@@ -573,9 +574,26 @@ pub const File = struct {
573 return &ptr.base;574 return &ptr.base;
574 },575 },
575 .lld => unreachable, // not known from ofmt576 .lld => unreachable, // not known from ofmt
577 .llvm => |tag| return createDummy(arena, tag, comp, emit),
576 }578 }
577 }579 }
578580
581 fn createDummy(arena: Allocator, tag: Tag, comp: *Compilation, path: Path) Allocator.Error!*File {
582 const base = try arena.create(File);
583 base.* = .{
584 .tag = tag,
585 .comp = comp,
586 .emit = path,
587 .file = null,
588 .gc_sections = false,
589 .print_gc_sections = false,
590 .build_id = .none,
591 .allow_shlib_undefined = false,
592 .stack_size = 0,
593 };
594 return base;
595 }
596
579 pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {597 pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn {
580 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;598 return if (dev.env.supports(tag.devFeature()) and base.tag == tag) @fieldParentPtr("base", base) else null;
581 }599 }
...@@ -606,7 +624,7 @@ pub const File = struct {...@@ -606,7 +624,7 @@ pub const File = struct {
606 const gpa = comp.gpa;624 const gpa = comp.gpa;
607 const io = comp.io;625 const io = comp.io;
608 switch (base.tag) {626 switch (base.tag) {
609 .lld => assert(base.file == null),627 .lld, .llvm => assert(base.file == null),
610 .elf, .macho, .wasm => {628 .elf, .macho, .wasm => {
611 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });629 dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker });
612 if (base.file != null) return;630 if (base.file != null) return;
...@@ -706,7 +724,7 @@ pub const File = struct {...@@ -706,7 +724,7 @@ pub const File = struct {
706 if (!base.canMakeExecutable())724 if (!base.canMakeExecutable())
707 return;725 return;
708 switch (base.tag) {726 switch (base.tag) {
709 .lld => assert(base.file == null),727 .lld, .llvm => assert(base.file == null),
710 .elf => if (base.file) |f| {728 .elf => if (base.file) |f| {
711 dev.check(.elf_linker);729 dev.check(.elf_linker);
712 f.close(io);730 f.close(io);
...@@ -827,6 +845,7 @@ pub const File = struct {...@@ -827,6 +845,7 @@ pub const File = struct {
827845
828 switch (base.tag) {846 switch (base.tag) {
829 .lld => unreachable,847 .lld => unreachable,
848 .llvm => unreachable,
830 .plan9 => unreachable,849 .plan9 => unreachable,
831 inline else => |tag| {850 inline else => |tag| {
832 dev.check(tag.devFeature());851 dev.check(tag.devFeature());
...@@ -862,6 +881,7 @@ pub const File = struct {...@@ -862,6 +881,7 @@ pub const File = struct {
862 assert(pt.zcu.llvm_object == null);881 assert(pt.zcu.llvm_object == null);
863 switch (base.tag) {882 switch (base.tag) {
864 .lld => unreachable,883 .lld => unreachable,
884 .llvm => unreachable,
865 .plan9 => unreachable,885 .plan9 => unreachable,
866 inline else => |tag| {886 inline else => |tag| {
867 dev.check(tag.devFeature());887 dev.check(tag.devFeature());
...@@ -897,6 +917,7 @@ pub const File = struct {...@@ -897,6 +917,7 @@ pub const File = struct {
897 }917 }
898 switch (base.tag) {918 switch (base.tag) {
899 .lld => unreachable,919 .lld => unreachable,
920 .llvm => unreachable,
900 .plan9 => unreachable,921 .plan9 => unreachable,
901 .spirv => {},922 .spirv => {},
902 .coff => {},923 .coff => {},
...@@ -941,6 +962,7 @@ pub const File = struct {...@@ -941,6 +962,7 @@ pub const File = struct {
941 base.releaseLock();962 base.releaseLock();
942 if (base.file) |f| f.close(io);963 if (base.file) |f| f.close(io);
943 switch (base.tag) {964 switch (base.tag) {
965 .llvm => {},
944 .plan9 => unreachable,966 .plan9 => unreachable,
945 inline else => |tag| {967 inline else => |tag| {
946 dev.check(tag.devFeature());968 dev.check(tag.devFeature());
...@@ -1003,6 +1025,7 @@ pub const File = struct {...@@ -1003,6 +1025,7 @@ pub const File = struct {
1003 }1025 }
1004 assert(base.post_prelink);1026 assert(base.post_prelink);
1005 switch (base.tag) {1027 switch (base.tag) {
1028 .llvm => {},
1006 .plan9 => unreachable,1029 .plan9 => unreachable,
1007 inline else => |tag| {1030 inline else => |tag| {
1008 dev.check(tag.devFeature());1031 dev.check(tag.devFeature());
...@@ -1030,6 +1053,7 @@ pub const File = struct {...@@ -1030,6 +1053,7 @@ pub const File = struct {
10301053
1031 switch (base.tag) {1054 switch (base.tag) {
1032 .lld => unreachable,1055 .lld => unreachable,
1056 .llvm => unreachable,
1033 .plan9 => unreachable,1057 .plan9 => unreachable,
1034 inline else => |tag| {1058 inline else => |tag| {
1035 dev.check(tag.devFeature());1059 dev.check(tag.devFeature());
...@@ -1056,6 +1080,7 @@ pub const File = struct {...@@ -1056,6 +1080,7 @@ pub const File = struct {
1056 assert(base.comp.zcu.?.llvm_object == null);1080 assert(base.comp.zcu.?.llvm_object == null);
1057 switch (base.tag) {1081 switch (base.tag) {
1058 .lld => unreachable,1082 .lld => unreachable,
1083 .llvm => unreachable,
1059 .c => unreachable,1084 .c => unreachable,
1060 .spirv => unreachable,1085 .spirv => unreachable,
1061 .wasm => unreachable,1086 .wasm => unreachable,
...@@ -1078,6 +1103,7 @@ pub const File = struct {...@@ -1078,6 +1103,7 @@ pub const File = struct {
1078 assert(pt.zcu.llvm_object == null);1103 assert(pt.zcu.llvm_object == null);
1079 switch (base.tag) {1104 switch (base.tag) {
1080 .lld => unreachable,1105 .lld => unreachable,
1106 .llvm => unreachable,
1081 .c => unreachable,1107 .c => unreachable,
1082 .spirv => unreachable,1108 .spirv => unreachable,
1083 .wasm => unreachable,1109 .wasm => unreachable,
...@@ -1095,6 +1121,7 @@ pub const File = struct {...@@ -1095,6 +1121,7 @@ pub const File = struct {
1095 assert(base.comp.zcu.?.llvm_object == null);1121 assert(base.comp.zcu.?.llvm_object == null);
1096 switch (base.tag) {1122 switch (base.tag) {
1097 .lld => unreachable,1123 .lld => unreachable,
1124 .llvm => unreachable,
1098 .c => unreachable,1125 .c => unreachable,
1099 .spirv => unreachable,1126 .spirv => unreachable,
1100 .wasm => unreachable,1127 .wasm => unreachable,
...@@ -1124,6 +1151,7 @@ pub const File = struct {...@@ -1124,6 +1151,7 @@ pub const File = struct {
1124 .spirv,1151 .spirv,
1125 .plan9,1152 .plan9,
1126 .lld,1153 .lld,
1154 .llvm,
1127 .spork8,1155 .spork8,
1128 => return .unimplemented,1156 => return .unimplemented,
1129 inline else => |tag| {1157 inline else => |tag| {
...@@ -1240,7 +1268,7 @@ pub const File = struct {...@@ -1240,7 +1268,7 @@ pub const File = struct {
1240 dev.check(tag.devFeature());1268 dev.check(tag.devFeature());
1241 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);1269 return @as(*tag.Type(), @fieldParentPtr("base", base)).loadInput(input);
1242 },1270 },
1243 .c, .spork8, .plan9, .lld => {},1271 .c, .spork8, .plan9, .lld, .llvm => {},
1244 }1272 }
1245 }1273 }
12461274
...@@ -1352,6 +1380,7 @@ pub const File = struct {...@@ -1352,6 +1380,7 @@ pub const File = struct {
1352 coff,1380 coff,
1353 elf,1381 elf,
1354 elf2,1382 elf2,
1383 llvm,
1355 macho,1384 macho,
1356 macho2,1385 macho2,
1357 c,1386 c,
...@@ -1366,13 +1395,14 @@ pub const File = struct {...@@ -1366,13 +1395,14 @@ pub const File = struct {
1366 .coff => Coff,1395 .coff => Coff,
1367 .elf => Elf,1396 .elf => Elf,
1368 .elf2 => Elf2,1397 .elf2 => Elf2,
1398 .llvm => File,
1369 .macho => MachO,1399 .macho => MachO,
1370 .macho2 => MachO2,1400 .macho2 => MachO2,
1371 .c => C,1401 .c => C,
1372 .wasm => Wasm,1402 .wasm => Wasm,
1373 .spirv => Spirv,1403 .spirv => Spirv,
1374 .lld => Lld,1404 .lld => Lld,
1375 .plan9 => comptime unreachable,1405 .plan9 => unreachable,
1376 .spork8 => Spork8,1406 .spork8 => Spork8,
1377 };1407 };
1378 }1408 }
...@@ -1381,6 +1411,7 @@ pub const File = struct {...@@ -1381,6 +1411,7 @@ pub const File = struct {
1381 return switch (ofmt) {1411 return switch (ofmt) {
1382 .coff => .coff,1412 .coff => .coff,
1383 .elf => if (use_new_linker) .elf2 else .elf,1413 .elf => if (use_new_linker) .elf2 else .elf,
1414 .llvmbc, .llvmir => .llvm,
1384 .macho => if (use_new_linker) .macho2 else .macho,1415 .macho => if (use_new_linker) .macho2 else .macho,
1385 .wasm => .wasm,1416 .wasm => .wasm,
1386 .plan9 => .plan9,1417 .plan9 => .plan9,
src/link/Elf.zig+1-3
...@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -860,9 +860,7 @@ fn flushInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
860860
861 // Dump the state for easy debugging.861 // Dump the state for easy debugging.
862 // State can be dumped via `--debug-log link_state`.862 // State can be dumped via `--debug-log link_state`.
863 if (build_options.enable_logging) {863 state_log.debug("{f}", .{self.dumpState()});
864 state_log.debug("{f}", .{self.dumpState()});
865 }
866864
867 // Beyond this point, everything has been allocated a virtual address and we can resolve865 // Beyond this point, everything has been allocated a virtual address and we can resolve
868 // the relocations, and commit objects to file.866 // the relocations, and commit objects to file.
src/link/Elf/ZigObject.zig+1-1
...@@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {...@@ -291,7 +291,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
291 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;291 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
292 }292 }
293293
294 if (build_options.enable_logging) {294 if (build_options.enable_debug_extensions) {
295 const active = elf_file.base.comp.zcu.?.activate(tid);295 const active = elf_file.base.comp.zcu.?.activate(tid);
296 defer active.deactivate();296 defer active.deactivate();
297 for (self.navs.keys(), self.navs.values()) |nav_index, meta| {297 for (self.navs.keys(), self.navs.values()) |nav_index, meta| {
src/link/Elf/gc.zig+1-1
...@@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool {...@@ -98,7 +98,7 @@ fn markAtom(atom: *Atom) bool {
98}98}
9999
100fn markLive(atom: *Atom, elf_file: *Elf) void {100fn markLive(atom: *Atom, elf_file: *Elf) void {
101 if (@import("build_options").enable_logging) track_live_level.incr();101 if (@import("build_options").enable_debug_extensions) track_live_level.incr();
102102
103 assert(atom.visited);103 assert(atom.visited);
104 const file = atom.file(elf_file).?;104 const file = atom.file(elf_file).?;
src/link/Elf/relocatable.zig+4-10
...@@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {...@@ -51,9 +51,7 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
51 try allocateAllocSections(elf_file);51 try allocateAllocSections(elf_file);
52 try elf_file.allocateNonAllocSections();52 try elf_file.allocateNonAllocSections();
5353
54 if (build_options.enable_logging) {54 state_log.debug("{f}", .{elf_file.dumpState()});
55 state_log.debug("{f}", .{elf_file.dumpState()});
56 }
5755
58 try elf_file.writeMergeSections();56 try elf_file.writeMergeSections();
59 try writeSyntheticSections(elf_file);57 try writeSyntheticSections(elf_file);
...@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {...@@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void {
117 break :blk pos;115 break :blk pos;
118 };116 };
119117
120 if (build_options.enable_logging) {118 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});
121 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)});119 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
122 state_log.debug("ar_strtab\n{f}\n", .{ar_strtab});
123 }
124120
125 const buffer = try gpa.alloc(u8, total_size);121 const buffer = try gpa.alloc(u8, total_size);
126 defer gpa.free(buffer);122 defer gpa.free(buffer);
...@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {...@@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void {
193 try allocateAllocSections(elf_file);189 try allocateAllocSections(elf_file);
194 try elf_file.allocateNonAllocSections();190 try elf_file.allocateNonAllocSections();
195191
196 if (build_options.enable_logging) {192 state_log.debug("{f}", .{elf_file.dumpState()});
197 state_log.debug("{f}", .{elf_file.dumpState()});
198 }
199193
200 try writeAtoms(elf_file);194 try writeAtoms(elf_file);
201 try elf_file.writeMergeSections();195 try elf_file.writeMergeSections();
src/link/MachO.zig+1-3
...@@ -456,9 +456,7 @@ pub fn flush(...@@ -456,9 +456,7 @@ pub fn flush(
456 self.allocateSegments();456 self.allocateSegments();
457 self.allocateSyntheticSymbols();457 self.allocateSyntheticSymbols();
458458
459 if (build_options.enable_logging) {459 state_log.debug("{f}", .{self.dumpState()});
460 state_log.debug("{f}", .{self.dumpState()});
461 }
462460
463 // Beyond this point, everything has been allocated a virtual address and we can resolve461 // Beyond this point, everything has been allocated a virtual address and we can resolve
464 // the relocations, and commit objects to file.462 // the relocations, and commit objects to file.
src/link/MachO/dead_strip.zig+2-1
...@@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {...@@ -123,8 +123,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {
123 atom.getName(macho_file),123 atom.getName(macho_file),
124 });124 });
125125
126 if (build_options.enable_logging)126 if (build_options.enable_debug_extensions) {
127 track_live_level.incr();127 track_live_level.incr();
128 }
128129
129 for (atom.getRelocs(macho_file)) |rel| {130 for (atom.getRelocs(macho_file)) |rel| {
130 const target_atom = switch (rel.tag) {131 const target_atom = switch (rel.tag) {
src/link/MachO/relocatable.zig+3-9
...@@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -61,9 +61,7 @@ pub fn flushObject(macho_file: *MachO, comp: *Compilation) link.Error!void {
61 };61 };
62 allocateSegment(macho_file);62 allocateSegment(macho_file);
6363
64 if (build_options.enable_logging) {64 state_log.debug("{f}", .{macho_file.dumpState()});
65 state_log.debug("{f}", .{macho_file.dumpState()});
66 }
6765
68 try writeSections(macho_file);66 try writeSections(macho_file);
69 sortRelocs(macho_file);67 sortRelocs(macho_file);
...@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
107 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});105 return diags.fail("failed to allocate sections: {s}", .{@errorName(err)});
108 allocateSegment(macho_file);106 allocateSegment(macho_file);
109107
110 if (build_options.enable_logging) {108 state_log.debug("{f}", .{macho_file.dumpState()});
111 state_log.debug("{f}", .{macho_file.dumpState()});
112 }
113109
114 try writeSections(macho_file);110 try writeSections(macho_file);
115 sortRelocs(macho_file);111 sortRelocs(macho_file);
...@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {...@@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void {
185 break :blk pos;181 break :blk pos;
186 };182 };
187183
188 if (build_options.enable_logging) {184 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
189 state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)});
190 }
191185
192 const buffer = try gpa.alloc(u8, total_size);186 const buffer = try gpa.alloc(u8, total_size);
193 defer gpa.free(buffer);187 defer gpa.free(buffer);
src/main.zig+42-79
...@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;...@@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20;
4242
43pub const std_options: std.Options = .{43pub const std_options: std.Options = .{
44 .logFn = log,44 .logFn = log,
4545 .log_level = switch (build_options.log_level) {
46 .log_level = switch (builtin.mode) {46 inline else => |log_level| @field(std.log.Level, @tagName(log_level)),
47 .debug => .debug,
48 .safe, .fast => .info,
49 .small => .err,
50 },47 },
51};48};
52pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;49pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null;
...@@ -104,7 +101,7 @@ const normal_usage =...@@ -104,7 +101,7 @@ const normal_usage =
104 \\ help Print this help and exit101 \\ help Print this help and exit
105 \\ cache-cat Print a zig-cache manifest file as zon102 \\ cache-cat Print a zig-cache manifest file as zon
106 \\ std View standard library documentation in a browser103 \\ std View standard library documentation in a browser
107 \\ libc Display native libc paths file or validate one104 \\ libc Print native libc paths file or validate one
108 \\ targets List available compilation targets105 \\ targets List available compilation targets
109 \\ version Print version number and exit106 \\ version Print version number and exit
110 \\ zen Print Zen of Zig and exit107 \\ zen Print Zen of Zig and exit
...@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++...@@ -126,7 +123,15 @@ const debug_usage = normal_usage ++
126123
127const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;124const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
128125
129var log_scopes: std.ArrayList([]const u8) = .empty;126var log_scopes: std.array_hash_map.String(void) = .empty;
127
128pub fn debugLogScopeEnabled(scope: []const u8) bool {
129 switch (build_options.log_level) {
130 else => {},
131 .debug => if (log_scopes.contains(scope)) return true,
132 }
133 return false;
134}
130135
131pub fn log(136pub fn log(
132 comptime level: std.log.Level,137 comptime level: std.log.Level,
...@@ -135,18 +140,11 @@ pub fn log(...@@ -135,18 +140,11 @@ pub fn log(
135 args: anytype,140 args: anytype,
136) void {141) void {
137 // Hide debug messages unless:142 // Hide debug messages unless:
138 // * logging enabled with `-Dlog`.143 // * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`.
139 // * the --debug-log arg for the scope has been provided144 // * the --debug-log arg for the scope has been provided
140 if (@backingInt(level) > @backingInt(std.options.log_level) or145 switch (level) {
141 @backingInt(level) > @backingInt(std.log.Level.info))146 else => {},
142 {147 .debug => if (!debugLogScopeEnabled(@tagName(scope))) return,
143 if (!build_options.enable_logging) return;
144
145 const scope_name = @tagName(scope);
146 for (log_scopes.items) |log_scope| {
147 if (mem.eql(u8, log_scope, scope_name))
148 break;
149 } else return;
150 }148 }
151149
152 // Otherwise, use the default implementation.150 // Otherwise, use the default implementation.
...@@ -557,11 +555,14 @@ const compile_usage =...@@ -557,11 +555,14 @@ const compile_usage =
557 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation555 \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation
558 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL556 \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL
559 \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL557 \\ -fno-emit-implib Do not produce an import .lib when building a Windows DLL
560 \\ --show-builtin Output the source of @import("builtin") then exit
561 \\ --cache-dir [path] Override the local cache directory558 \\ --cache-dir [path] Override the local cache directory
562 \\ --global-cache-dir [path] Override the global cache directory559 \\ --global-cache-dir [path] Override the global cache directory
563 \\ --zig-lib-dir [path] Override path to Zig installation lib directory560 \\ --zig-lib-dir [path] Override path to Zig installation lib directory
564 \\ --build-root [path] Override path to project source files561 \\ --build-root [path] Override path to project source files
562 \\ --show-builtin Output the source of @import("builtin") then exit
563 \\ --time-report Send timing diagnostics to '--listen' clients
564 \\ --verbose-cc Print C compiler commands before executing them
565 \\ --verbose-link Print linker commands before executing them
565 \\566 \\
566 \\Global Compile Options:567 \\Global Compile Options:
567 \\ --name [name] Compilation unit name (not a file path)568 \\ --name [name] Compilation unit name (not a file path)
...@@ -593,7 +594,6 @@ const compile_usage =...@@ -593,7 +594,6 @@ const compile_usage =
593 \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues594 \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues
594 \\ -mexec-model=[value] (WASI) Execution model595 \\ -mexec-model=[value] (WASI) Execution model
595 \\ -municode (Windows) Use wmain/wWinMain as entry point596 \\ -municode (Windows) Use wmain/wWinMain as entry point
596 \\ --time-report Send timing diagnostics to '--listen' clients
597 \\597 \\
598 \\Per-Module Compile Options:598 \\Per-Module Compile Options:
599 \\ --dep [[import=]name] Add an entry to the next module's import table599 \\ --dep [[import=]name] Add an entry to the next module's import table
...@@ -604,13 +604,15 @@ const compile_usage =...@@ -604,13 +604,15 @@ const compile_usage =
604 \\ safe Enable both safety checks and machine code optimizations604 \\ safe Enable both safety checks and machine code optimizations
605 \\ small Prioritize small binary size. Safety checks off.605 \\ small Prioritize small binary size. Safety checks off.
606 \\ -ofmt=[fmt] Override target object format606 \\ -ofmt=[fmt] Override target object format
607 \\ elf Executable and Linking Format
608 \\ c C source code607 \\ c C source code
609 \\ wasm WebAssembly
610 \\ coff Common Object File Format (Windows)608 \\ coff Common Object File Format (Windows)
609 \\ elf Executable and Linking Format
610 \\ llvmir LLVM text intermediate representation
611 \\ llvmbc LLVM binary intermediate representation
611 \\ macho macOS relocatables612 \\ macho macOS relocatables
612 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
613 \\ plan9 Plan 9 from Bell Labs object format613 \\ plan9 Plan 9 from Bell Labs object format
614 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
615 \\ wasm WebAssembly
614 \\ hex (planned feature) Intel IHEX616 \\ hex (planned feature) Intel IHEX
615 \\ raw (planned feature) Dump machine code directly617 \\ raw (planned feature) Dump machine code directly
616 \\ -mcpu [cpu] Specify target CPU and feature set618 \\ -mcpu [cpu] Specify target CPU and feature set
...@@ -791,15 +793,6 @@ const compile_usage =...@@ -791,15 +793,6 @@ const compile_usage =
791 \\Debug Options (Zig Compiler Development):793 \\Debug Options (Zig Compiler Development):
792 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes794 \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes
793 \\ -fstack-report Print stack size diagnostics795 \\ -fstack-report Print stack size diagnostics
794 \\ --verbose-link Display linker invocations
795 \\ --verbose-cc Display C compiler invocations
796 \\ --verbose-air Enable compiler debug output for Zig AIR
797 \\ --verbose-intern-pool Enable compiler debug output for InternPool
798 \\ --verbose-generic-instances Enable compiler debug output for generic instance generation
799 \\ --verbose-llvm-ir[=path] Enable compiler debug output for unoptimized LLVM IR
800 \\ --verbose-llvm-bc=[path] Enable compiler debug output for unoptimized LLVM BC
801 \\ --verbose-cimport Enable compiler debug output for C imports
802 \\ --verbose-llvm-cpu-features Enable compiler debug output for LLVM CPU features
803 \\ --debug-log [scope] Enable printing debug/info log messages for scope796 \\ --debug-log [scope] Enable printing debug/info log messages for scope
804 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error797 \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error
805 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting798 \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting
...@@ -933,17 +926,11 @@ fn buildOutputType(...@@ -933,17 +926,11 @@ fn buildOutputType(
933 var listen: Listen = .none;926 var listen: Listen = .none;
934 var debug_compile_errors = false;927 var debug_compile_errors = false;
935 var debug_incremental = false;928 var debug_incremental = false;
936 var verbose_link = (native_os != .wasi or builtin.link_libc) and
937 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
938 var verbose_cc = (native_os != .wasi or builtin.link_libc) and929 var verbose_cc = (native_os != .wasi or builtin.link_libc) and
939 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);930 EnvVar.ZIG_VERBOSE_CC.isSet(environ_map);
940 var verbose_air = false;931 var verbose_link = (native_os != .wasi or builtin.link_libc) and
941 var verbose_intern_pool = false;932 EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map);
942 var verbose_generic_instances = false;
943 var verbose_llvm_ir: ?[]const u8 = null;
944 var verbose_llvm_bc: ?[]const u8 = null;
945 var link_depfile: ?[]const u8 = null;933 var link_depfile: ?[]const u8 = null;
946 var verbose_llvm_cpu_features = false;
947 var time_report = false;934 var time_report = false;
948 var stack_report = false;935 var stack_report = false;
949 var show_builtin = false;936 var show_builtin = false;
...@@ -1809,24 +1796,10 @@ fn buildOutputType(...@@ -1809,24 +1796,10 @@ fn buildOutputType(
1809 } else {1796 } else {
1810 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});1797 warn("Zig was compiled without debug extensions. --debug-compile-errors has no effect.", .{});
1811 }1798 }
1812 } else if (mem.eql(u8, arg, "--verbose-link")) {
1813 verbose_link = true;
1814 } else if (mem.eql(u8, arg, "--verbose-cc")) {1799 } else if (mem.eql(u8, arg, "--verbose-cc")) {
1815 verbose_cc = true;1800 verbose_cc = true;
1816 } else if (mem.eql(u8, arg, "--verbose-air")) {1801 } else if (mem.eql(u8, arg, "--verbose-link")) {
1817 verbose_air = true;1802 verbose_link = true;
1818 } else if (mem.eql(u8, arg, "--verbose-intern-pool")) {
1819 verbose_intern_pool = true;
1820 } else if (mem.eql(u8, arg, "--verbose-generic-instances")) {
1821 verbose_generic_instances = true;
1822 } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) {
1823 verbose_llvm_ir = "-";
1824 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-ir=")) |rest| {
1825 verbose_llvm_ir = rest;
1826 } else if (mem.cutPrefix(u8, arg, "--verbose-llvm-bc=")) |rest| {
1827 verbose_llvm_bc = rest;
1828 } else if (mem.eql(u8, arg, "--verbose-llvm-cpu-features")) {
1829 verbose_llvm_cpu_features = true;
1830 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {1803 } else if (mem.cutPrefix(u8, arg, "-T")) |rest| {
1831 linker_script = rest;1804 linker_script = rest;
1832 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {1805 } else if (mem.cutPrefix(u8, arg, "-L")) |rest| {
...@@ -3395,7 +3368,7 @@ fn buildOutputType(...@@ -3395,7 +3368,7 @@ fn buildOutputType(
3395 const target = &main_mod.resolved_target.result;3368 const target = &main_mod.resolved_target.result;
33963369
3397 if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) {3370 if (target.cpu.arch == .arc or target.cpu.arch.isNvptx()) {
3398 if (emit_bin != .no and create_module.resolved_options.use_llvm) {3371 if (emit_bin != .no and target.ofmt != .llvmbc and target.ofmt != .llvmir and create_module.resolved_options.use_llvm) {
3399 fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{3372 fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{
3400 @tagName(target.cpu.arch),3373 @tagName(target.cpu.arch),
3401 });3374 });
...@@ -3729,13 +3702,7 @@ fn buildOutputType(...@@ -3729,13 +3702,7 @@ fn buildOutputType(
3729 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,3702 .libc_installation = if (create_module.libc_installation) |*lci| lci else null,
3730 .verbose_cc = verbose_cc,3703 .verbose_cc = verbose_cc,
3731 .verbose_link = verbose_link,3704 .verbose_link = verbose_link,
3732 .verbose_air = verbose_air,
3733 .verbose_intern_pool = verbose_intern_pool,
3734 .verbose_generic_instances = verbose_generic_instances,
3735 .verbose_llvm_ir = verbose_llvm_ir,
3736 .verbose_llvm_bc = verbose_llvm_bc,
3737 .link_depfile = link_depfile,3705 .link_depfile = link_depfile,
3738 .verbose_llvm_cpu_features = verbose_llvm_cpu_features,
3739 .time_report = time_report,3706 .time_report = time_report,
3740 .stack_report = stack_report,3707 .stack_report = stack_report,
3741 .build_id = build_id,3708 .build_id = build_id,
...@@ -3956,10 +3923,10 @@ fn buildOutputType(...@@ -3956,10 +3923,10 @@ fn buildOutputType(
3956 });3923 });
3957 }3924 }
39583925
3959 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc));3926 try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc));
3960 for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });3927 for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope });
3961 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3962 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");3928 if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc");
3929 if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link");
3963 }3930 }
39643931
3965 try runOrTest(3932 try runOrTest(
...@@ -4446,13 +4413,12 @@ fn serve(...@@ -4446,13 +4413,12 @@ fn serve(
4446 switch (hdr.tag) {4413 switch (hdr.tag) {
4447 .exit => return cleanExit(io),4414 .exit => return cleanExit(io),
4448 .update => {4415 .update => {
4449 file_system_inputs.clearRetainingCapacity();
4450
4451 if (arg_mode == .translate_c) {4416 if (arg_mode == .translate_c) {
4452 var arena_instance = std.heap.ArenaAllocator.init(gpa);4417 var arena_instance = std.heap.ArenaAllocator.init(gpa);
4453 defer arena_instance.deinit();4418 defer arena_instance.deinit();
4454 const arena = arena_instance.allocator();4419 const arena = arena_instance.allocator();
4455 var output: Compilation.TranslateCResult = undefined;4420 var output: Compilation.TranslateCResult = undefined;
4421 file_system_inputs.clearRetainingCapacity();
4456 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map);4422 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map);
4457 defer output.deinit(gpa);4423 defer output.deinit(gpa);
44584424
...@@ -4470,7 +4436,6 @@ fn serve(...@@ -4470,7 +4436,6 @@ fn serve(
44704436
4471 continue;4437 continue;
4472 }4438 }
4473
4474 try comp.makeBinFileWritable();4439 try comp.makeBinFileWritable();
4475 try comp.update(main_progress_node);4440 try comp.update(main_progress_node);
4476 try comp.makeBinFileExecutable();4441 try comp.makeBinFileExecutable();
...@@ -4496,7 +4461,6 @@ fn serve(...@@ -4496,7 +4461,6 @@ fn serve(
4496 //);4461 //);
4497 },4462 },
4498 .hot_update => {4463 .hot_update => {
4499 file_system_inputs.clearRetainingCapacity();
4500 if (child_pid) |pid| {4464 if (child_pid) |pid| {
4501 try comp.hotCodeSwap(main_progress_node, pid);4465 try comp.hotCodeSwap(main_progress_node, pid);
4502 try serveUpdateResults(&server, comp);4466 try serveUpdateResults(&server, comp);
...@@ -5627,17 +5591,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5627,17 +5591,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
5627 }5591 }
5628 }5592 }
56295593
5630 const display_path = zig_source_path orelse "<stdin>";5594 const print_path = zig_source_path orelse "<stdin>";
5631 const source: [:0]const u8 = s: {5595 const source: [:0]const u8 = s: {
5632 var f = if (zig_source_path) |p| file: {5596 var f = if (zig_source_path) |p| file: {
5633 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {5597 break :file Io.Dir.cwd().openFile(io, p, .{}) catch |err| {
5634 fatal("unable to open file {q} for ast-check: {t}", .{ display_path, err });5598 fatal("unable to open file {q} for ast-check: {t}", .{ print_path, err });
5635 };5599 };
5636 } else Io.File.stdin();5600 } else Io.File.stdin();
5637 defer if (zig_source_path != null) f.close(io);5601 defer if (zig_source_path != null) f.close(io);
5638 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);5602 var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer);
5639 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {5603 break :s std.zig.readSourceFileToEndAlloc(arena, &file_reader) catch |err| {
5640 fatal("unable to load file {q} for ast-check: {t}", .{ display_path, err });5604 fatal("unable to load file {q} for ast-check: {t}", .{ print_path, err });
5641 };5605 };
5642 };5606 };
56435607
...@@ -5661,7 +5625,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5661,7 +5625,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
56615625
5662 if (zir.hasCompileErrors()) {5626 if (zir.hasCompileErrors()) {
5663 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);5627 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
5664 try wip_errors.addZirErrorMessages(zir, tree, source, display_path);5628 try wip_errors.addZirErrorMessages(zir, tree, source, print_path);
5665 var error_bundle = try wip_errors.toOwnedBundle("");5629 var error_bundle = try wip_errors.toOwnedBundle("");
5666 try error_bundle.renderToStderr(io, .{}, color);5630 try error_bundle.renderToStderr(io, .{}, color);
5667 if (zir.loweringFailed()) {5631 if (zir.loweringFailed()) {
...@@ -5731,7 +5695,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:...@@ -5731,7 +5695,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map:
5731 const zoir = try ZonGen.generate(arena, tree, .{});5695 const zoir = try ZonGen.generate(arena, tree, .{});
5732 if (zoir.hasCompileErrors()) {5696 if (zoir.hasCompileErrors()) {
5733 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);5697 var wip_errors: std.zig.ErrorBundle.Wip = try .init(arena);
5734 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);5698 try wip_errors.addZoirErrorMessages(zoir, tree, source, print_path);
5735 var error_bundle = try wip_errors.toOwnedBundle("");5699 var error_bundle = try wip_errors.toOwnedBundle("");
5736 error_bundle.renderToStderr(io, .{}, color) catch {};5700 error_bundle.renderToStderr(io, .{}, color) catch {};
5737 process.exit(1);5701 process.exit(1);
...@@ -6254,9 +6218,8 @@ fn randInt(io: Io, comptime T: type) T {...@@ -6254,9 +6218,8 @@ fn randInt(io: Io, comptime T: type) T {
6254}6218}
62556219
6256fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {6220fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void {
6257 if (!build_options.enable_logging) {6221 switch (build_options.log_level) {
6258 warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{});6222 else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}),
6259 } else {6223 .debug => try log_scopes.put(arena, try arena.dupe(u8, scope_name), {}),
6260 try log_scopes.append(arena, scope_name);
6261 }6224 }
6262}6225}
src/target.zig+2
...@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)...@@ -193,6 +193,8 @@ pub fn hasLlvmSupport(target: *const std.Target, ofmt: std.Target.ObjectFormat)
193 .coff,193 .coff,
194 .elf,194 .elf,
195 .hex,195 .hex,
196 .llvmbc,
197 .llvmir,
196 .macho,198 .macho,
197 .spirv,199 .spirv,
198 .raw,200 .raw,
src/zig_llvm.cpp+5-3
...@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
410 // Code generation phase410 // Code generation phase
411 codegen_pm.run(llvm_module);411 codegen_pm.run(llvm_module);
412412
413 if (options->llvm_ir_out != nullptr) {
414 *options->llvm_ir_out = LLVMPrintModuleToString(module_ref);
415 }
416
413 if (options->llvm_ir_filename) {417 if (options->llvm_ir_filename) {
414 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {418 if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) {
415 return true;419 return true;
...@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi...@@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi
430 auto os = raw_string_ostream(out_str);434 auto os = raw_string_ostream(out_str);
431 TimerGroup::printAll(os);435 TimerGroup::printAll(os);
432 TimerGroup::clearAll();436 TimerGroup::clearAll();
433 auto c_str = (char *)malloc(out_str.length() + 1);437 *options->time_report_out = LLVMCreateMessage(out_str.c_str());
434 strcpy(c_str, out_str.c_str());
435 *options->time_report_out = c_str;
436 }438 }
437 return false;439 return false;
438}440}
src/zig_llvm.h+6-2
...@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {...@@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions {
67 bool is_debug;67 bool is_debug;
68 bool is_small;68 bool is_small;
69 // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this69 // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
70 // `char *` will be populated with a `malloc`-allocated string containing the serialized (as70 // `char *` will be populated with the serialized (as JSON) time report data. The caller is
71 // JSON) time report data. The caller is responsible for freeing that memory.71 // responsible for freeing that memory with `disposeMessage`.
72 char **time_report_out;72 char **time_report_out;
73 bool tsan;73 bool tsan;
74 bool sancov;74 bool sancov;
...@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {...@@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions {
79 const char *bin_filename;79 const char *bin_filename;
80 const char *llvm_ir_filename;80 const char *llvm_ir_filename;
81 const char *bitcode_filename;81 const char *bitcode_filename;
82 // If not null and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this
83 // `char *` will be populated with the optimized LLVM IR. The caller is responsible for freeing
84 // this memory with `disposeMessage`.
85 char **llvm_ir_out;
82 ZigLLVMCoverageOptions coverage;86 ZigLLVMCoverageOptions coverage;
83};87};
8488
stage1/config.zig.in+1-1
...@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;...@@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false;
6pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";6pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@";
7pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;7pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable;
8pub const enable_debug_extensions = false;8pub const enable_debug_extensions = false;
9pub const enable_logging = false;9pub const log_level: @import("std").log.Level = .err;
10pub const enable_link_snapshots = false;10pub const enable_link_snapshots = false;
11pub const enable_tracy = false;11pub const enable_tracy = false;
12pub const value_tracing = false;12pub const value_tracing = false;
test/Runner.zig created+2605
...@@ -0,0 +1,2605 @@
1const assert = std.debug.assert;
2const builtin = @import("builtin");
3const std = @import("std");
4const Runner = @This();
5
6/// These are passed as `<target>-<cache_mode>-<backend>-<linker>-<pic>` strings.
7///
8/// If only one specific test is failing on a target, instead of entirely disabling the target here, you
9/// can skip the target for that specific test only by adding a line like this to top of the manifest:
10///
11/// #skip x86_64-linux-none-baseline-whole-selfhosted-new-pic
12pub const Target = struct {
13 cpu: Cpu = .{ .native = .{} },
14 os: Os = .native,
15 abi: Abi = .default,
16 ofmt: ObjectFormat = .default,
17 dynamic_linker: DynamicLinker = .default,
18
19 cache_mode: enum { whole, incremental },
20 backend: enum { selfhosted, llvm, cbe },
21 linker: enum { lld, old, new },
22 pic: enum { nopic, pic, pie },
23
24 pub const Cpu = Cpu: {
25 @setEvalBranchQuota(3_000);
26 const Arch = std.Target.Cpu.Arch;
27 const arch_info = @typeInfo(Arch).@"enum";
28 const field_names = .{"native"} ++ arch_info.field_names;
29 var field_types: [field_names.len]type = undefined;
30 field_types[0] = struct {
31 model: Model = .native,
32
33 pub const Model = enum { native, baseline };
34 };
35 for (field_types[1..], field_names[1..]) |*field_type, field_name| {
36 const arch = @field(Arch, field_name);
37 const models = arch.allCpuModels();
38 const family = @field(std.Target, @tagName(arch.family()));
39 field_type.* = struct {
40 model: Model = .baseline,
41 features: struct {
42 add: []const Feature = &.{},
43 remove: []const Feature = &.{},
44 comptime {
45 _ = &family; // hack around compiler bug
46 }
47 } = .{},
48
49 pub const Model = Model: {
50 const explicit_models = @typeInfo(family.cpu).@"struct".decl_names;
51 var model_names: []const []const u8 = &.{"native"};
52 if (!@hasDecl(family.cpu, "baseline")) model_names = model_names ++ .{"baseline"};
53 model_names = model_names ++ explicit_models;
54 const TagInt = std.math.IntFittingRange(0, model_names.len - 1);
55 var model_values: [model_names.len]TagInt = undefined;
56 var model_index = 0;
57 {
58 var model_value = explicit_models.len;
59 model_values[model_index] = model_value;
60 model_index += 1;
61 model_value += 1;
62 if (!@hasDecl(family.cpu, "baseline")) {
63 model_values[model_index] = model_value;
64 model_index += 1;
65 model_value += 1;
66 }
67 }
68 for (model_values[model_index..], 0..) |*model_value, value| model_value.* = value;
69 break :Model @Enum(TagInt, .exhaustive, model_names, &model_values);
70 };
71
72 pub const Feature = family.Feature;
73
74 pub fn updateQuery(cpu: *const @This(), query: *std.Target.Query) void {
75 query.cpu_model = switch (cpu.model) {
76 .native => .native,
77 .baseline => .baseline,
78 else => |model| .{ .explicit = models[@backingInt(model)] },
79 };
80 for (cpu.features.add) |add_feature|
81 query.cpu_features_add.addFeature(@backingInt(add_feature));
82 for (cpu.features.remove) |remove_feature|
83 query.cpu_features_sub.addFeature(@backingInt(remove_feature));
84 }
85 };
86 }
87 const TagInt = std.math.IntFittingRange(0, field_names.len - 1);
88 var field_values: [field_names.len]TagInt = undefined;
89 field_values[0] = field_names.len - 1;
90 for (field_values[1..], arch_info.field_values) |*field_value, value| field_value.* = value;
91 const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values);
92 break :Cpu @Union(.auto, Tag, field_names, &field_types, &@splat(.{}));
93 };
94
95 pub const Os = Os: {
96 const os_info = @typeInfo(std.Target.Os.Tag).@"enum";
97 const field_names = .{"native"} ++ os_info.field_names;
98 var field_types: [field_names.len]type = undefined;
99 field_types[0] = void;
100 for (field_types[1..], field_names[1..]) |*field_type, field_name| {
101 const version: enum {
102 none,
103 semver,
104 windows,
105 } = switch (@field(std.Target.Os.Tag, field_name).versionRangeTag()) {
106 .none => .none,
107 .semver, .hurd, .linux => .semver,
108 .windows => .windows,
109 };
110 field_type.* = struct {
111 version: ?Version = null,
112
113 pub const Version = switch (version) {
114 .none => struct {},
115 .semver => struct {
116 min: std.SemanticVersion,
117 max: ?std.SemanticVersion = null,
118 },
119 .windows => struct {
120 min: std.Target.Os.WindowsVersion,
121 max: ?std.Target.Os.WindowsVersion = null,
122 },
123 };
124
125 pub fn updateQuery(os: *const @This(), query: *std.Target.Query) void {
126 if (os.version) |v| switch (version) {
127 .none => {},
128 .semver => {
129 query.os_version_min = .{ .semver = v.min };
130 if (v.max) |max| query.os_version_max = .{ .semver = max };
131 },
132 .windows => {
133 query.os_version_min = .{ .windows = v.min };
134 if (v.max) |max| query.os_version_max = .{ .windows = max };
135 },
136 };
137 }
138 };
139 }
140 const TagInt = std.math.IntFittingRange(0, field_names.len - 1);
141 var field_values: [field_names.len]TagInt = undefined;
142 field_values[0] = field_names.len - 1;
143 for (field_values[1..], os_info.field_values) |*field_value, value| field_value.* = value;
144 const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values);
145 break :Os @Union(.auto, Tag, field_names, &field_types, &@splat(.{}));
146 };
147
148 pub const Abi = Abi: {
149 const abi_info = @typeInfo(std.Target.Abi).@"enum";
150 const field_names = .{"default"} ++ abi_info.field_names;
151 var field_types: [field_names.len]type = undefined;
152 field_types[0] = void;
153 for (field_types[1..], field_names[1..]) |*field_type, field_name| {
154 const abi_tag = @field(std.Target.Abi, field_name);
155 const version: enum { none, libc, android } = if (abi_tag.isAndroid())
156 .android
157 else if (abi_tag.isGnu() or abi_tag.isMusl())
158 .libc
159 else
160 .none;
161 field_type.* = struct {
162 version: ?Version = null,
163
164 pub const Version = switch (version) {
165 .none => struct {},
166 .libc => std.SemanticVersion,
167 .android => u32,
168 };
169
170 pub fn updateQuery(abi: *const @This(), query: *std.Target.Query) void {
171 if (abi.version) |v| switch (version) {
172 .none => {},
173 .libc => query.glibc_version = v,
174 .android => query.android_api_level = v,
175 };
176 }
177 };
178 }
179 const TagInt = std.math.IntFittingRange(0, field_names.len - 1);
180 var field_values: [field_names.len]TagInt = undefined;
181 field_values[0] = field_names.len - 1;
182 for (field_values[1..], abi_info.field_values) |*field_value, value| field_value.* = value;
183 const Tag = @Enum(TagInt, .exhaustive, field_names, &field_values);
184 break :Abi @Union(.auto, Tag, field_names, &field_types, &@splat(.{}));
185 };
186
187 pub const ObjectFormat = ObjectFormat: {
188 const ofmt_info = @typeInfo(std.Target.ObjectFormat).@"enum";
189 const field_names = .{"default"} ++ ofmt_info.field_names;
190 const TagInt = std.math.IntFittingRange(0, field_names.len - 1);
191 var field_values: [field_names.len]TagInt = undefined;
192 field_values[0] = field_names.len - 1;
193 for (field_values[1..], ofmt_info.field_values) |*field_value, value| field_value.* = value;
194 break :ObjectFormat @Enum(TagInt, .exhaustive, field_names, &field_values);
195 };
196
197 pub const DynamicLinker = union(enum) {
198 default,
199 none,
200 explicit: []const u8,
201 };
202
203 pub fn toQuery(target: *const Target) std.Target.Query {
204 var query: std.Target.Query = .{};
205 query.cpu_arch = switch (target.cpu) {
206 .native => null,
207 else => |_, arch| @fromBackingInt(@backingInt(arch)),
208 };
209 switch (target.cpu) {
210 .native => |native| query.cpu_model = switch (native.model) {
211 .native => .native,
212 .baseline => .baseline,
213 },
214 inline else => |cpu| cpu.updateQuery(&query),
215 }
216 query.os_tag = switch (target.os) {
217 .native => null,
218 else => |_, os| @fromBackingInt(@backingInt(os)),
219 };
220 switch (target.os) {
221 .native => {},
222 inline else => |os| os.updateQuery(&query),
223 }
224 query.abi = switch (target.abi) {
225 .default => null,
226 else => |_, abi| @fromBackingInt(@backingInt(abi)),
227 };
228 switch (target.abi) {
229 .default => {},
230 inline else => |abi| abi.updateQuery(&query),
231 }
232 query.ofmt = switch (target.ofmt) {
233 .default => null,
234 else => |ofmt| @fromBackingInt(@backingInt(ofmt)),
235 };
236 query.dynamic_linker = switch (target.dynamic_linker) {
237 .default => null,
238 .none => .none,
239 .explicit => |dynamic_linker| .init(dynamic_linker),
240 };
241 return query;
242 }
243
244 pub fn format(target: *const Target, w: *std.Io.Writer) std.Io.Writer.Error!void {
245 try w.print("{f}-{f}-{t}-{t}-{t}-{t}", .{
246 std.fmt.alt(&target.toQuery(), .printZigTriple),
247 std.fmt.alt(&target.toQuery(), .printCpu),
248 target.cache_mode,
249 target.backend,
250 target.linker,
251 target.pic,
252 });
253 }
254};
255
256gpa: std.mem.Allocator,
257arena: *std.heap.ArenaAllocator,
258environ_map: std.process.Environ.Map,
259io: std.Io,
260prog_node: std.Progress.Node,
261args: Args,
262host: std.Target,
263server: std.zig.Server,
264eb_wip: std.zig.ErrorBundle.Wip,
265
266const Args = struct {
267 @"test": ?struct {
268 input_dir: std.zig.Server.Message.InputDir,
269 dir: std.Io.Dir,
270 },
271 manifest_file: ?std.Io.File,
272 zig_exe: ?std.Io.File,
273 lib_dir: ?std.Io.Dir,
274 src_dir: ?std.Io.Dir,
275 targets: std.ArrayList(u32),
276 target_bytes: std.ArrayList(u8),
277
278 libc_runtimes_dir: ?std.Io.Dir,
279 enable_darling: bool,
280 enable_qemu: bool,
281 enable_rosetta: bool,
282 enable_wasmtime: bool,
283 enable_wine: bool,
284
285 gdb_exe: ?std.Io.File,
286 lldb_exe: ?std.Io.File,
287
288 quiet: bool,
289
290 fn deinit(args: *Args, gpa: std.mem.Allocator) void {
291 args.targets.deinit(gpa);
292 args.target_bytes.deinit(gpa);
293 args.* = undefined;
294 }
295
296 fn addTarget(args: *Args, gpa: std.mem.Allocator, target: []const u8) std.mem.Allocator.Error!void {
297 try args.target_bytes.ensureUnusedCapacity(gpa, target.len + 1);
298 try args.targets.append(gpa, @intCast(args.target_bytes.items.len));
299 args.target_bytes.appendSliceAssumeCapacity(target);
300 args.target_bytes.appendAssumeCapacity(0);
301 }
302};
303
304fn deinit(runner: *Runner) void {
305 runner.environ_map.deinit();
306 runner.prog_node.end();
307 runner.args.deinit(runner.gpa);
308 runner.eb_wip.deinit();
309 runner.* = undefined;
310}
311
312const FailError = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable;
313fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError {
314 return runner.failString(try runner.eb_wip.printString(fmt, args));
315}
316fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError {
317 try runner.eb_wip.addRootErrorMessage(.{ .msg = msg });
318 return error.AlreadyReported;
319}
320
321pub const ProtocolError = error{
322 ServerReadFailed,
323 ServerWriteFailed,
324 ServerEndOfStream,
325} || FailError;
326pub fn runServer(runner: *Runner) ProtocolError {
327 runner.server.serveStringMessage(.zig_version, builtin.zig_version_string) catch |err| switch (err) {
328 error.WriteFailed => return error.ServerWriteFailed,
329 };
330 while (true) {
331 _ = runner.arena.reset(.retain_capacity);
332 const arena = runner.arena.allocator();
333 const hdr = runner.server.receiveMessage() catch |err| switch (err) {
334 error.ReadFailed => return error.ServerReadFailed,
335 error.EndOfStream => return error.ServerEndOfStream,
336 };
337 switch (hdr.tag) {
338 else => |tag| return runner.fail("unsupported message: {t}", .{tag}),
339 .exit => std.process.exit(0),
340 .args => {
341 const args_body = try arena.alloc(u8, hdr.bytes_len);
342 runner.server.in.readSliceAll(args_body) catch unreachable;
343 const State = enum {
344 positional,
345 @"--zig",
346 @"--lib",
347 @"--src",
348 @"--target",
349 @"--libc-runtimes",
350 @"--gdb",
351 @"--lldb",
352 };
353 var state: State = .positional;
354 const state_expected: std.enums.EnumArray(
355 State,
356 enum { path, dir, file, string },
357 ) = .init(.{
358 .positional = .path,
359 .@"--zig" = .file,
360 .@"--lib" = .dir,
361 .@"--src" = .dir,
362 .@"--target" = .string,
363 .@"--libc-runtimes" = .dir,
364 .@"--gdb" = .file,
365 .@"--lldb" = .file,
366 });
367 var input_dir: std.zig.Server.Message.InputDir = .cwd;
368 var args_body_offset: usize = 0;
369 while (args_body.len - args_body_offset > 0) {
370 const arg: std.zig.Client.Message.Arg =
371 @fromBackingInt(args_body[args_body_offset]);
372 args_body_offset += 1;
373 arg: switch (arg) {
374 .string => {
375 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
376 const string = args_body[args_body_offset..end];
377 args_body_offset = end + 1;
378 switch (state) {
379 .positional => if (std.mem.eql(u8, string, "--target")) {
380 state = .@"--target";
381 continue;
382 } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| {
383 try runner.args.addTarget(runner.gpa, target);
384 } else if (std.mem.eql(u8, string, "--libc-runtimes")) {
385 state = .@"--libc-runtimes";
386 continue;
387 } else if (std.mem.eql(u8, string, "-fdarling")) {
388 runner.args.enable_darling = true;
389 } else if (std.mem.eql(u8, string, "-fqemu")) {
390 runner.args.enable_qemu = true;
391 } else if (std.mem.eql(u8, string, "-frosetta")) {
392 runner.args.enable_rosetta = true;
393 } else if (std.mem.eql(u8, string, "-fwasmtime")) {
394 runner.args.enable_wasmtime = true;
395 } else if (std.mem.eql(u8, string, "-fwine")) {
396 runner.args.enable_wine = true;
397 } else if (std.mem.eql(u8, string, "--gdb")) {
398 state = .@"--gdb";
399 continue;
400 } else if (std.mem.eql(u8, string, "--lldb")) {
401 state = .@"--lldb";
402 continue;
403 } else if (std.mem.eql(u8, string, "--quiet")) {
404 runner.args.quiet = true;
405 },
406 .@"--target" => try runner.args.addTarget(runner.gpa, string),
407 else => return runner.fail(
408 "\"{t}\" expected {t}, got {t}",
409 .{ state, state_expected.get(state), arg },
410 ),
411 }
412 },
413 .prefix => {
414 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
415 const string = args_body[args_body_offset..end];
416 args_body_offset = end + 1;
417 assert(state == .positional);
418 state = if (std.mem.eql(u8, string, "--zig="))
419 .@"--zig"
420 else if (std.mem.eql(u8, string, "--lib="))
421 .@"--lib"
422 else if (std.mem.eql(u8, string, "--src="))
423 .@"--src"
424 else if (std.mem.eql(u8, string, "--libc-runtimes="))
425 .@"--libc-runtimes"
426 else if (std.mem.eql(u8, string, "--gdb="))
427 .@"--gdb"
428 else if (std.mem.eql(u8, string, "--lldb="))
429 .@"--lldb"
430 else
431 return runner.fail("unsupported arg prefix: {q}", .{string});
432 continue;
433 },
434 .suffix => {
435 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
436 const string = args_body[args_body_offset..end];
437 args_body_offset = end + 1;
438 return runner.fail("unsupported arg suffix: {q}", .{string});
439 },
440 .input_dir => {
441 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);
442 continue :arg .output_dir;
443 },
444 .output_dir => {
445 const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast(
446 args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)],
447 );
448 args_body_offset += @sizeOf(std.Io.Dir.Handle);
449 const dir = runner.io.vtable.inheritParentDir(
450 runner.io.userdata,
451 dir_handle.*,
452 ) catch |err| switch (err) {
453 error.Canceled => |e| return e,
454 else => |e| return runner.fail(
455 "unable to inherit parent dir: {t}",
456 .{e},
457 ),
458 };
459 switch (state) {
460 .positional => {
461 if (runner.args.@"test" != null or
462 runner.args.manifest_file != null) return runner.fail(
463 "{t} specified multiple times",
464 .{state},
465 );
466 runner.args.@"test" = .{ .input_dir = input_dir, .dir = dir };
467 const manifest_path = "manifest";
468 runner.args.manifest_file = dir.openFile(
469 runner.io,
470 manifest_path,
471 .{},
472 ) catch |err| switch (err) {
473 error.Canceled => |e| return e,
474 else => |e| return runner.fail(
475 "unable to open manifest file: {t}",
476 .{e},
477 ),
478 };
479 try runner.discoverInput(input_dir, manifest_path);
480 },
481 .@"--lib" => {
482 if (runner.args.lib_dir != null) return runner.fail(
483 "\"{t}\" specified multiple times",
484 .{state},
485 );
486 runner.args.lib_dir = dir;
487 },
488 .@"--src" => {
489 if (runner.args.src_dir != null) return runner.fail(
490 "\"{t}\" specified multiple times",
491 .{state},
492 );
493 runner.args.src_dir = dir;
494 },
495 .@"--libc-runtimes" => {
496 if (runner.args.libc_runtimes_dir != null) return runner.fail(
497 "\"{t}\" specified multiple times",
498 .{state},
499 );
500 runner.args.libc_runtimes_dir = dir;
501 },
502 else => return runner.fail(
503 "\"{t}\" expected {t}, got {t}",
504 .{ state, state_expected.get(state), arg },
505 ),
506 }
507 },
508 .input_file, .input_file_content, .output_file => {
509 const file_handle: *align(1) const std.Io.File.Handle = @ptrCast(
510 args_body[args_body_offset..][0..@sizeOf(std.Io.File.Handle)],
511 );
512 args_body_offset += @sizeOf(std.Io.File.Handle);
513 const file = runner.io.vtable.inheritParentFile(
514 runner.io.userdata,
515 file_handle.*,
516 .{ .nonblocking = false },
517 ) catch |err| switch (err) {
518 error.Canceled => |e| return e,
519 else => |e| return runner.fail(
520 "unable to inherit parent file: {t}",
521 .{e},
522 ),
523 };
524 switch (state) {
525 .positional => {
526 if (runner.args.@"test" != null or
527 runner.args.manifest_file != null) return runner.fail(
528 "{t} specified multiple times",
529 .{state},
530 );
531 runner.args.manifest_file = file;
532 },
533 .@"--zig" => {
534 if (runner.args.zig_exe != null) return runner.fail(
535 "\"{t}\" specified multiple times",
536 .{state},
537 );
538 runner.args.zig_exe = file;
539 },
540 .@"--gdb" => {
541 if (runner.args.gdb_exe != null) return runner.fail(
542 "\"{t}\" specified multiple times",
543 .{state},
544 );
545 runner.args.gdb_exe = file;
546 },
547 .@"--lldb" => {
548 if (runner.args.lldb_exe != null) return runner.fail(
549 "\"{t}\" specified multiple times",
550 .{state},
551 );
552 runner.args.lldb_exe = file;
553 },
554 else => return runner.fail(
555 "\"{t}\" expected {t}, got {t}",
556 .{ state, state_expected.get(state), arg },
557 ),
558 }
559 },
560 }
561 state = .positional;
562 }
563 },
564 .query_test_metadata => {
565 const expected_panic_msgs = try arena.alloc(u32, runner.args.targets.items.len);
566 @memset(expected_panic_msgs, 0);
567 runner.server.serveTestMetadata(.{
568 .names = runner.args.targets.items,
569 .expected_panic_msgs = expected_panic_msgs,
570 .string_bytes = runner.args.target_bytes.items,
571 }) catch |err| switch (err) {
572 error.WriteFailed => return error.ServerWriteFailed,
573 };
574 },
575 .run_test => {
576 const test_index = runner.server.receiveBody_u32() catch unreachable;
577 runner.server.serveBodylessMessage(.test_started) catch |err| switch (err) {
578 error.WriteFailed => return error.ServerWriteFailed,
579 };
580 runner.server.serveTestResults(.{
581 .index = test_index,
582 .flags = .{
583 .status = if (runner.testOne(test_index))
584 .pass
585 else |err| status: switch (err) {
586 error.Canceled,
587 error.OutOfMemory,
588 error.ServerWriteFailed,
589 => |e| return e,
590 error.AlreadyReported => {
591 var eb = try runner.eb_wip.toOwnedBundle("");
592 defer eb.deinit(runner.gpa);
593 assert(eb.errorMessageCount() > 0); // already reported what?
594 runner.server.serveErrorBundle(
595 .error_bundle,
596 eb,
597 ) catch |server_err| switch (server_err) {
598 error.WriteFailed => return error.ServerWriteFailed,
599 };
600 const eb_wip: std.zig.ErrorBundle.Wip = try .init(runner.gpa);
601 runner.eb_wip.deinit();
602 runner.eb_wip = eb_wip;
603 break :status .fail;
604 },
605 error.SkipTest => .skip,
606 },
607 .fuzz = false,
608 .log_err_count = 0,
609 .leak_count = 0,
610 },
611 }) catch |err| switch (err) {
612 error.WriteFailed => return error.ServerWriteFailed,
613 };
614 assert(runner.eb_wip.root_list.items.len == 0); // failed to report
615 },
616 }
617 }
618}
619
620fn discoverInput(
621 runner: *Runner,
622 dir: std.zig.Server.Message.InputDir,
623 sub_path: []const u8,
624) error{ServerWriteFailed}!void {
625 return runner.discoverInputInner(dir, sub_path) catch |err| switch (err) {
626 error.WriteFailed => return error.ServerWriteFailed,
627 };
628}
629fn discoverInputInner(
630 runner: *Runner,
631 dir: std.zig.Server.Message.InputDir,
632 sub_path: []const u8,
633) std.Io.Writer.Error!void {
634 try runner.server.serveMessageHeader(.{
635 .tag = .discovered_inputs,
636 .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) +
637 sub_path.len + 1),
638 });
639 try runner.server.out.writeInt(u32, @backingInt(dir), .little);
640 try runner.server.out.writeAll(sub_path);
641 try runner.server.out.writeByte(0);
642 try runner.server.out.flush();
643}
644
645pub const SourceReader = struct {
646 const Io = std.Io;
647
648 backing: *std.Io.Reader,
649 line_aw: std.Io.Writer.Allocating,
650 interface: std.Io.Reader,
651 line: u32,
652 eb_wip: *std.zig.ErrorBundle.Wip,
653 src_path: std.zig.ErrorBundle.String,
654
655 pub fn init(
656 reader: *Io.Reader,
657 gpa: std.mem.Allocator,
658 eb_wip: *std.zig.ErrorBundle.Wip,
659 src_path: std.zig.ErrorBundle.String,
660 ) SourceReader {
661 return .{
662 .backing = reader,
663 .line_aw = .init(gpa),
664 .interface = .{
665 .vtable = &.{
666 .stream = stream,
667 .discard = discard,
668 .readVec = readVec,
669 .rebase = rebase,
670 },
671 .buffer = &.{},
672 .seek = 0,
673 .end = 0,
674 },
675 .line = 0,
676 .eb_wip = eb_wip,
677 .src_path = src_path,
678 };
679 }
680 fn deinit(s: *SourceReader) void {
681 s.line_aw.deinit();
682 }
683 fn stream(r: *Io.Reader, _: *Io.Writer, _: Io.Limit) Io.Reader.StreamError!usize {
684 const s: *SourceReader = @fieldParentPtr("interface", r);
685 try s.bufferLine();
686 return 0;
687 }
688 fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
689 const s: *SourceReader = @fieldParentPtr("interface", r);
690 const remaining = r.buffered();
691 if (remaining.len > 0) {
692 const n = limit.minInt(remaining.len);
693 r.toss(n);
694 return n;
695 }
696 try s.bufferLine();
697 return 0;
698 }
699 fn readVec(r: *Io.Reader, _: [][]u8) Io.Reader.Error!usize {
700 const s: *SourceReader = @fieldParentPtr("interface", r);
701 try s.bufferLine();
702 return 0;
703 }
704 fn rebase(r: *Io.Reader, capacity: usize) Io.Reader.RebaseError!void {
705 const s: *SourceReader = @fieldParentPtr("interface", r);
706 defer s.updateBuffer();
707 s.line_aw.ensureUnusedCapacity(capacity) catch |err| switch (err) {
708 error.OutOfMemory => return error.ReadFailed,
709 };
710 }
711 fn updateBuffer(s: *SourceReader) void {
712 s.interface.buffer = s.line_aw.writer.buffer;
713 s.interface.end = s.line_aw.writer.end;
714 }
715 fn bufferLine(s: *SourceReader) Io.Reader.Error!void {
716 defer s.updateBuffer();
717 {
718 const written = s.line_aw.written();
719 const start = if (std.mem.findScalarLast(u8, written[0..s.interface.seek], '\n')) |newline|
720 newline + 1
721 else
722 0;
723 s.line += @intCast(std.mem.countScalar(u8, written[0..start], '\n'));
724 const preserve = written[start..];
725 @memmove(written[0..preserve.len], preserve);
726 s.line_aw.shrinkRetainingCapacity(preserve.len);
727 s.interface.seek -= start;
728 }
729 const n = s.backing.streamDelimiterEnding(&s.line_aw.writer, '\n') catch |err| switch (err) {
730 error.ReadFailed => |e| return e,
731 error.WriteFailed => return error.ReadFailed,
732 };
733 if (std.mem.endsWith(u8, s.line_aw.written(), "\r")) s.line_aw.writer.end -= 1;
734 const buffered = s.backing.buffered();
735 if (n == 0 and buffered.len == 0) return error.EndOfStream;
736 if (std.mem.startsWith(u8, buffered, "\n")) {
737 s.line_aw.writer.writeByte('\n') catch |err| switch (err) {
738 error.WriteFailed => return error.ReadFailed,
739 };
740 s.backing.toss(1);
741 }
742 }
743 fn fail(
744 s: *SourceReader,
745 src_loc: []const u8,
746 comptime fmt: []const u8,
747 args: anytype,
748 ) FailError {
749 return s.failString(src_loc, try s.eb_wip.printString(fmt, args));
750 }
751 fn failString(
752 s: *SourceReader,
753 src_loc: []const u8,
754 msg: std.zig.ErrorBundle.String,
755 ) FailError {
756 try s.eb_wip.addRootErrorMessage(.{ .msg = msg, .src_loc = try s.srcLoc(src_loc) });
757 return error.AlreadyReported;
758 }
759 fn srcLoc(
760 s: *SourceReader,
761 src_loc: []const u8,
762 ) std.mem.Allocator.Error!std.zig.ErrorBundle.SourceLocationIndex {
763 const line: u32, const column: u32, const source_line = src_loc: {
764 const buffer = s.interface.buffer[0..s.interface.end];
765 const pos = src_loc.ptr - buffer.ptr;
766 const end = std.mem.findScalarPos(u8, buffer, pos, '\n') orelse buffer.len;
767 const start =
768 if (std.mem.findScalarLast(u8, buffer[0..end], '\n')) |newline| newline + 1 else 0;
769 break :src_loc .{
770 @intCast(s.line + std.mem.countScalar(u8, buffer[0..start], '\n')),
771 @intCast(pos - start),
772 buffer[start..end],
773 };
774 };
775 return s.eb_wip.addSourceLocation(.{
776 .src_path = s.src_path,
777 .line = line,
778 .column = column,
779 .span_start = column,
780 .span_main = column,
781 .span_end = @intCast(column + src_loc.len),
782 .source_line = try s.eb_wip.addString(source_line),
783 });
784 }
785};
786pub const DelimitedReader = struct {
787 const Io = std.Io;
788
789 unlimited: *Io.Reader,
790 remaining: Io.Limit,
791 delimiter: []const u8,
792 interface: Io.Reader,
793
794 pub fn init(reader: *Io.Reader, delimiter: []const u8, buffer: []u8) DelimitedReader {
795 return .{
796 .unlimited = reader,
797 .remaining = .nothing,
798 .delimiter = delimiter,
799 .interface = .{
800 .vtable = &.{
801 .stream = stream,
802 .discard = discard,
803 },
804 .buffer = buffer,
805 .seek = 0,
806 .end = 0,
807 },
808 };
809 }
810 fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
811 const d: *DelimitedReader = @fieldParentPtr("interface", r);
812 const block = try d.unlimited.peekGreedy(d.delimiter.len);
813 d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse
814 block.len - d.delimiter.len + 1);
815 if (d.remaining == .nothing) return error.EndOfStream;
816 const n = try d.unlimited.stream(w, limit.min(d.remaining));
817 d.remaining = d.remaining.subtract(n).?;
818 return n;
819 }
820 fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
821 const d: *DelimitedReader = @fieldParentPtr("interface", r);
822 const block = try d.unlimited.peekGreedy(d.delimiter.len);
823 d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse
824 block.len - d.delimiter.len + 1);
825 if (d.remaining == .nothing) return error.EndOfStream;
826 const n = try d.unlimited.discard(limit.min(d.remaining));
827 d.remaining = d.remaining.subtract(n).?;
828 return n;
829 }
830};
831
832const Update = struct {
833 target_query: []const u8,
834 manifest_sr: SourceReader,
835 compiler: ?Compiler,
836 src_dir: std.Io.Dir,
837 eb_wip: *std.zig.ErrorBundle.Wip,
838 cmd_src_loc: std.zig.ErrorBundle.SourceLocationIndex,
839 src_loc: ?std.zig.ErrorBundle.SourceLocationIndex,
840 num: usize,
841 name: []const u8,
842 prog_node: std.Progress.Node,
843 mtime: std.Io.Timestamp,
844 allow_skip: bool,
845
846 fn checkMatches(
847 update: *const Update,
848 what: []const u8,
849 expected: []const u8,
850 actual: []const u8,
851 ) FailError!void {
852 var expected_match_it = std.mem.splitSequence(u8, expected, "#...");
853 var pos: usize = 0;
854 while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) {
855 var context_len: usize = expected_match.len;
856 pos = while (true) : (context_len -= 1) break std.mem.findPos(
857 u8,
858 actual,
859 pos,
860 expected_match[0..context_len],
861 ) orelse continue;
862 const actual_match = actual[pos..];
863 std.testing.expectEqualStrings(
864 expected_match,
865 actual_match[0..@min(actual_match.len, expected_match.len)],
866 ) catch |err| switch (err) {
867 error.TestExpectedEqual => {
868 std.testing.failPrint("\n=============== full output: =========\n", .{});
869 std.testing.failPrintWithVisibleNewlines(actual_match);
870 std.testing.failPrint("\n======================================\n", .{});
871 return update.fail("{s} did not match expected", .{what});
872 },
873 };
874 }
875 }
876
877 fn fail(update: *const Update, comptime fmt: []const u8, args: anytype) FailError {
878 return update.failString(try update.eb_wip.printString(fmt, args));
879 }
880 fn failString(update: *const Update, msg: std.zig.ErrorBundle.String) FailError {
881 var notes_buffer: [1]std.zig.ErrorBundle.ErrorMessage = undefined;
882 var notes_len: u32 = 0;
883 if (update.src_loc) |src_loc| {
884 notes_buffer[notes_len] = .{
885 .msg = try update.eb_wip.addString("after this update"),
886 .src_loc = src_loc,
887 };
888 notes_len += 1;
889 }
890 try update.eb_wip.addRootErrorMessageWithNotes(.{
891 .msg = msg,
892 .src_loc = update.cmd_src_loc,
893 .notes_len = 1,
894 }, notes_buffer[0..notes_len]);
895 return error.AlreadyReported;
896 }
897};
898
899const TestError = error{
900 SkipTest,
901} || FailError;
902fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestError)!void {
903 const target_query =
904 std.mem.sliceTo(runner.args.target_bytes.items[runner.args.targets.items[test_index]..], 0);
905 const manifest_file = runner.args.manifest_file orelse
906 return runner.fail("missing \"path/to/test\" arg", .{});
907 var manifest_buffer: [512]u8 = undefined;
908 var manifest_fr = manifest_file.reader(runner.io, &manifest_buffer);
909 var update: Update = .{
910 .target_query = target_query,
911 .manifest_sr = .init(&manifest_fr.interface, runner.gpa, &runner.eb_wip, src_path_string: {
912 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
913 const src_path = src_path: {
914 break :src_path path_buffer[0 .. manifest_file.realPath(
915 runner.io,
916 &path_buffer,
917 ) catch |err| switch (err) {
918 error.Canceled => |e| return e,
919 else => break :src_path "manifest",
920 }];
921 };
922 break :src_path_string try runner.eb_wip.addString(src_path);
923 }),
924 .compiler = null,
925 .src_dir = (runner.args.src_dir orelse
926 return runner.fail("missing \"--src=path/to/src\" arg", .{})).createDirPathOpen(
927 runner.io,
928 target_query,
929 .{},
930 ) catch |err| switch (err) {
931 error.Canceled => |e| return e,
932 else => |e| return runner.fail("unable to create {q}: {t}", .{ target_query, e }),
933 },
934 .eb_wip = &runner.eb_wip,
935 .cmd_src_loc = undefined,
936 .src_loc = null,
937 .num = 0,
938 .name = undefined,
939 .prog_node = .none,
940 .mtime = .now(runner.io, .real),
941 .allow_skip = true,
942 };
943 defer {
944 update.manifest_sr.deinit();
945 if (update.compiler) |*comp| comp.deinit();
946 update.src_dir.close(runner.io);
947 update.prog_node.end();
948 }
949
950 // hack around `std.Io.Reader` interface bugs by ensuring the
951 // buffer is larger than the longest supported manifest line
952 try update.manifest_sr.line_aw.ensureTotalCapacityPrecise(512);
953 update.manifest_sr.updateBuffer();
954
955 var skip_delimiter = false;
956 while (update.manifest_sr.interface.takeSentinel('\n')) |line| {
957 var line_it = std.mem.tokenizeScalar(u8, line, ' ');
958 const cmd_src_loc = line_it.next() orelse continue;
959 if (skip_delimiter) {
960 assert(std.mem.eql(u8, cmd_src_loc, "#}"));
961 skip_delimiter = false;
962 const unexpected = line_it.rest();
963 if (unexpected.len > 0)
964 return update.manifest_sr.fail(unexpected, "unexpected argument {q}", .{unexpected});
965 continue;
966 }
967 update.cmd_src_loc = try update.manifest_sr.srcLoc(cmd_src_loc);
968 const cmd = std.meta.stringToEnum(Command, std.mem.cutPrefix(u8, cmd_src_loc, "#") orelse
969 return update.manifest_sr.fail(cmd_src_loc, "expected command", .{})) orelse
970 return update.manifest_sr.fail(cmd_src_loc, "unknown command", .{});
971 const arg = switch (cmd) {
972 .todo, .exe, .lib, .obj, .update => null,
973 .skip, .write, .delete, .check => line_it.next() orelse
974 return update.manifest_sr.fail(line_it.rest()[0..0], "missing argument", .{}),
975 };
976 var contents_file: ?std.Io.File = null;
977 defer if (contents_file) |file| file.close(runner.io);
978 var contents_buffer: [512]u8 = undefined;
979 var contents_impl: union(enum) {
980 r: std.Io.Reader,
981 dr: DelimitedReader,
982 fr: std.Io.File.Reader,
983 } = undefined;
984 const contents_r: *std.Io.Reader = contents_r: switch (cmd) {
985 .skip, .delete => {
986 const unexpected = line_it.rest();
987 if (unexpected.len > 0) return update.manifest_sr.fail(
988 unexpected,
989 "unexpected argument {q}",
990 .{unexpected},
991 );
992 contents_impl = .{ .r = .ending_instance };
993 break :contents_r &contents_impl.r;
994 },
995 else => {
996 const contents = line_it.rest();
997 if (contents.len == 0) {
998 contents_impl = .{ .r = .ending_instance };
999 break :contents_r &contents_impl.r;
1000 }
1001 contents: switch (contents[0]) {
1002 else => return update.manifest_sr.fail(contents, "invalid contents syntax", .{}),
1003 '"' => {
1004 if (contents.len < 2 or contents[contents.len - 1] != '"') continue :contents 0;
1005 var contents_fw: std.Io.Writer = .fixed(&contents_buffer);
1006 switch (std.zig.string_literal.parseWrite(
1007 &contents_fw,
1008 contents,
1009 ) catch |err| switch (err) {
1010 error.WriteFailed => return update.manifest_sr.fail(
1011 contents,
1012 "contents string too long, use inline or file syntax instead",
1013 .{},
1014 ),
1015 }) {
1016 .success => {
1017 contents_impl = .{ .r = .fixed(contents_fw.buffered()) };
1018 break :contents_r &contents_impl.r;
1019 },
1020 .failure => |err| return update.manifest_sr.fail(
1021 contents[err.offset()..][0..0],
1022 "{f}",
1023 .{err.fmt(contents)},
1024 ),
1025 }
1026 },
1027 '{' => {
1028 if (contents.len != 1) continue :contents 0;
1029
1030 contents_impl = .{
1031 .dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer),
1032 };
1033 skip_delimiter = true;
1034 break :contents_r &contents_impl.dr.interface;
1035 },
1036 '@' => {
1037 const args_test = runner.args.@"test" orelse return update.manifest_sr.fail(
1038 contents,
1039 "contents file requires directory test",
1040 .{},
1041 );
1042 const contents_path = contents[1..];
1043 try runner.discoverInput(args_test.input_dir, contents_path);
1044
1045 contents_file = args_test.dir.openFile(
1046 runner.io,
1047 contents_path,
1048 .{},
1049 ) catch |err| switch (err) {
1050 error.Canceled => |e| return e,
1051 else => |e| return update.manifest_sr.fail(
1052 contents_path,
1053 "unable to open contents file: {t}",
1054 .{e},
1055 ),
1056 };
1057 contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) };
1058 break :contents_r &contents_impl.fr.interface;
1059 },
1060 }
1061 },
1062 };
1063
1064 runner.handleCommand(&update, cmd_src_loc, cmd, arg, contents_r) catch |err| switch (err) {
1065 error.Canceled,
1066 error.OutOfMemory,
1067 error.AlreadyReported,
1068 error.SkipTest,
1069 => |e| return e,
1070 error.ContentsReadFailed => switch (contents_impl) {
1071 .r => unreachable,
1072 .dr => switch (manifest_fr.err orelse return error.OutOfMemory) {
1073 error.Canceled => |e| return e,
1074 else => |e| return update.fail("unable to read manifest: {t}", .{e}),
1075 },
1076 .fr => |fr| switch (fr.err.?) {
1077 error.Canceled => |e| return e,
1078 else => |e| return update.fail("unable to read contents file: {t}", .{e}),
1079 },
1080 },
1081 };
1082 } else |err| switch (err) {
1083 error.ReadFailed => switch (manifest_fr.err orelse return error.OutOfMemory) {
1084 error.Canceled => |e| return e,
1085 else => |e| return update.fail("unable to read manifest: {t}", .{e}),
1086 },
1087 error.StreamTooLong => unreachable,
1088 error.EndOfStream => {
1089 const final_line = update.manifest_sr.interface.buffered();
1090 switch (final_line.len) {
1091 0 => if (skip_delimiter) return update.manifest_sr.fail(
1092 final_line[0..0],
1093 "missing \"#}}\" delimiter",
1094 .{},
1095 ),
1096 else => return update.manifest_sr.fail(
1097 final_line[final_line.len..],
1098 "missing trailing newline",
1099 .{},
1100 ),
1101 }
1102 },
1103 }
1104 if (update.compiler) |*comp| {
1105 if (comp.state != .idle) return update.fail("missing \"#check\"", .{});
1106 try comp.exit();
1107 }
1108}
1109const Command = enum { todo, skip, exe, lib, obj, write, delete, update, check };
1110fn handleCommand(
1111 runner: *Runner,
1112 update: *Update,
1113 cmd_src_loc: []const u8,
1114 cmd: Command,
1115 arg: ?[]const u8,
1116 contents_r: *std.Io.Reader,
1117) (error{ContentsReadFailed} || TestError)!void {
1118 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1119 const cmd_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "#{t}{s}{s}", .{
1120 cmd, if (arg) |_| " " else "", arg orelse "",
1121 }) catch &name_buffer, 0);
1122 defer cmd_prog_node.end();
1123
1124 cmd: switch (cmd) {
1125 .todo => _ = contents_r.discardRemaining() catch |err| switch (err) {
1126 error.ReadFailed => {},
1127 },
1128 .skip => if (!update.allow_skip) return update.manifest_sr.fail(
1129 cmd_src_loc,
1130 "\"#skip\" must appear before other commands",
1131 .{},
1132 ) else if (std.mem.eql(u8, update.target_query, arg.?)) return error.SkipTest,
1133 .exe, .lib, .obj => runner.spawnCompiler(&update.compiler, update.src_dir, switch (cmd) {
1134 else => unreachable,
1135 .exe => .Exe,
1136 .lib => .Lib,
1137 .obj => .Obj,
1138 }, contents_r, target: {
1139 var component_it = std.mem.splitBackwardsScalar(u8, update.target_query, '-');
1140 const pic_str = component_it.next() orelse
1141 return update.fail("target {q} missing pic", .{update.target_query});
1142 const pic = std.meta.stringToEnum(Compiler.Target.Pic, pic_str) orelse
1143 return update.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str });
1144 const linker_str = component_it.next() orelse
1145 return update.fail("target {q} missing linker", .{update.target_query});
1146 const linker = std.meta.stringToEnum(Compiler.Target.Linker, linker_str) orelse
1147 return update.fail("target {q} unknown linker {q}", .{
1148 update.target_query, linker_str,
1149 });
1150 const backend_str = component_it.next() orelse
1151 return update.fail("target {q} missing backend", .{update.target_query});
1152 const backend = std.meta.stringToEnum(Compiler.Target.Backend, backend_str) orelse
1153 return update.fail("target {q} unknown backend {q}", .{
1154 update.target_query, backend_str,
1155 });
1156 const cache_mode_str = component_it.next() orelse
1157 return update.fail("target {q} missing cache mode", .{update.target_query});
1158 const cache_mode = std.meta.stringToEnum(Compiler.Target.CacheMode, cache_mode_str) orelse
1159 return update.fail("target {q} unknown cache mode {q}", .{
1160 update.target_query, cache_mode_str,
1161 });
1162 const triple_cpu = component_it.rest();
1163 var triple_len: usize = 0;
1164 for (0..3) |_| {
1165 const component_start = triple_len;
1166 triple_len = if (std.mem.findScalarPos(u8, triple_cpu, triple_len, '-')) |dash_pos|
1167 dash_pos + 1
1168 else
1169 return update.fail("target {q} missing cpu", .{update.target_query});
1170 if (std.mem.eql(u8, triple_cpu[component_start..triple_len], "native-")) break;
1171 }
1172 const triple = triple_cpu[0 .. triple_len - 1];
1173 const cpu = triple_cpu[triple_len..];
1174 var query_parse_diags: std.Target.Query.ParseOptions.Diagnostics = undefined;
1175 break :target .{
1176 .triple = triple,
1177 .resolved = std.zig.system.resolveTargetQuery(
1178 runner.io,
1179 std.Target.Query.parse(.{
1180 .arch_os_abi = triple,
1181 .cpu_features = cpu,
1182 .object_format = switch (backend) {
1183 .sema, .selfhosted, .llvm => null,
1184 .cbe => "c",
1185 },
1186 .diagnostics = &query_parse_diags,
1187 }) catch |err| switch (err) {
1188 error.UnknownArchitecture => return update.fail(
1189 "unable to resolve target {q}: unknown architecture: {q}",
1190 .{ update.target_query, query_parse_diags.unknown_architecture_name.? },
1191 ),
1192 error.MissingOperatingSystem => return update.fail(
1193 "unable to resolve target {q}: missing operating system",
1194 .{update.target_query},
1195 ),
1196 error.UnknownOperatingSystem => return update.fail(
1197 "unable to resolve target {q}: unknown operating system: {q}",
1198 .{ update.target_query, query_parse_diags.os_name.? },
1199 ),
1200 error.InvalidOperatingSystemVersion => return update.fail(
1201 "unable to resolve target {q}: invalid operating system version",
1202 .{update.target_query},
1203 ),
1204 error.UnknownApplicationBinaryInterface => return update.fail(
1205 "unable to resolve target {q}: unknown abi",
1206 .{update.target_query},
1207 ),
1208 error.InvalidAbiVersion => return update.fail(
1209 "unable to resolve target {q}: invalid abi version",
1210 .{update.target_query},
1211 ),
1212 error.UnexpectedExtraField => unreachable, // validated above
1213 error.UnknownCpuModel => return update.fail(
1214 "unable to resolve target {q}: unknown cpu: {q}",
1215 .{ update.target_query, query_parse_diags.cpu_name.? },
1216 ),
1217 error.UnknownCpuFeature => return update.fail(
1218 "unable to resolve target {q}: unknown cpu feature: {q}",
1219 .{ update.target_query, query_parse_diags.unknown_feature_name.? },
1220 ),
1221 error.UnknownObjectFormat => return update.fail(
1222 "unable to resolve target {q}: unknown object format",
1223 .{update.target_query},
1224 ),
1225 },
1226 ) catch |err| switch (err) {
1227 error.Canceled => |e| return e,
1228 else => |e| return update.fail("unable to resolve target {q}: {t}", .{ triple, e }),
1229 },
1230 .cache_mode = cache_mode,
1231 .backend = backend,
1232 .linker = linker,
1233 .pic = pic,
1234 };
1235 }) catch |err| switch (err) {
1236 error.Canceled, error.OutOfMemory, error.AlreadyReported, error.SkipTest => |e| return e,
1237 error.ReadFailed => return error.ContentsReadFailed,
1238 },
1239 .write => {
1240 const file = update.src_dir.createFile(runner.io, arg.?, .{}) catch |err| switch (err) {
1241 error.Canceled => |e| return e,
1242 else => |e| return update.manifest_sr.fail(arg.?, "unable to create file: {t}", .{e}),
1243 };
1244 defer file.close(runner.io);
1245 var fw_buffer: [512]u8 = undefined;
1246 var fw = file.writer(runner.io, &fw_buffer);
1247 _ = contents_r.streamRemaining(&fw.interface) catch |err| switch (err) {
1248 error.ReadFailed => return error.ContentsReadFailed,
1249 error.WriteFailed => switch (fw.err.?) {
1250 error.Canceled => |e| return e,
1251 else => |e| return update.manifest_sr.fail(
1252 arg.?,
1253 "unable to write file: {t}",
1254 .{e},
1255 ),
1256 },
1257 };
1258 fw.flush() catch |err| switch (err) {
1259 error.Canceled => |e| return e,
1260 else => |e| return update.manifest_sr.fail(
1261 arg.?,
1262 "unable to write file: {t}",
1263 .{e},
1264 ),
1265 };
1266 file.setTimestamps(runner.io, .{ .modify_timestamp = .{
1267 .new = update.mtime,
1268 } }) catch |err| switch (err) {
1269 error.Canceled => |e| return e,
1270 else => |e| return update.manifest_sr.fail(
1271 arg.?,
1272 "unable to update file timestamps: {t}",
1273 .{e},
1274 ),
1275 };
1276 },
1277 .delete => update.src_dir.deleteFile(runner.io, arg.?) catch |err| switch (err) {
1278 error.Canceled => |e| return e,
1279 else => |e| return update.manifest_sr.fail(arg.?, "unable to delete file: {t}", .{e}),
1280 },
1281 .update => {
1282 update.src_loc = update.cmd_src_loc;
1283 const comp = &(update.compiler orelse return update.manifest_sr.fail(
1284 cmd_src_loc,
1285 "missing \"#exe\", \"#lib\", or \"#obj\"",
1286 .{},
1287 ));
1288 update.prog_node.end();
1289 const arena = runner.arena.allocator();
1290 update.name = switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) {
1291 error.ReadFailed => return error.ContentsReadFailed,
1292 }) {
1293 0 => switch (update.num) {
1294 0 => "initial update",
1295 else => |num| try arena.print("update {d}", .{num}),
1296 },
1297 else => |name_len| try arena.dupe(u8, name_buffer[0..name_len]),
1298 };
1299 update.prog_node = runner.prog_node.start(update.name, 0);
1300 _ = contents_r.discardRemaining() catch |err| switch (err) {
1301 error.ReadFailed => return error.ContentsReadFailed,
1302 };
1303 if (comp.state != .idle)
1304 return update.manifest_sr.fail(cmd_src_loc, "missing \"#check\"", .{});
1305 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
1306 error.WriteFailed => switch (comp.fw.err.?) {
1307 error.Canceled => |e| return e,
1308 else => |e| return update.fail("unable to send message to compiler: {t}", .{e}),
1309 },
1310 };
1311 comp.state = .update;
1312 update.mtime = update.mtime.addDuration(.fromSeconds(2));
1313 update.num += 1;
1314 },
1315 .check => {
1316 const check = std.meta.stringToEnum(Compiler.Check, arg.?) orelse
1317 return update.manifest_sr.fail(arg.?, "unknown check", .{});
1318 const expected =
1319 contents_r.allocRemaining(runner.gpa, .unlimited) catch |err| switch (err) {
1320 error.OutOfMemory => |e| return e,
1321 error.ReadFailed => return error.ContentsReadFailed,
1322 error.StreamTooLong => unreachable, // .unlimited
1323 };
1324 defer runner.gpa.free(expected);
1325
1326 const comp = &(update.compiler orelse return update.manifest_sr.fail(
1327 cmd_src_loc,
1328 "missing \"#exe\", \"#lib\", or \"#obj\"",
1329 .{},
1330 ));
1331 if (comp.state != .update)
1332 return update.manifest_sr.fail(cmd_src_loc, "missing \"#update\"", .{});
1333 const stderr = comp.mr.reader(1);
1334 while (try comp.receiveMessage()) |message| switch (message.tag) {
1335 else => {}, // Ignore other messages,
1336 .config => {
1337 var body_r: std.Io.Reader = .fixed(message.body);
1338 comp.config = body_r.takeStruct(std.zig.Server.Message.Config, .little) catch
1339 unreachable;
1340 },
1341 .emit_digest => {
1342 var body_r: std.Io.Reader = .fixed(message.body);
1343 _ = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch
1344 unreachable;
1345 const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch
1346 unreachable;
1347 try comp.checkSuccess(update, check, expected, digest);
1348 },
1349 .error_bundle => {
1350 const eb = std.zig.Server.allocErrorBundle(
1351 runner.arena.allocator(),
1352 message.body,
1353 ) catch |err| switch (err) {
1354 error.OutOfMemory => |e| return e,
1355 error.EndOfStream => return update.fail("error bundle truncated", .{}),
1356 };
1357 switch (check) {
1358 .errors => {
1359 var error_aw: std.Io.Writer.Allocating = .init(runner.gpa);
1360 defer error_aw.deinit();
1361 eb.renderToWriter(.{
1362 .include_reference_trace = false,
1363 .include_source_line = false,
1364 .include_log_text = true,
1365 }, &error_aw.writer) catch |err| switch (err) {
1366 error.WriteFailed => return error.OutOfMemory,
1367 };
1368 const actual = error_aw.written();
1369 std.mem.replaceScalar(u8, actual, '\\', '/');
1370 std.testing.expectEqualStrings(expected, actual) catch |err| switch (err) {
1371 error.TestExpectedEqual => return update.fail(
1372 "errors did not match expected",
1373 .{},
1374 ),
1375 };
1376 },
1377 .stdout, .exit, .llvm, .gdb, .lldb => if (eb.errorMessageCount() > 0) {
1378 eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) {
1379 error.Canceled => {},
1380 else => {},
1381 };
1382 return update.fail("unexpected compile errors", .{});
1383 },
1384 }
1385 comp.state = .idle;
1386 break :cmd;
1387 },
1388 };
1389
1390 const stderr_buffered = stderr.buffered();
1391 if (stderr_buffered.len > 0) {
1392 if (comp.allow_compiler_stderr) {
1393 std.log.info("#update {q} stderr:\n{s}", .{ update.name, stderr_buffered });
1394 } else return update.fail("unexpected stderr:\n{s}", .{stderr_buffered});
1395 }
1396
1397 return update.fail("compiler failed to send terminating error_bundle", .{});
1398 },
1399 }
1400 assert(contents_r.discardRemaining() catch |err| switch (err) {
1401 error.ReadFailed => return error.ContentsReadFailed,
1402 } == 0);
1403 switch (cmd) {
1404 .todo, .skip => {},
1405 else => update.allow_skip = false,
1406 }
1407}
1408
1409fn spawnCompiler(
1410 runner: *Runner,
1411 compiler: *?Compiler,
1412 src_dir: std.Io.Dir,
1413 output_mode: std.lang.OutputMode,
1414 args_r: *std.Io.Reader,
1415 target: Compiler.Target,
1416) (std.Io.Reader.ShortError || TestError)!void {
1417 const gpa = runner.gpa;
1418 const arena = runner.arena.allocator();
1419 if (compiler.*) |*comp| {
1420 comp.deinit();
1421 compiler.* = null;
1422 }
1423 errdefer compiler.* = null;
1424
1425 compiler.* = .{
1426 .runner = runner,
1427 .allow_compiler_stderr = true,
1428 .output_mode = output_mode,
1429 .state = .idle,
1430 .child = undefined,
1431 .fw = undefined,
1432 .mr_buffer = undefined,
1433 .mr = undefined,
1434 .client = undefined,
1435 .target = target,
1436 .emit_name = null,
1437 .prog_node = .none,
1438 .config = null,
1439 };
1440 const comp = &compiler.*.?;
1441
1442 var argv: std.ArrayList([]const u8) = .empty;
1443 defer argv.deinit(gpa);
1444 try argv.appendSlice(gpa, &.{
1445 "zig",
1446 switch (output_mode) {
1447 .Obj => "build-obj",
1448 .Exe => "build-exe",
1449 .Lib => "build-lib",
1450 },
1451 "-target",
1452 comp.target.triple,
1453 "--cache-dir",
1454 ".zig-cache",
1455 });
1456 switch (comp.target.cache_mode) {
1457 .whole => {},
1458 .incremental => try argv.append(gpa, "-fincremental"),
1459 }
1460 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
1461 if (comp.target.backend) |b| switch (b) {
1462 .sema => try argv.append(gpa, "-fno-emit-bin"),
1463 .selfhosted => try argv.append(gpa, "-fno-llvm"),
1464 .llvm => try argv.append(gpa, "-fllvm"),
1465 .cbe => try argv.append(gpa, "-ofmt=c"),
1466 } else try argv.appendSlice(gpa, &.{ "-I", path_buffer[0 .. (runner.args.lib_dir orelse
1467 return runner.fail("\"--lib=path/to/lib\" arg required with cbe", .{}))
1468 .realPath(runner.io, &path_buffer) catch |err| switch (err) {
1469 error.Canceled => |e| return e,
1470 else => |e| return runner.fail("unable to get lib path: {t}", .{e}),
1471 }] });
1472 switch (comp.target.linker) {
1473 .lld => try argv.appendSlice(gpa, &.{ "-flld", "-fno-new-linker" }),
1474 .old => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fno-new-linker" }),
1475 .new => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fnew-linker" }),
1476 }
1477 switch (comp.target.pic) {
1478 .nopic => try argv.appendSlice(gpa, &.{ "-fno-PIC", "-fno-PIE" }),
1479 .pic => try argv.appendSlice(gpa, &.{ "-fPIC", "-fno-PIE" }),
1480 .pie => try argv.appendSlice(gpa, &.{ "-fPIC", "-fPIE" }),
1481 }
1482
1483 var need: usize = 1;
1484 var state: enum { positional, @"--name" } = .positional;
1485 var root_name: ?[]const u8 = null;
1486 var emit: ?std.zig.EmitArtifact = .bin;
1487 while (true) {
1488 const done = if (args_r.fill(need)) false else |err| switch (err) {
1489 error.ReadFailed => |e| return e,
1490 error.EndOfStream => true,
1491 };
1492 const buffered = args_r.buffered();
1493 const start = std.mem.findNone(u8, buffered, "\n ") orelse buffered.len;
1494 const end = std.mem.findAnyPos(u8, buffered, start, "\n ") orelse buffered.len;
1495 if (end - start > 0) {
1496 const arg = try arena.dupe(u8, buffered[start..end]);
1497 switch (state) {
1498 .positional => if (std.mem.eql(u8, arg, "--name")) {
1499 state = .@"--name";
1500 } else if (std.mem.cutPrefix(u8, arg, "-ofmt=")) |ofmt| {
1501 comp.target.resolved.ofmt =
1502 std.meta.stringToEnum(std.Target.ObjectFormat, ofmt) orelse
1503 return runner.fail("invalid object format {q}", .{ofmt});
1504 } else if (std.mem.cutPrefix(u8, arg, "-M")) |module| {
1505 var module_name_it = std.mem.splitScalar(u8, module, '=');
1506 const module_name = module_name_it.next().?;
1507 root_name = root_name orelse module_name;
1508 } else if (std.mem.eql(u8, arg, "-femit-asm")) {
1509 emit = .@"asm";
1510 } else if (std.mem.eql(u8, arg, "-femit-bin")) {
1511 emit = .bin;
1512 } else if (std.mem.eql(u8, arg, "-femit-docs")) {
1513 emit = .docs;
1514 } else if (std.mem.eql(u8, arg, "-femit-h")) {
1515 emit = .h;
1516 } else if (std.mem.eql(u8, arg, "-femit-implib")) {
1517 emit = .implib;
1518 } else if (std.mem.eql(u8, arg, "-femit-llvm-bc")) {
1519 emit = .llvm_bc;
1520 } else if (std.mem.eql(u8, arg, "-femit-llvm-ir")) {
1521 emit = .llvm_ir;
1522 } else if (std.mem.eql(u8, arg, "-fno-emit-asm")) {
1523 if (emit == .@"asm") emit = null;
1524 } else if (std.mem.eql(u8, arg, "-fno-emit-bin")) {
1525 if (emit == .bin) emit = null;
1526 } else if (std.mem.eql(u8, arg, "-fno-emit-docs")) {
1527 if (emit == .docs) emit = null;
1528 } else if (std.mem.eql(u8, arg, "-fno-emit-h")) {
1529 if (emit == .h) emit = null;
1530 } else if (std.mem.eql(u8, arg, "-fno-emit-implib")) {
1531 if (emit == .implib) emit = null;
1532 } else if (std.mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
1533 if (emit == .llvm_bc) emit = null;
1534 } else if (std.mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
1535 if (emit == .llvm_ir) emit = null;
1536 },
1537 .@"--name" => {
1538 root_name = arg;
1539 state = .positional;
1540 },
1541 }
1542 try argv.append(gpa, arg);
1543 args_r.toss(end);
1544 need = 1;
1545 } else {
1546 args_r.toss(start);
1547 need = buffered.len - start + 1;
1548 }
1549 if (done) break;
1550 }
1551 try argv.append(gpa, "--listen=-");
1552
1553 comp.emit_name = if (emit) |e| try e.cacheName(arena, .{
1554 .root_name = root_name orelse "root",
1555 .cpu_arch = comp.target.resolved.cpu.arch,
1556 .os_tag = comp.target.resolved.os.tag,
1557 .ofmt = comp.target.resolved.ofmt,
1558 .abi = comp.target.resolved.abi,
1559 .output_mode = output_mode,
1560 }) else null;
1561
1562 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1563 comp.prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "compile {s}", .{
1564 comp.emit_name orelse root_name orelse "root",
1565 }) catch &name_buffer, 0);
1566 errdefer comp.prog_node.end();
1567
1568 comp.child = std.process.spawn(runner.io, .{
1569 .exe = .{ .file = runner.args.zig_exe orelse
1570 return runner.fail("missing \"--zig=path/to/zig\" arg", .{}) },
1571 .argv = argv.items,
1572 .cwd = .{ .dir = src_dir },
1573 .progress_node = comp.prog_node,
1574 .stdin = .pipe,
1575 .stdout = .pipe,
1576 .stderr = .pipe,
1577 }) catch |err| switch (err) {
1578 error.Canceled, error.OutOfMemory => |e| return e,
1579 error.OperationUnsupported => return error.SkipTest,
1580 else => |e| return runner.fail("unable to spawn compiler: {t}", .{e}),
1581 };
1582 comp.fw = comp.child.stdin.?.writerStreaming(runner.io, &.{});
1583 comp.mr.init(gpa, runner.io, comp.mr_buffer.toStreams(), &.{
1584 comp.child.stdout.?, comp.child.stderr.?,
1585 });
1586 comp.client = .{ .in = comp.mr.reader(0), .out = &comp.fw.interface };
1587}
1588const Compiler = struct {
1589 runner: *Runner,
1590 allow_compiler_stderr: bool,
1591 output_mode: std.lang.OutputMode,
1592 state: enum { idle, update },
1593 child: std.process.Child,
1594 fw: std.Io.File.Writer,
1595 mr_buffer: std.Io.File.MultiReader.Buffer(2),
1596 mr: std.Io.File.MultiReader,
1597 client: std.zig.Client,
1598 target: Compiler.Target,
1599 emit_name: ?[]const u8,
1600 prog_node: std.Progress.Node,
1601 config: ?std.zig.Server.Message.Config,
1602
1603 const Target = struct {
1604 triple: []const u8,
1605 resolved: std.Target,
1606 cache_mode: CacheMode,
1607 backend: ?Backend,
1608 linker: Linker,
1609 pic: Pic,
1610
1611 const CacheMode = enum { whole, incremental };
1612
1613 const Backend = enum {
1614 /// Run semantic analysis only. Runtime output will not be tested, but we still verify
1615 /// that compilation succeeds. Corresponds to `-fno-emit-bin`.
1616 sema,
1617 /// Use the self-hosted code generation backend for this target.
1618 /// Corresponds to `-fno-llvm -fno-lld`.
1619 selfhosted,
1620 /// Use the LLVM backend.
1621 /// Corresponds to `-fllvm -flld`.
1622 llvm,
1623 /// Use the C backend. The output is compiled with `zig cc`.
1624 /// Corresponds to `-ofmt=c`.
1625 cbe,
1626 };
1627
1628 const Linker = enum { old, new, lld };
1629
1630 const Pic = enum { nopic, pic, pie };
1631 };
1632
1633 fn deinit(comp: *Compiler) void {
1634 comp.child.kill(comp.runner.io);
1635 comp.prog_node.end();
1636 comp.prog_node = .none;
1637 }
1638
1639 fn receiveMessage(comp: *Compiler) FailError!?struct {
1640 tag: std.zig.Server.Message.Tag,
1641 body: []const u8,
1642 } {
1643 const header = comp.client.receiveMessageWithMultiReader(
1644 &comp.mr,
1645 .none,
1646 ) catch |err| switch (err) {
1647 error.Canceled, error.OutOfMemory => |e| return e,
1648 error.Timeout => unreachable,
1649 error.EndOfStream => return null,
1650 else => |e| return comp.runner.fail("unable to receive message: {t}", .{e}),
1651 };
1652 const body = comp.client.in.take(header.bytes_len) catch unreachable;
1653 const stderr = comp.mr.reader(1);
1654 if (stderr.bufferedLen() > 0) {
1655 if (comp.allow_compiler_stderr) {
1656 std.log.info("{t} stderr:\n{s}", .{ header.tag, stderr.buffered() });
1657 } else {
1658 return comp.runner.fail("{t} unexpected stderr:\n{s}", .{
1659 header.tag, stderr.buffered(),
1660 });
1661 }
1662 stderr.tossBuffered();
1663 }
1664 return .{ .tag = header.tag, .body = body };
1665 }
1666
1667 const Check = enum { errors, stdout, exit, llvm, gdb, lldb };
1668 fn checkSuccess(
1669 comp: *Compiler,
1670 update: *const Update,
1671 check: Check,
1672 expected: []const u8,
1673 digest: *const std.Build.Cache.BinDigest,
1674 ) TestError!void {
1675 const runner = comp.runner;
1676 const gpa = runner.gpa;
1677 const arena = runner.arena.allocator();
1678 const io = runner.io;
1679 const target = &comp.target.resolved;
1680 const emit_name = switch (check) {
1681 else => comp.emit_name orelse
1682 return update.fail("unable to perform {t} check without emitted file", .{check}),
1683 .errors => return, // expect no emitted file
1684 };
1685 const config = &comp.config.?;
1686 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
1687
1688 // After a failure while running a script, the debugger starts accepting commands from stdin, and
1689 // because it is empty, the debugger exits normally with status 0. Choose a non-zero status to
1690 // return from the debugger script instead to detect it running to completion and indicate success.
1691 const debug_success = 99;
1692
1693 const tmp_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "tmp";
1694 update.src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) {
1695 error.Canceled => |e| return e,
1696 else => |e| return update.fail("unable to create dir path {q}: {t}", .{
1697 tmp_dir_path, e,
1698 }),
1699 };
1700
1701 const emit_path = emit_path: {
1702 const emit_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++
1703 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);
1704 const emit_path =
1705 try std.Io.Dir.path.join(arena, &.{ emit_dir_path, emit_name });
1706 break :emit_path switch (comp.target.backend.?) {
1707 .sema => return,
1708 .selfhosted, .llvm => emit_path,
1709 .cbe => try comp.compileC(update.src_dir, emit_path),
1710 };
1711 };
1712
1713 const emit_file = update.src_dir.openFile(io, emit_path, .{}) catch |err| switch (err) {
1714 error.Canceled => |e| return e,
1715 else => |e| return update.fail("unable to open {q}: {t}", .{ emit_path, e }),
1716 };
1717 defer emit_file.close(io);
1718
1719 var argv: std.ArrayList([]const u8) = try .initCapacity(arena, 5 + 4);
1720 var environ_map: std.process.Environ.Map = .init(gpa);
1721 defer environ_map.deinit();
1722 try environ_map.putAll(&runner.environ_map);
1723 var script_buffer: [512]u8 = undefined;
1724 const script_path, const script_file, var script_fw = script: switch (check) {
1725 .errors => unreachable,
1726 .stdout, .exit => .{ undefined, null, undefined },
1727 .llvm => {
1728 var emit_fr = emit_file.reader(io, &.{});
1729 const actual = emit_fr.interface.readAllocAll(arena, @intCast(
1730 emit_fr.getSize() catch |err| switch (err) {
1731 error.Canceled => |e| return e,
1732 else => |e| return runner.fail("unable to get size of {q}: {t}", .{ emit_path, e }),
1733 },
1734 )) catch |err| switch (switch (err) {
1735 error.OutOfMemory => |e| return e,
1736 error.EndOfStream => |e| e,
1737 error.ReadFailed => emit_fr.err.?,
1738 }) {
1739 error.Canceled => |e| return e,
1740 else => |e| return runner.fail("unable to read {q}: {t}", .{ emit_path, e }),
1741 };
1742 return update.checkMatches("LLVM IR", expected, actual);
1743 },
1744 .gdb => {
1745 const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb";
1746 argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" });
1747 const script_file =
1748 update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
1749 error.Canceled => |e| return e,
1750 else => |e| return update.fail("unable to create debugger script {q}: {t}", .{
1751 script_path, e,
1752 }),
1753 };
1754 errdefer script_file.close(io);
1755 var script_fw = script_file.writer(io, &script_buffer);
1756 script_fw.interface.writeAll(
1757 \\set remotetimeout 0
1758 \\
1759 \\
1760 ) catch |err| switch (err) {
1761 error.WriteFailed => switch (script_fw.err.?) {
1762 error.Canceled => |e| return e,
1763 else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
1764 script_path, e,
1765 }),
1766 },
1767 };
1768 break :script .{ script_path, script_file, script_fw };
1769 },
1770 .lldb => {
1771 const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "lldb";
1772 argv.appendSliceAssumeCapacity(&.{ "lldb", "--batch", "--source", script_path, "--" });
1773 try environ_map.put("LANG", "C.UTF-8"); // affects output formatting
1774 const script_file =
1775 update.src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
1776 error.Canceled => |e| return e,
1777 else => |e| return update.fail("unable to create debugger script {q}: {t}", .{
1778 script_path, e,
1779 }),
1780 };
1781 errdefer script_file.close(io);
1782 var script_fw = script_file.writer(io, &script_buffer);
1783 script_fw.interface.writeAll(
1784 \\settings set frame-format 'frame #${frame.index}:{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.basename}:${line.number}{:${line.column}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n'
1785 \\settings set plugin.process.gdb-remote.packet-timeout 0
1786 \\settings set stop-line-count-after 0
1787 \\settings set stop-line-count-before 0
1788 \\
1789 ) catch |err| switch (err) {
1790 error.WriteFailed => switch (script_fw.err.?) {
1791 error.Canceled => |e| return e,
1792 else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
1793 script_path, e,
1794 }),
1795 },
1796 };
1797 break :script .{ script_path, script_file, script_fw };
1798 },
1799 };
1800 defer if (script_file) |file| file.close(io);
1801
1802 const need_cross_libc =
1803 target.os.tag == .linux and config.flags.link_libc and config.flags.link_mode == .dynamic;
1804 const use_executor = use_executor: switch (std.zig.system.getExternalExecutor(io, target, .{
1805 .host_cpu_arch = runner.host.cpu.arch,
1806 .host_os_tag = runner.host.os.tag,
1807 .qemu_fixes_dl = need_cross_libc and runner.args.libc_runtimes_dir != null,
1808 .link_mode = config.flags.link_mode,
1809 .link_libc = config.flags.link_libc,
1810 })) {
1811 .bad_dl, .bad_os_or_cpu => {
1812 // This binary cannot be executed on this host.
1813 if (!runner.args.quiet) std.log.warn("skipping execution because host {q} cannot " ++
1814 "execute binaries for foreign target {q}", .{
1815 try runner.host.zigTriple(arena), comp.target.triple,
1816 });
1817 return;
1818 },
1819 .native => false,
1820 .darling => |executor| if (runner.args.enable_darling) {
1821 argv.appendAssumeCapacity(executor);
1822 break :use_executor true;
1823 } else continue :use_executor .bad_os_or_cpu,
1824 .qemu => |executor| if (runner.args.enable_qemu) {
1825 argv.appendAssumeCapacity(executor);
1826 if (need_cross_libc) {
1827 const libc_runtimes_dir = runner.args.libc_runtimes_dir orelse
1828 continue :use_executor .bad_os_or_cpu;
1829 const libc_runtimes_path = path_buffer[0 .. libc_runtimes_dir.realPath(
1830 io,
1831 &path_buffer,
1832 ) catch |err| switch (err) {
1833 error.Canceled => |e| return e,
1834 else => |e| return update.fail("unable to get libc runtimes path: {t}", .{e}),
1835 }];
1836 argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{
1837 libc_runtimes_path,
1838 try if (target.isGnuLibC()) std.zig.target.glibcRuntimeTriple(
1839 arena,
1840 target.cpu.arch,
1841 target.os.tag,
1842 target.abi,
1843 ) else if (target.isMuslLibC()) std.zig.target.muslRuntimeTriple(
1844 arena,
1845 target.cpu.arch,
1846 target.abi,
1847 ) else unreachable,
1848 }) });
1849 }
1850 break :use_executor true;
1851 } else continue :use_executor .bad_os_or_cpu,
1852 .rosetta => if (runner.args.enable_rosetta)
1853 true
1854 else
1855 continue :use_executor .bad_os_or_cpu,
1856 .wine => |executor| if (runner.args.enable_wine) {
1857 if (!environ_map.contains("WINEDEBUG")) try environ_map.put("WINEDEBUG", "-all");
1858 argv.appendAssumeCapacity(executor);
1859 break :use_executor true;
1860 } else continue :use_executor .bad_os_or_cpu,
1861 .wasmtime => |executor| if (runner.args.enable_wasmtime) {
1862 if (!environ_map.contains("WASMTIME_BACKTRACE_DETAILS"))
1863 try environ_map.put("WASMTIME_BACKTRACE_DETAILS", "1");
1864 argv.appendSliceAssumeCapacity(&.{ executor, "--dir=.", "-Sinherit-env" });
1865 break :use_executor true;
1866 } else continue :use_executor .bad_os_or_cpu,
1867 };
1868 argv.appendAssumeCapacity(emit_path);
1869
1870 if (!runner.args.quiet) std.log.info("{f}", .{std.zig.SubprocessCommand{
1871 .argv = argv.items,
1872 .cwd = cwd_path: {
1873 break :cwd_path path_buffer[0 .. update.src_dir.realPath(
1874 io,
1875 &path_buffer,
1876 ) catch |err| switch (err) {
1877 error.Canceled => |e| return e,
1878 else => break :cwd_path null,
1879 }];
1880 },
1881 .parent_env = &runner.environ_map,
1882 .child_env = &environ_map,
1883 }});
1884
1885 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1886 const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{
1887 emit_name,
1888 }) catch &name_buffer, 0);
1889 defer run_prog_node.end();
1890
1891 const result = std.process.run(gpa, io, .{
1892 .exe = exe: switch (check) {
1893 .errors, .llvm => unreachable,
1894 .stdout, .exit => if (use_executor) .search else .{ .file = emit_file },
1895 .gdb, .lldb => {
1896 if (use_executor) {
1897 if (!runner.args.quiet) std.log.warn(
1898 "skipping debugging of {q} via executor for foreign target {q}",
1899 .{ emit_path, comp.target.triple },
1900 );
1901 return;
1902 }
1903
1904 var line_it = std.mem.splitScalar(u8, expected, '\n');
1905 while (line_it.next()) |line| if (std.mem.cutPrefix(u8, line, switch (check) {
1906 else => unreachable,
1907 .gdb => "(gdb) ",
1908 .lldb => "(lldb) ",
1909 })) |cmd| script_fw.interface.print(
1910 \\{s}
1911 \\
1912 , .{cmd}) catch |err| switch (err) {
1913 error.WriteFailed => switch (script_fw.err.?) {
1914 error.Canceled => |e| return e,
1915 else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
1916 script_path, e,
1917 }),
1918 },
1919 };
1920 script_fw.interface.print(
1921 \\
1922 \\quit {d}
1923 \\
1924 , .{debug_success}) catch |err| switch (err) {
1925 error.WriteFailed => switch (script_fw.err.?) {
1926 error.Canceled => |e| return e,
1927 else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
1928 script_path, e,
1929 }),
1930 },
1931 };
1932 script_fw.flush() catch |err| switch (err) {
1933 error.Canceled => |e| return e,
1934 else => |e| return update.fail("unable to write debugger script {q}: {t}", .{
1935 script_path, e,
1936 }),
1937 };
1938 break :exe .{ .file = switch (check) {
1939 else => unreachable,
1940 .gdb => runner.args.gdb_exe,
1941 .lldb => runner.args.lldb_exe,
1942 } orelse {
1943 if (!runner.args.quiet) std.log.warn(
1944 "skipping debugging of {q} because of missing \"--{t}=path/to/{[1]t}\" arg",
1945 .{ emit_path, check },
1946 );
1947 return;
1948 } };
1949 },
1950 },
1951 .argv = argv.items,
1952 .cwd = .{ .dir = update.src_dir },
1953 .environ_map = &environ_map,
1954 .progress_node = run_prog_node,
1955 }) catch |err| if (use_executor) {
1956 // Chances are the foreign executor isn't available. Skip this evaluation.
1957 if (!runner.args.quiet) std.log.warn(
1958 "skipping execution of {q} via executor for foreign target {q}: {t}",
1959 .{ emit_path, comp.target.triple, err },
1960 );
1961 return;
1962 } else return update.fail("unable to run the generated executable {q}: {t}", .{
1963 emit_path, err,
1964 });
1965 defer {
1966 gpa.free(result.stdout);
1967 gpa.free(result.stderr);
1968 }
1969 switch (result.term) {
1970 .exited => |code| switch (check) {
1971 .errors, .llvm => unreachable,
1972 .stdout => {
1973 if (code != 0) return update.fail(
1974 "generated executable {q} failed with code {d}",
1975 .{ emit_path, code },
1976 );
1977 std.testing.expectEqualStrings(
1978 expected,
1979 result.stdout,
1980 ) catch |err| switch (err) {
1981 error.TestExpectedEqual => return update.fail(
1982 "stdout did not match expected",
1983 .{},
1984 ),
1985 };
1986 },
1987 .exit => {
1988 var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 =
1989 undefined;
1990 std.testing.expectEqualStrings(
1991 expected,
1992 std.mem.print(&actual_code_buffer, "{d}", .{code}) catch unreachable,
1993 ) catch |err| switch (err) {
1994 error.TestExpectedEqual => return update.fail(
1995 "exit code did not match expected",
1996 .{},
1997 ),
1998 };
1999 },
2000 .gdb, .lldb => {
2001 if (code != debug_success) return update.fail(
2002 "debugging {q} failed with code {d}",
2003 .{ emit_path, code },
2004 );
2005 try update.checkMatches("stdout", expected, result.stdout);
2006 },
2007 },
2008 .signal => |sig| return update.fail(
2009 "generated executable {q} terminated with signal {t}",
2010 .{ emit_path, sig },
2011 ),
2012 .stopped => |sig| return update.fail(
2013 "generated executable {q} stopped with signal {t}",
2014 .{ emit_path, sig },
2015 ),
2016 .unknown => return update.fail(
2017 "generated executable {q} terminated unexpectedly",
2018 .{emit_path},
2019 ),
2020 }
2021 if (!use_executor and result.stderr.len > 0) {
2022 std.log.err("#update {q} generated executable {q} had unexpected stderr:\n{s}", .{
2023 update.name, emit_path, result.stderr,
2024 });
2025 }
2026 }
2027
2028 fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) TestError![]const u8 {
2029 const runner = parent_comp.runner;
2030 const arena = runner.arena.allocator();
2031 var compiler: ?Compiler = null;
2032 var args_r: std.Io.Reader = .fixed(c_path);
2033 parent_comp.runner.spawnCompiler(&compiler, src_dir, parent_comp.output_mode, &args_r, .{
2034 .triple = parent_comp.target.triple,
2035 .resolved = resolved: {
2036 var resolved = parent_comp.target.resolved;
2037 resolved.ofmt = .default(resolved.os.tag, resolved.cpu.arch);
2038 break :resolved resolved;
2039 },
2040 .cache_mode = .whole,
2041 .backend = null,
2042 .linker = .lld,
2043 .pic = parent_comp.target.pic,
2044 }) catch |err| switch (err) {
2045 error.Canceled, error.OutOfMemory, error.AlreadyReported, error.SkipTest => |e| return e,
2046 error.ReadFailed => unreachable, // .fixed
2047 };
2048 const comp = &compiler.?;
2049 defer comp.deinit();
2050 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
2051 error.WriteFailed => switch (comp.fw.err.?) {
2052 error.Canceled => |e| return e,
2053 else => |e| return runner.fail("unable to send message: {t}", .{e}),
2054 },
2055 };
2056 comp.state = .update;
2057 var emit_path: ?[]const u8 = null;
2058 while (try comp.receiveMessage()) |message| switch (message.tag) {
2059 else => {}, // Ignore other messages,
2060 .config => {
2061 var body_r: std.Io.Reader = .fixed(message.body);
2062 comp.config =
2063 body_r.takeStruct(std.zig.Server.Message.Config, .little) catch unreachable;
2064 },
2065 .emit_digest => {
2066 var body_r: std.Io.Reader = .fixed(message.body);
2067 _ = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable;
2068 const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch unreachable;
2069
2070 const emit_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++
2071 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);
2072 emit_path = try std.Io.Dir.path.join(arena, &.{ emit_dir, comp.emit_name.? });
2073 },
2074 .error_bundle => {
2075 const eb = std.zig.Server.allocErrorBundle(
2076 runner.arena.allocator(),
2077 message.body,
2078 ) catch |err| switch (err) {
2079 error.OutOfMemory => |e| return e,
2080 error.EndOfStream => return runner.fail("error bundle truncated", .{}),
2081 };
2082 if (eb.errorMessageCount() > 0) {
2083 try runner.eb_wip.addBundleAsRoots(eb);
2084 return runner.fail("unexpected compile errors", .{});
2085 }
2086 comp.state = .idle;
2087 break;
2088 },
2089 };
2090 try comp.exit();
2091 return emit_path.?;
2092 }
2093
2094 fn exit(comp: *Compiler) FailError!void {
2095 const runner = comp.runner;
2096 comp.client.serveBodylessMessage(.exit) catch |err| switch (err) {
2097 error.WriteFailed => switch (comp.fw.err.?) {
2098 error.Canceled => |e| return e,
2099 error.BrokenPipe => {},
2100 else => |e| return comp.runner.fail("unable to send exit: {t}", .{e}),
2101 },
2102 };
2103 comp.child.stdin.?.close(runner.io);
2104 comp.child.stdin = null;
2105 while (try comp.receiveMessage()) |_| {}
2106 if (comp.client.in.bufferedLen() > 0) return runner.fail("unable to receive messages", .{});
2107 const term = comp.child.wait(runner.io) catch |err|
2108 return runner.fail("child process failed: {t}", .{err});
2109 switch (term) {
2110 .exited => |code| if (code != 0)
2111 return runner.fail("compiler failed with code {d}", .{code}),
2112 .signal => |sig| return runner.fail("compiler terminated with signal {t}", .{sig}),
2113 .stopped => |sig| return runner.fail("compiler stopped unexpectedly with signal {t}", .{
2114 sig,
2115 }),
2116 .unknown => return runner.fail("compiler terminated unexpectedly", .{}),
2117 }
2118 }
2119};
2120
2121const ClientArgs = struct {
2122 test_file: std.Io.File,
2123 test_kind: std.Io.File.Kind,
2124 zig_exe: std.Io.File,
2125 lib_dir: std.Io.Dir,
2126 src_dir: std.Io.Dir,
2127 targets: std.ArrayList([]const u8),
2128
2129 libc_runtimes_dir: ?std.Io.Dir,
2130 enable_darling: bool,
2131 enable_qemu: bool,
2132 enable_rosetta: bool,
2133 enable_wine: bool,
2134 enable_wasmtime: bool,
2135
2136 gdb_exe: ?std.Io.File,
2137 lldb_exe: ?std.Io.File,
2138
2139 quiet: bool,
2140 keep_src: bool,
2141};
2142pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelable)!u8 {
2143 const fatal = struct {
2144 fn fatal(comptime fmt: []const u8, args: anytype) noreturn {
2145 std.log.err(fmt, args);
2146 std.process.exit(1);
2147 }
2148 }.fatal;
2149 const arena = init.arena.allocator();
2150
2151 var test_path_arg: ?[]const u8 = null;
2152 var zig_path_arg: ?[]const u8 = null;
2153 var lib_path_arg: ?[]const u8 = null;
2154 var libc_runtimes_path_arg: ?[]const u8 = null;
2155 var gdb_path_arg: ?[]const u8 = null;
2156 var lldb_path_arg: ?[]const u8 = null;
2157 var args: ClientArgs = .{
2158 .test_file = undefined,
2159 .test_kind = undefined,
2160 .zig_exe = undefined,
2161 .lib_dir = undefined,
2162 .src_dir = undefined,
2163 .targets = .empty,
2164
2165 .libc_runtimes_dir = null,
2166 .enable_darling = false,
2167 .enable_qemu = false,
2168 .enable_rosetta = false,
2169 .enable_wine = false,
2170 .enable_wasmtime = false,
2171
2172 .gdb_exe = null,
2173 .lldb_exe = null,
2174
2175 .quiet = false,
2176 .keep_src = false,
2177 };
2178 defer args.targets.deinit(init.gpa);
2179
2180 var arg_it = try init.minimal.args.iterateAllocator(arena);
2181 const self = arg_it.next().?;
2182 while (arg_it.next()) |arg| {
2183 if (std.mem.eql(u8, arg, "--listen=-")) {
2184 var stdin_buffer: [512]u8 = undefined;
2185 var stdin: std.Io.File.Reader = .initStreaming(.stdin(), init.io, &stdin_buffer);
2186 var stdout_buffer: [512]u8 = undefined;
2187 var stdout: std.Io.File.Writer = .initStreaming(.stdout(), init.io, &stdout_buffer);
2188 var runner: Runner = .{
2189 .gpa = init.gpa,
2190 .arena = init.arena,
2191 .environ_map = init.minimal.environ.createMap(init.gpa) catch |err| switch (err) {
2192 error.OutOfMemory => |e| return e,
2193 else => |e| fatal("unable to get environment: {t}", .{e}),
2194 },
2195 .io = init.io,
2196 .prog_node = std.Progress.start(init.io, .{}),
2197 .args = .{
2198 .@"test" = null,
2199 .manifest_file = null,
2200 .zig_exe = null,
2201 .lib_dir = null,
2202 .src_dir = null,
2203 .targets = .empty,
2204 .target_bytes = .empty,
2205
2206 .libc_runtimes_dir = null,
2207 .enable_darling = false,
2208 .enable_qemu = false,
2209 .enable_rosetta = false,
2210 .enable_wasmtime = false,
2211 .enable_wine = false,
2212
2213 .gdb_exe = null,
2214 .lldb_exe = null,
2215
2216 .quiet = false,
2217 },
2218 .host = std.zig.system.resolveTargetQuery(init.io, .{}) catch |err| switch (err) {
2219 error.Canceled => |e| return e,
2220 else => |e| fatal("unable to resolve host target: {t}", .{e}),
2221 },
2222 .server = .{
2223 .in = &stdin.interface,
2224 .out = &stdout.interface,
2225 },
2226 .eb_wip = try .init(init.gpa),
2227 };
2228 defer runner.deinit();
2229 switch (runner.runServer()) {
2230 error.Canceled, error.OutOfMemory => |e| return e,
2231 error.ServerReadFailed => switch (stdin.err.?) {
2232 error.Canceled => |e| return e,
2233 else => |e| fatal("unable to receive message: {t}", .{e}),
2234 },
2235 error.ServerWriteFailed => switch (stdout.err.?) {
2236 error.Canceled => |e| return e,
2237 else => |e| fatal("unable to send message: {t}", .{e}),
2238 },
2239 error.ServerEndOfStream => fatal("no more messages", .{}),
2240 error.AlreadyReported => {
2241 var eb = try runner.eb_wip.toOwnedBundle("");
2242 defer eb.deinit(init.gpa);
2243 eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) {
2244 error.Canceled => |e| return e,
2245 else => {},
2246 };
2247 std.process.exit(1);
2248 },
2249 }
2250 } else if (std.mem.eql(u8, arg, "--zig")) {
2251 zig_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
2252 } else if (std.mem.cutPrefix(u8, arg, "--zig=")) |zig_path| {
2253 zig_path_arg = zig_path;
2254 } else if (std.mem.eql(u8, arg, "--lib")) {
2255 lib_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
2256 } else if (std.mem.cutPrefix(u8, arg, "--lib=")) |lib_path| {
2257 lib_path_arg = lib_path;
2258 } else if (std.mem.eql(u8, arg, "--target")) {
2259 try args.targets.append(
2260 init.gpa,
2261 try arena.dupe(u8, arg_it.next() orelse fatal("missing arg after {q}", .{arg})),
2262 );
2263 } else if (std.mem.cutPrefix(u8, arg, "--target=")) |target| {
2264 try args.targets.append(init.gpa, try arena.dupe(u8, target));
2265 } else if (std.mem.eql(u8, arg, "--libc-runtimes")) {
2266 libc_runtimes_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
2267 } else if (std.mem.cutPrefix(u8, arg, "--libc-runtimes=")) |libc_runtimes_path| {
2268 libc_runtimes_path_arg = libc_runtimes_path;
2269 } else if (std.mem.eql(u8, arg, "-fdarling")) {
2270 args.enable_darling = true;
2271 } else if (std.mem.eql(u8, arg, "-fqemu")) {
2272 args.enable_qemu = true;
2273 } else if (std.mem.eql(u8, arg, "-frosetta")) {
2274 args.enable_rosetta = true;
2275 } else if (std.mem.eql(u8, arg, "-fwine")) {
2276 args.enable_wine = true;
2277 } else if (std.mem.eql(u8, arg, "-fwasmtime")) {
2278 args.enable_wasmtime = true;
2279 } else if (std.mem.eql(u8, arg, "--gdb")) {
2280 gdb_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
2281 } else if (std.mem.cutPrefix(u8, arg, "--gdb=")) |gdb_path| {
2282 gdb_path_arg = gdb_path;
2283 } else if (std.mem.eql(u8, arg, "--lldb")) {
2284 lldb_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
2285 } else if (std.mem.cutPrefix(u8, arg, "--lldb=")) |lldb_path| {
2286 lldb_path_arg = lldb_path;
2287 } else if (std.mem.eql(u8, arg, "--quiet")) {
2288 args.quiet = true;
2289 } else if (std.mem.eql(u8, arg, "--keep-src")) {
2290 args.keep_src = true;
2291 } else {
2292 if (test_path_arg) |_| fatal("unexpected arg {q}", .{arg});
2293 test_path_arg = arg;
2294 }
2295 }
2296
2297 const test_path = test_path_arg orelse fatal("missing \"path/to/test\" arg", .{});
2298 const zig_path = zig_path_arg orelse fatal("missing \"--zig=path/to/zig\" arg", .{});
2299 const lib_path = lib_path_arg orelse fatal("missing \"--lib=path/to/lib\" arg", .{});
2300
2301 const cwd: std.Io.Dir = .cwd();
2302 args.test_file = cwd.openFile(init.io, test_path, .{
2303 .allow_directory = true,
2304 }) catch |err| switch (err) {
2305 error.Canceled => |e| return e,
2306 else => |e| fatal("unable to open {q}: {t}", .{ test_path, e }),
2307 };
2308 defer args.test_file.close(init.io);
2309 args.test_kind = (args.test_file.stat(init.io) catch |err| switch (err) {
2310 error.Canceled => |e| return e,
2311 else => |e| fatal("unable to stat {q}: {t}", .{ test_path, e }),
2312 }).kind;
2313 args.zig_exe = cwd.openFile(init.io, zig_path, .{}) catch |err| switch (err) {
2314 error.Canceled => |e| return e,
2315 else => |e| fatal("unable to open {q}: {t}", .{ zig_path, e }),
2316 };
2317 defer args.zig_exe.close(init.io);
2318 args.lib_dir = cwd.openDir(init.io, lib_path, .{}) catch |err| switch (err) {
2319 error.Canceled => |e| return e,
2320 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
2321 };
2322 defer args.lib_dir.close(init.io);
2323 if (libc_runtimes_path_arg) |libc_runtimes_path| args.libc_runtimes_dir = cwd.openDir(
2324 init.io,
2325 libc_runtimes_path,
2326 .{},
2327 ) catch |err| switch (err) {
2328 error.Canceled => |e| return e,
2329 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
2330 };
2331 defer if (args.libc_runtimes_dir) |libc_runtimes_dir| libc_runtimes_dir.close(init.io);
2332 if (gdb_path_arg) |gdb_path| args.gdb_exe = cwd.openFile(init.io, gdb_path, .{}) catch |err| switch (err) {
2333 error.Canceled => |e| return e,
2334 else => |e| fatal("unable to open {q}: {t}", .{ gdb_path, e }),
2335 };
2336 defer if (args.gdb_exe) |gdb_exe| gdb_exe.close(init.io);
2337 if (lldb_path_arg) |lldb_path| args.lldb_exe = cwd.openFile(init.io, lldb_path, .{}) catch |err| switch (err) {
2338 error.Canceled => |e| return e,
2339 else => |e| fatal("unable to open {q}: {t}", .{ lldb_path, e }),
2340 };
2341 defer if (args.lldb_exe) |lldb_exe| lldb_exe.close(init.io);
2342
2343 const src_dir_path = "src_" ++ std.fmt.hex(rand_int: {
2344 var rand_int: u64 = undefined;
2345 init.io.random(@ptrCast(&rand_int));
2346 break :rand_int rand_int;
2347 });
2348 args.src_dir = cwd.createDirPathOpen(init.io, src_dir_path, .{}) catch |err| switch (err) {
2349 error.Canceled => |e| return e,
2350 else => |e| fatal("unable to create {q}: {t}", .{ src_dir_path, e }),
2351 };
2352 defer {
2353 args.src_dir.close(init.io);
2354 if (!args.keep_src) cwd.deleteTree(init.io, src_dir_path) catch |err| {
2355 std.log.warn("unable to delete tree {q}: {t}", .{ src_dir_path, err });
2356 };
2357 }
2358
2359 var inherit_dirs: std.ArrayList(std.Io.Dir) = try .initCapacity(arena, 3);
2360 var inherit_files: std.ArrayList(std.Io.File) = try .initCapacity(arena, 4);
2361 inherit_files.appendSliceAssumeCapacity(&.{ args.test_file, args.zig_exe });
2362 inherit_dirs.appendSliceAssumeCapacity(&.{ args.lib_dir, args.src_dir });
2363 if (args.libc_runtimes_dir) |libc_runtimes_dir| inherit_dirs.appendAssumeCapacity(libc_runtimes_dir);
2364 if (args.gdb_exe) |gdb_exe| inherit_files.appendAssumeCapacity(gdb_exe);
2365 if (args.lldb_exe) |lldb_exe| inherit_files.appendAssumeCapacity(lldb_exe);
2366 var child = std.process.spawn(init.io, .{
2367 .argv = &.{ self, "--listen=-" },
2368 .stdin = .pipe,
2369 .stdout = .pipe,
2370 .inherit_dirs = inherit_dirs.items,
2371 .inherit_files = inherit_files.items,
2372 }) catch |err| switch (err) {
2373 error.Canceled, error.OutOfMemory => |e| return e,
2374 else => |e| fatal("unable to spawn runner: {t}", .{e}),
2375 };
2376
2377 var child_reader_buffer: [512]u8 = undefined;
2378 var child_reader = child.stdout.?.readerStreaming(init.io, &child_reader_buffer);
2379 var child_writer_buffer: [512]u8 = undefined;
2380 var child_writer = child.stdin.?.writerStreaming(init.io, &child_writer_buffer);
2381 var client: std.zig.Client = .{
2382 .in = &child_reader.interface,
2383 .out = &child_writer.interface,
2384 };
2385 const success = runClient(init.gpa, arena, init.io, &client, &args) catch |err| switch (err) {
2386 error.OutOfMemory => |e| return e,
2387 error.ReadFailed => switch (child_reader.err.?) {
2388 error.Canceled => |e| return e,
2389 else => |e| fatal("unable to receive message: {t}", .{e}),
2390 },
2391 error.WriteFailed => switch (child_writer.err.?) {
2392 error.Canceled => |e| return e,
2393 else => |e| fatal("unable to send message: {t}", .{e}),
2394 },
2395 error.EndOfStream => fatal("no more messages", .{}),
2396 };
2397 _ = child.wait(init.io) catch |err| switch (err) {
2398 error.Canceled => |e| return e,
2399 else => |e| fatal("unable to wait for runner: {t}", .{e}),
2400 };
2401 return if (success) 0 else 1;
2402}
2403fn runClient(
2404 gpa: std.mem.Allocator,
2405 arena: std.mem.Allocator,
2406 io: std.Io,
2407 client: *std.zig.Client,
2408 args: *const ClientArgs,
2409) (std.mem.Allocator.Error || std.Io.Reader.Error || std.Io.Writer.Error)!bool {
2410 var stdout_buffer: [512]u8 = undefined;
2411 var stdout_fw: std.Io.File.Writer = .initStreaming(.stdout(), io, &stdout_buffer);
2412 const stdout = &stdout_fw.interface;
2413 var stderr_buffer: [512]u8 = undefined;
2414 var stderr_fw: std.Io.File.Writer = .initStreaming(.stderr(), io, &stderr_buffer);
2415 const stderr = &stderr_fw.interface;
2416
2417 var argv: std.ArrayList(u8) = .empty;
2418 defer argv.deinit(gpa);
2419 const Arg = std.zig.Client.Message.Arg;
2420
2421 try argv.append(gpa, @backingInt(@as(Arg, switch (args.test_kind) {
2422 else => unreachable,
2423 .file => .input_file,
2424 .directory => .input_dir,
2425 })));
2426 try argv.appendSlice(gpa, @ptrCast(&args.test_file.handle));
2427
2428 try argv.append(gpa, @backingInt(Arg.prefix));
2429 try argv.appendSlice(gpa, "--zig=");
2430 try argv.append(gpa, 0);
2431 try argv.append(gpa, @backingInt(Arg.input_file));
2432 try argv.appendSlice(gpa, @ptrCast(&args.zig_exe.handle));
2433
2434 try argv.append(gpa, @backingInt(Arg.prefix));
2435 try argv.appendSlice(gpa, "--lib=");
2436 try argv.append(gpa, 0);
2437 try argv.append(gpa, @backingInt(Arg.input_dir));
2438 try argv.appendSlice(gpa, @ptrCast(&args.lib_dir.handle));
2439
2440 try argv.append(gpa, @backingInt(Arg.prefix));
2441 try argv.appendSlice(gpa, "--src=");
2442 try argv.append(gpa, 0);
2443 try argv.append(gpa, @backingInt(Arg.output_dir));
2444 try argv.appendSlice(gpa, @ptrCast(&args.src_dir.handle));
2445
2446 for (args.targets.items) |target| {
2447 try argv.append(gpa, @backingInt(Arg.string));
2448 try argv.appendSlice(gpa, "--target");
2449 try argv.append(gpa, 0);
2450
2451 try argv.append(gpa, @backingInt(Arg.string));
2452 try argv.appendSlice(gpa, target);
2453 try argv.append(gpa, 0);
2454 }
2455
2456 if (args.libc_runtimes_dir) |libc_runtimes_dir| {
2457 try argv.append(gpa, @backingInt(Arg.prefix));
2458 try argv.appendSlice(gpa, "--libc-runtimes=");
2459 try argv.append(gpa, 0);
2460 try argv.append(gpa, @backingInt(Arg.input_dir));
2461 try argv.appendSlice(gpa, @ptrCast(&libc_runtimes_dir.handle));
2462 }
2463 if (args.enable_darling) {
2464 try argv.append(gpa, @backingInt(Arg.string));
2465 try argv.appendSlice(gpa, "-fdarling");
2466 try argv.append(gpa, 0);
2467 }
2468 if (args.enable_qemu) {
2469 try argv.append(gpa, @backingInt(Arg.string));
2470 try argv.appendSlice(gpa, "-fqemu");
2471 try argv.append(gpa, 0);
2472 }
2473 if (args.enable_rosetta) {
2474 try argv.append(gpa, @backingInt(Arg.string));
2475 try argv.appendSlice(gpa, "-frosetta");
2476 try argv.append(gpa, 0);
2477 }
2478 if (args.enable_wine) {
2479 try argv.append(gpa, @backingInt(Arg.string));
2480 try argv.appendSlice(gpa, "-fwine");
2481 try argv.append(gpa, 0);
2482 }
2483 if (args.enable_wasmtime) {
2484 try argv.append(gpa, @backingInt(Arg.string));
2485 try argv.appendSlice(gpa, "-fwasmtime");
2486 try argv.append(gpa, 0);
2487 }
2488
2489 if (args.gdb_exe) |gdb_exe| {
2490 try argv.append(gpa, @backingInt(Arg.prefix));
2491 try argv.appendSlice(gpa, "--gdb=");
2492 try argv.append(gpa, 0);
2493 try argv.append(gpa, @backingInt(Arg.input_file));
2494 try argv.appendSlice(gpa, @ptrCast(&gdb_exe.handle));
2495 }
2496 if (args.lldb_exe) |lldb_exe| {
2497 try argv.append(gpa, @backingInt(Arg.prefix));
2498 try argv.appendSlice(gpa, "--lldb=");
2499 try argv.append(gpa, 0);
2500 try argv.append(gpa, @backingInt(Arg.input_file));
2501 try argv.appendSlice(gpa, @ptrCast(&lldb_exe.handle));
2502 }
2503
2504 if (args.quiet) {
2505 try argv.append(gpa, @backingInt(Arg.string));
2506 try argv.appendSlice(gpa, "--quiet");
2507 try argv.append(gpa, 0);
2508 }
2509
2510 try client.serveMessageHeader(.{
2511 .tag = .args,
2512 .bytes_len = @intCast(argv.items.len),
2513 });
2514 try client.out.writeAll(argv.items);
2515
2516 var success = true;
2517 var metadata: struct {
2518 index: u32,
2519 len: u32,
2520 names: []u32,
2521 expected_panic_msgs: []u32,
2522 string_bytes: []u8,
2523
2524 fn name(m: *@This()) []const u8 {
2525 return std.mem.sliceTo(m.string_bytes[m.names[m.index - 1]..], 0);
2526 }
2527
2528 fn expectedPanicMsg(m: *@This()) ?[:0]const u8 {
2529 return switch (m.expected_panic_msgs[m.index - 1]) {
2530 0 => null,
2531 else => |offset| m.string_bytes[offset..std.mem.findScalarPos(
2532 u8,
2533 m.string_bytes,
2534 offset,
2535 0,
2536 ).? :0],
2537 };
2538 }
2539
2540 fn next(m: *@This()) ?u32 {
2541 if (m.len - m.index == 0) return null;
2542 defer m.index += 1;
2543 return m.index;
2544 }
2545 } = .{ .index = 0, .len = 0, .names = &.{}, .expected_panic_msgs = &.{}, .string_bytes = &.{} };
2546 try client.serveBodylessMessage(.query_test_metadata);
2547 while (true) {
2548 const hdr = try client.receiveMessage();
2549 switch (hdr.tag) {
2550 else => try client.in.discardAll(hdr.bytes_len),
2551 .zig_version => {
2552 const actual_version = try client.in.take(hdr.bytes_len);
2553 if (!std.mem.eql(u8, builtin.zig_version_string, actual_version)) {
2554 try stderr.print(
2555 "error: zig version mismatch compiler test runner vs compiler: {q} vs {q}\n",
2556 .{ builtin.zig_version_string, actual_version },
2557 );
2558 try stderr.flush();
2559 std.process.exit(1);
2560 }
2561 },
2562 .error_bundle => {
2563 const body = try arena.alloc(u8, hdr.bytes_len);
2564 try client.in.readSliceAll(body);
2565 const eb = std.zig.Server.allocErrorBundle(arena, body) catch |err| switch (err) {
2566 error.OutOfMemory => |e| return e,
2567 error.EndOfStream => {
2568 try stderr.writeAll("error bundle truncated\n");
2569 try stderr.flush();
2570 std.process.exit(1);
2571 },
2572 };
2573 success = false;
2574 eb.renderToStderr(io, .{}, .auto) catch {};
2575 },
2576 .test_metadata => {
2577 const tm_hdr =
2578 try client.in.takeStruct(std.zig.Server.Message.TestMetadata, .little);
2579 metadata = .{
2580 .index = 0,
2581 .len = tm_hdr.tests_len,
2582 .names = try arena.alloc(u32, tm_hdr.tests_len),
2583 .expected_panic_msgs = try arena.alloc(u32, tm_hdr.tests_len),
2584 .string_bytes = try arena.alloc(u8, tm_hdr.string_bytes_len),
2585 };
2586 try client.in.readSliceEndian(u32, metadata.names, .little);
2587 try client.in.readSliceEndian(u32, metadata.expected_panic_msgs, .little);
2588 try client.in.readSliceAll(metadata.string_bytes);
2589 try client.serveRunTest(metadata.next() orelse break);
2590 },
2591 .test_results => {
2592 const tr = try client.in.takeStruct(std.zig.Server.Message.TestResults, .little);
2593 switch (tr.flags.status) {
2594 .pass, .skip => {},
2595 .fail => success = false,
2596 }
2597 try stdout.print("[{t}] {s}\n", .{ tr.flags.status, metadata.name() });
2598 try stdout.flush();
2599 try client.serveRunTest(metadata.next() orelse break);
2600 },
2601 }
2602 }
2603 try client.serveBodylessMessage(.exit);
2604 return success;
2605}
test/behavior/slice.zig+18
...@@ -1209,3 +1209,21 @@ test "modify slice through coerced array pointer" {...@@ -1209,3 +1209,21 @@ test "modify slice through coerced array pointer" {
1209 assert(slice[2] == 0);1209 assert(slice[2] == 0);
1210 }1210 }
1211}1211}
1212
1213test "iterate empty slice of uninstantiable types" {
1214 const E = enum {};
1215 var slice_enum: []const E = undefined;
1216 slice_enum = &.{};
1217 for (slice_enum) |elem| {
1218 _ = elem;
1219 return error.ReachedUnreachable;
1220 }
1221
1222 const U = union { foo: struct { a: u8, b: noreturn }, bar: E };
1223 var slice_union: []const U = undefined;
1224 slice_union = &.{};
1225 for (slice_union) |elem| {
1226 _ = elem;
1227 return error.ReachedUnreachable;
1228 }
1229}
test/cases.zig+1-2
...@@ -9,7 +9,6 @@ pub const BuildOptions = struct {...@@ -9,7 +9,6 @@ pub const BuildOptions = struct {
9 llvm_has_xtensa: bool,9 llvm_has_xtensa: bool,
10};10};
1111
12pub fn addCases(cases: *Cases, build_options: BuildOptions, b: *std.Build) !void {12pub fn addCases(cases: *Cases, b: *std.Build) !void {
13 try @import("compile_errors.zig").addCases(cases, b);13 try @import("compile_errors.zig").addCases(cases, b);
14 try @import("llvm_targets.zig").addCases(cases, build_options, b);
15}14}
test/cases/compile_errors/load_uninstantiable_type.zig created+48
...@@ -0,0 +1,48 @@
1const E = enum {};
2const U = union {
3 foo: struct { a: u8, b: noreturn },
4 bar: E,
5};
6export fn loadSliceUninstantiableEnum() void {
7 const bytes: [32]u8 = @splat(0);
8 const ptr: *const [1]E = @ptrCast(&bytes);
9 const slice: []const E = ptr;
10 _ = comptime slice[0];
11 comptime unreachable;
12}
13export fn iterateSliceUninstantiableEnum() void {
14 const bytes: [32]u8 = @splat(0);
15 const ptr: *const [1]E = @ptrCast(&bytes);
16 const slice: []const E = ptr;
17 comptime for (slice) |elem| {
18 _ = elem;
19 };
20 comptime unreachable;
21}
22export fn loadSliceUninstantiableUnion() void {
23 const bytes: [32]u8 = @splat(0);
24 const ptr: *const [1]U = @ptrCast(&bytes);
25 const slice: []const U = ptr;
26 _ = comptime slice[0];
27 comptime unreachable;
28}
29export fn iterateSliceUninstantiableUnion() void {
30 const bytes: [32]u8 = @splat(0);
31 const ptr: *const [1]U = @ptrCast(&bytes);
32 const slice: []const U = ptr;
33 comptime for (slice) |elem| {
34 _ = elem;
35 };
36 comptime unreachable;
37}
38
39// error
40//
41// :10:23: error: cannot load uninstantiable type 'tmp.E'
42// :1:11: note: enum declared here
43// :17:19: error: cannot load uninstantiable type 'tmp.E'
44// :1:11: note: enum declared here
45// :26:23: error: cannot load uninstantiable type 'tmp.U'
46// :2:11: note: union declared here
47// :33:19: error: cannot load uninstantiable type 'tmp.U'
48// :2:11: note: union declared here
test/cases/safety/iterate_slice_uninstantiable_enum.zig created+21
...@@ -0,0 +1,21 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const E = enum {};
12pub fn main() error{TestFailed}!void {
13 const bytes: [32]u8 = @splat(0);
14 const ptr: *const [1]E = @ptrCast(&bytes);
15 const slice: []const E = ptr;
16 for (slice) |elem| _ = elem;
17 return error.TestFailed;
18}
19// run
20// backend=selfhosted,llvm
21// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/cases/safety/iterate_slice_uninstantiable_union.zig created+24
...@@ -0,0 +1,24 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const U = union {
12 foo: struct { a: u8, b: noreturn },
13 bar: enum {},
14};
15pub fn main() error{TestFailed}!void {
16 const bytes: [32]u8 = @splat(0);
17 const ptr: *const [1]U = @ptrCast(&bytes);
18 const slice: []const U = ptr;
19 for (slice) |elem| _ = elem;
20 return error.TestFailed;
21}
22// run
23// backend=selfhosted,llvm
24// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/cases/safety/load_slice_uninstantiable_enum.zig created+21
...@@ -0,0 +1,21 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const E = enum {};
12pub fn main() error{TestFailed}!void {
13 const bytes: [32]u8 = @splat(0);
14 const ptr: *const [1]E = @ptrCast(&bytes);
15 const slice: []const E = ptr;
16 _ = slice[0];
17 return error.TestFailed;
18}
19// run
20// backend=selfhosted,llvm
21// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/cases/safety/load_slice_uninstantiable_union.zig created+24
...@@ -0,0 +1,24 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const U = union {
12 foo: struct { a: u8, b: noreturn },
13 bar: enum {},
14};
15pub fn main() error{TestFailed}!void {
16 const bytes: [32]u8 = @splat(0);
17 const ptr: *const [1]U = @ptrCast(&bytes);
18 const slice: []const U = ptr;
19 _ = slice[0];
20 return error.TestFailed;
21}
22// run
23// backend=selfhosted,llvm
24// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/cases/safety/load_uninstantiable_enum_from_slice.zig deleted-21
...@@ -1,21 +0,0 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const E = enum {};
12pub fn main() error{TestFailed}!void {
13 const bytes: [32]u8 = @splat(0);
14 const ptr: *const [1]E = @ptrCast(&bytes);
15 const slice: []const E = ptr;
16 _ = slice[0];
17 return error.TestFailed;
18}
19// run
20// backend=selfhosted,llvm
21// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/cases/safety/load_uninstantiable_union.zig+1-1
...@@ -9,7 +9,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usi...@@ -9,7 +9,7 @@ pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usi
9}9}
1010
11const U = union {11const U = union {
12 foo: struct { a: u8, b: noreturn, },12 foo: struct { a: u8, b: noreturn },
13 bar: enum {},13 bar: enum {},
14};14};
15pub fn main() error{TestFailed}!void {15pub fn main() error{TestFailed}!void {
test/cases/safety/load_uninstantiable_union_from_slice.zig deleted-24
...@@ -1,24 +0,0 @@
1const std = @import("std");
2
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace, _: ?usize) noreturn {
4 _ = stack_trace;
5 if (std.mem.eql(u8, message, "attempt to load uninstantiable type")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
9}
10
11const U = union {
12 foo: struct { a: u8, b: noreturn, },
13 bar: enum {},
14};
15pub fn main() error{TestFailed}!void {
16 const bytes: [32]u8 = @splat(0);
17 const ptr: *const [1]U = @ptrCast(&bytes);
18 const slice: []const U = ptr;
19 _ = slice[0];
20 return error.TestFailed;
21}
22// run
23// backend=selfhosted,llvm
24// target=x86_64-linux,aarch64-linux,wasm32-wasi
test/debugger/basic/manifest+2-2
...@@ -3,6 +3,6 @@...@@ -3,6 +3,6 @@
3-Mroot=basic.zig3-Mroot=basic.zig
4#}4#}
55
6#write basic.zig basic.zig6#write basic.zig @basic.zig
7#update7#update
8#check lldb lldb8#check lldb @lldb
test/debugger/enums+5-7
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1#todo {1#todo "passes, but prints errors"
2passes, but prints errors2#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic
3#}3#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic
4#skip x86_64-linux-none-whole-selfhosted-new-nopic4#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic
5#skip x86_64-linux-none-whole-selfhosted-new-pic5#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic
6#skip x86_64-linux-none-incremental-selfhosted-new-nopic
7#skip x86_64-linux-none-incremental-selfhosted-new-pic
86
9#exe {7#exe {
10--name enums8--name enums
test/debugger/errors+5-7
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1#todo {1#todo "passes, but prints errors"
2passes, but prints errors2#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic
3#}3#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic
4#skip x86_64-linux-none-whole-selfhosted-new-nopic4#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic
5#skip x86_64-linux-none-whole-selfhosted-new-pic5#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic
6#skip x86_64-linux-none-incremental-selfhosted-new-nopic
7#skip x86_64-linux-none-incremental-selfhosted-new-pic
86
9#exe {7#exe {
10--name errors8--name errors
test/debugger/inline_call/manifest+8-10
...@@ -1,8 +1,6 @@...@@ -1,8 +1,6 @@
1#todo {1#todo "implement inline line info in lldb"
2implement inline line info in lldb2#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic
3#}3#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic
4#skip x86_64-linux-none-incremental-selfhosted-new-nopic
5#skip x86_64-linux-none-incremental-selfhosted-new-pic
64
7#exe {5#exe {
8--name inline_call6--name inline_call
...@@ -10,9 +8,9 @@ implement inline line info in lldb...@@ -10,9 +8,9 @@ implement inline line info in lldb
10-Mmodule=mod0.zig8-Mmodule=mod0.zig
11#}9#}
1210
13#write root0.zig root0.zig11#write root0.zig @root0.zig
14#write root1.zig root1.zig12#write root1.zig @root1.zig
15#write mod0.zig mod0.zig13#write mod0.zig @mod0.zig
16#write mod1.zig mod1.zig14#write mod1.zig @mod1.zig
17#update15#update
18#check lldb lldb16#check lldb @lldb
test/debugger/matrix.zon created+56
...@@ -0,0 +1,56 @@
1.{
2 .{
3 .cpu = .{ .x86_64 = .{} },
4 .os = .{ .linux = .{} },
5 .abi = .{ .none = .{} },
6 .cache_mode = .whole,
7 .backend = .selfhosted,
8 .linker = .old,
9 .pic = .nopic,
10 },
11 .{
12 .cpu = .{ .x86_64 = .{} },
13 .os = .{ .linux = .{} },
14 .abi = .{ .none = .{} },
15 .cache_mode = .whole,
16 .backend = .selfhosted,
17 .linker = .old,
18 .pic = .pic,
19 },
20 .{
21 .cpu = .{ .x86_64 = .{} },
22 .os = .{ .linux = .{} },
23 .abi = .{ .none = .{} },
24 .cache_mode = .whole,
25 .backend = .selfhosted,
26 .linker = .new,
27 .pic = .nopic,
28 },
29 .{
30 .cpu = .{ .x86_64 = .{} },
31 .os = .{ .linux = .{} },
32 .abi = .{ .none = .{} },
33 .cache_mode = .whole,
34 .backend = .selfhosted,
35 .linker = .new,
36 .pic = .pic,
37 },
38 .{
39 .cpu = .{ .x86_64 = .{} },
40 .os = .{ .linux = .{} },
41 .abi = .{ .none = .{} },
42 .cache_mode = .incremental,
43 .backend = .selfhosted,
44 .linker = .new,
45 .pic = .nopic,
46 },
47 .{
48 .cpu = .{ .x86_64 = .{} },
49 .os = .{ .linux = .{} },
50 .abi = .{ .none = .{} },
51 .cache_mode = .incremental,
52 .backend = .selfhosted,
53 .linker = .new,
54 .pic = .pic,
55 },
56}
test/debugger/multi_array_list/manifest+2-2
...@@ -3,6 +3,6 @@...@@ -3,6 +3,6 @@
3-Mroot=main.zig3-Mroot=main.zig
4#}4#}
55
6#write main.zig main.zig6#write main.zig @main.zig
7#update7#update
8#check lldb lldb8#check lldb @lldb
test/debugger/step_single_stmt_loops/manifest+2-2
...@@ -3,6 +3,6 @@...@@ -3,6 +3,6 @@
3-Mroot=step_single_stmt_loops.zig3-Mroot=step_single_stmt_loops.zig
4#}4#}
55
6#write step_single_stmt_loops.zig step_single_stmt_loops.zig6#write step_single_stmt_loops.zig @step_single_stmt_loops.zig
7#update7#update
8#check lldb lldb8#check lldb @lldb
test/debugger/unions+5-7
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1#todo {1#todo "passes, but prints errors"
2passes, but prints errors2#skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic
3#}3#skip x86_64-linux-none-baseline-whole-selfhosted-new-pic
4#skip x86_64-linux-none-whole-selfhosted-new-nopic4#skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic
5#skip x86_64-linux-none-whole-selfhosted-new-pic5#skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic
6#skip x86_64-linux-none-incremental-selfhosted-new-nopic
7#skip x86_64-linux-none-incremental-selfhosted-new-pic
86
9#exe {7#exe {
10--name unions8--name unions
test/incremental/add_decl+5-10
...@@ -24,8 +24,7 @@ const foo = "good morning\n";...@@ -24,8 +24,7 @@ const foo = "good morning\n";
24const bar = "good evening\n";24const bar = "good evening\n";
25const io = std.Io.Threaded.global_single_threaded.io();25const io = std.Io.Threaded.global_single_threaded.io();
26#}26#}
27#update {27#update "add new declaration"
28add new declaration#}
29#check stdout {28#check stdout {
30good morning29good morning
31#}30#}
...@@ -39,8 +38,7 @@ const foo = "good morning\n";...@@ -39,8 +38,7 @@ const foo = "good morning\n";
39const bar = "good evening\n";38const bar = "good evening\n";
40const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
41#}40#}
42#update {41#update "reference new declaration"
43reference new declaration#}
44#check stdout {42#check stdout {
45good evening43good evening
46#}44#}
...@@ -54,8 +52,7 @@ const foo = "good morning\n";...@@ -54,8 +52,7 @@ const foo = "good morning\n";
54const bar = "good evening\n";52const bar = "good evening\n";
55const io = std.Io.Threaded.global_single_threaded.io();53const io = std.Io.Threaded.global_single_threaded.io();
56#}54#}
57#update {55#update "reference missing declaration"
58reference missing declaration#}
59#check errors {56#check errors {
60main.zig:3:52: error: use of undeclared identifier 'qux'57main.zig:3:52: error: use of undeclared identifier 'qux'
61#}58#}
...@@ -70,8 +67,7 @@ const bar = "good evening\n";...@@ -70,8 +67,7 @@ const bar = "good evening\n";
70const qux = "good night\n";67const qux = "good night\n";
71const io = std.Io.Threaded.global_single_threaded.io();68const io = std.Io.Threaded.global_single_threaded.io();
72#}69#}
73#update {70#update "add missing declaration"
74add missing declaration#}
75#check stdout {71#check stdout {
76good night72good night
77#}73#}
...@@ -84,8 +80,7 @@ pub fn main() !void {...@@ -84,8 +80,7 @@ pub fn main() !void {
84const qux = "good night\n";80const qux = "good night\n";
85const io = std.Io.Threaded.global_single_threaded.io();81const io = std.Io.Threaded.global_single_threaded.io();
86#}82#}
87#update {83#update "remove unused declarations"
88remove unused declarations#}
89#check stdout {84#check stdout {
90good night85good night
91#}86#}
test/incremental/add_decl_namespaced+5-10
...@@ -24,8 +24,7 @@ const foo = "good morning\n";...@@ -24,8 +24,7 @@ const foo = "good morning\n";
24const bar = "good evening\n";24const bar = "good evening\n";
25const io = std.Io.Threaded.global_single_threaded.io();25const io = std.Io.Threaded.global_single_threaded.io();
26#}26#}
27#update {27#update "add new declaration"
28add new declaration#}
29#check stdout {28#check stdout {
30good morning29good morning
31#}30#}
...@@ -39,8 +38,7 @@ const foo = "good morning\n";...@@ -39,8 +38,7 @@ const foo = "good morning\n";
39const bar = "good evening\n";38const bar = "good evening\n";
40const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
41#}40#}
42#update {41#update "reference new declaration"
43reference new declaration#}
44#check stdout {42#check stdout {
45good evening43good evening
46#}44#}
...@@ -54,8 +52,7 @@ const foo = "good morning\n";...@@ -54,8 +52,7 @@ const foo = "good morning\n";
54const bar = "good evening\n";52const bar = "good evening\n";
55const io = std.Io.Threaded.global_single_threaded.io();53const io = std.Io.Threaded.global_single_threaded.io();
56#}54#}
57#update {55#update "reference missing declaration"
58reference missing declaration#}
59#check errors {56#check errors {
60main.zig:3:59: error: root source file struct 'main' has no member named 'qux'57main.zig:3:59: error: root source file struct 'main' has no member named 'qux'
61main.zig:1:1: note: struct declared here58main.zig:1:1: note: struct declared here
...@@ -71,8 +68,7 @@ const bar = "good evening\n";...@@ -71,8 +68,7 @@ const bar = "good evening\n";
71const qux = "good night\n";68const qux = "good night\n";
72const io = std.Io.Threaded.global_single_threaded.io();69const io = std.Io.Threaded.global_single_threaded.io();
73#}70#}
74#update {71#update "add missing declaration"
75add missing declaration#}
76#check stdout {72#check stdout {
77good night73good night
78#}74#}
...@@ -85,8 +81,7 @@ pub fn main() !void {...@@ -85,8 +81,7 @@ pub fn main() !void {
85const qux = "good night\n";81const qux = "good night\n";
86const io = std.Io.Threaded.global_single_threaded.io();82const io = std.Io.Threaded.global_single_threaded.io();
87#}83#}
88#update {84#update "remove unused declarations"
89remove unused declarations#}
90#check stdout {85#check stdout {
91good night86good night
92#}87#}
test/incremental/add_decls_around_bad_field_expr+1-2
...@@ -32,8 +32,7 @@ pub fn main() void {...@@ -32,8 +32,7 @@ pub fn main() void {
32 _ = @as(@This(), undefined);32 _ = @as(@This(), undefined);
33}33}
34#}34#}
35#update {35#update "add more decls around error"
36add more decls around error#}
37#check errors {36#check errors {
38main.zig:4:15: error: root source file struct 'main' has no member named 'does_not_exist'37main.zig:4:15: error: root source file struct 'main' has no member named 'does_not_exist'
39main.zig:1:1: note: struct declared here38main.zig:1:1: note: struct declared here
test/incremental/add_field_and_nested_struct_uses_changed_decl+3-6
...@@ -14,8 +14,7 @@ const S = struct {...@@ -14,8 +14,7 @@ const S = struct {
14};14};
15#}15#}
16#update16#update
17#check stdout {17#check stdout
18#}
1918
20#write main.zig {19#write main.zig {
21pub fn main() void {20pub fn main() void {
...@@ -29,7 +28,5 @@ const S = struct {...@@ -29,7 +28,5 @@ const S = struct {
29 bar: u32,28 bar: u32,
30};29};
31#}30#}
32#update {31#update "add field to outer struct, change decl used by inner struct"
33add field to outer struct, change decl used by inner struct#}32#check stdout
34#check stdout {
35#}
test/incremental/add_remove_struct_fields/manifest+7-10
...@@ -2,30 +2,27 @@...@@ -2,30 +2,27 @@
2-Mroot=main.zig2-Mroot=main.zig
3#}3#}
44
5#write main.zig 0/main.zig5#write main.zig @0/main.zig
6#update6#update
7#check stdout {7#check stdout {
81 10081 100
9#}9#}
1010
11#write main.zig 1/main.zig11#write main.zig @1/main.zig
12#update {12#update "add a field"
13add a field#}
14#check stdout {13#check stdout {
152 100142 100
16#}15#}
1716
18#write main.zig 2/main.zig17#write main.zig @2/main.zig
19#update {18#update "remove all fields"
20remove all fields#}
21#check errors {19#check errors {
22main.zig:15:24: error: no field named 'x' in struct 'main.S'20main.zig:15:24: error: no field named 'x' in struct 'main.S'
23main.zig:1:11: note: struct declared here21main.zig:1:11: note: struct declared here
24#}22#}
2523
26#write main.zig 3/main.zig24#write main.zig @3/main.zig
27#update {25#update "remove reference to non-existent field"
28remove reference to non-existent field#}
29#check stdout {26#check stdout {
300 <no fields>270 <no fields>
31#}28#}
test/incremental/add_remove_toplevel_fields/manifest+7-10
...@@ -2,30 +2,27 @@...@@ -2,30 +2,27 @@
2-Mroot=main.zig2-Mroot=main.zig
3#}3#}
44
5#write main.zig 0/main.zig5#write main.zig @0/main.zig
6#update6#update
7#check stdout {7#check stdout {
81 10081 100
9#}9#}
1010
11#write main.zig 1/main.zig11#write main.zig @1/main.zig
12#update {12#update "add a field"
13add a field#}
14#check stdout {13#check stdout {
152 100142 100
16#}15#}
1716
18#write main.zig 2/main.zig17#write main.zig @2/main.zig
19#update {18#update "remove all fields"
20remove all fields#}
21#check errors {19#check errors {
22main.zig:15:24: error: no field named 'x' in struct 'main'20main.zig:15:24: error: no field named 'x' in struct 'main'
23main.zig:1:1: note: struct declared here21main.zig:1:1: note: struct declared here
24#}22#}
2523
26#write main.zig 3/main.zig24#write main.zig @3/main.zig
27#update {25#update "remove reference to non-existent field"
28remove reference to non-existent field#}
29#check stdout {26#check stdout {
300 <no fields>270 <no fields>
31#}28#}
test/incremental/analysis_error_and_syntax_error+6-12
...@@ -16,8 +16,7 @@ main.zig:2:5: error: uh oh...@@ -16,8 +16,7 @@ main.zig:2:5: error: uh oh
16pub fn main() !void {16pub fn main() !void {
17 @compileError("uh oh");17 @compileError("uh oh");
18#}18#}
19#update {19#update "add parse error"
20add parse error#}
21#check errors {20#check errors {
22main.zig:3:1: error: expected statement, found 'EOF'21main.zig:3:1: error: expected statement, found 'EOF'
23#}22#}
...@@ -27,8 +26,7 @@ pub fn main() !void {...@@ -27,8 +26,7 @@ pub fn main() !void {
27 @compileError("uh oh");26 @compileError("uh oh");
28}27}
29#}28#}
30#update {29#update "fix parse error"
31fix parse error#}
32#check errors {30#check errors {
33main.zig:2:5: error: uh oh31main.zig:2:5: error: uh oh
34#}32#}
...@@ -37,8 +35,7 @@ main.zig:2:5: error: uh oh...@@ -37,8 +35,7 @@ main.zig:2:5: error: uh oh
37pub fn main() !void {35pub fn main() !void {
38 @compileError("uh oh");36 @compileError("uh oh");
39#}37#}
40#update {38#update "add parse error again"
41add parse error again#}
42#check errors {39#check errors {
43main.zig:3:1: error: expected statement, found 'EOF'40main.zig:3:1: error: expected statement, found 'EOF'
44#}41#}
...@@ -47,8 +44,7 @@ main.zig:3:1: error: expected statement, found 'EOF'...@@ -47,8 +44,7 @@ main.zig:3:1: error: expected statement, found 'EOF'
47pub fn main() !void {44pub fn main() !void {
48 //@compileError("uh oh");45 //@compileError("uh oh");
49#}46#}
50#update {47#update "comment @compileError call"
51comment @compileError call#}
52#check errors {48#check errors {
53main.zig:3:1: error: expected statement, found 'EOF'49main.zig:3:1: error: expected statement, found 'EOF'
54#}50#}
...@@ -58,7 +54,5 @@ pub fn main() !void {...@@ -58,7 +54,5 @@ pub fn main() !void {
58 //@compileError("uh oh");54 //@compileError("uh oh");
59}55}
60#}56#}
61#update {57#update "fix parse error again"
62fix parse error again#}58#check stdout
63#check stdout {
64#}
test/incremental/bad_import+2-4
...@@ -26,8 +26,7 @@ comptime {...@@ -26,8 +26,7 @@ comptime {
26 _ = @import("this_is/not_real.zig");26 _ = @import("this_is/not_real.zig");
27}27}
28#}28#}
29#update {29#update "change bad import"
30change bad import#}
31#check errors {30#check errors {
32this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound31this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
33foo.zig:2:17: note: file imported here32foo.zig:2:17: note: file imported here
...@@ -41,8 +40,7 @@ pub fn main() !void {...@@ -41,8 +40,7 @@ pub fn main() !void {
41const std = @import("std");40const std = @import("std");
42const io = std.Io.Threaded.global_single_threaded.io();41const io = std.Io.Threaded.global_single_threaded.io();
43#}42#}
44#update {43#update "remove import of 'foo.zig'"
45remove import of 'foo.zig'#}
46#check stdout {44#check stdout {
47success45success
48#}46#}
test/incremental/change_bitpack_backing_int+3-6
...@@ -38,8 +38,7 @@ comptime {...@@ -38,8 +38,7 @@ comptime {
38const std = @import("std");38const std = @import("std");
39const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
40#}40#}
41#update {41#update "make backing types signed"
42make backing types signed#}
43#check errors {42#check errors {
44main.zig:5:5: error: found compile log statement43main.zig:5:5: error: found compile log statement
45main.zig:8:5: note: also here44main.zig:8:5: note: also here
...@@ -62,8 +61,7 @@ comptime {...@@ -62,8 +61,7 @@ comptime {
62const std = @import("std");61const std = @import("std");
63const io = std.Io.Threaded.global_single_threaded.io();62const io = std.Io.Threaded.global_single_threaded.io();
64#}63#}
65#update {64#update "make backing types too small"
66make backing types too small#}
67#check errors {65#check errors {
68main.zig:1:20: error: backing integer bit width does not match total bit width of fields66main.zig:1:20: error: backing integer bit width does not match total bit width of fields
69main.zig:1:27: note: backing integer 'i5' has bit width '5'67main.zig:1:27: note: backing integer 'i5' has bit width '5'
...@@ -87,8 +85,7 @@ comptime {...@@ -87,8 +85,7 @@ comptime {
87const std = @import("std");85const std = @import("std");
88const io = std.Io.Threaded.global_single_threaded.io();86const io = std.Io.Threaded.global_single_threaded.io();
89#}87#}
90#update {88#update "make backing types too big"
91make backing types too big#}
92#check errors {89#check errors {
93main.zig:1:20: error: backing integer bit width does not match total bit width of fields90main.zig:1:20: error: backing integer bit width does not match total bit width of fields
94main.zig:1:27: note: backing integer 'u10' has bit width '10'91main.zig:1:27: note: backing integer 'u10' has bit width '10'
test/incremental/change_container_kind+8-16
...@@ -12,8 +12,7 @@ pub fn main() void {...@@ -12,8 +12,7 @@ pub fn main() void {
12#write foo.zig {12#write foo.zig {
13pub const T = struct { x: u8 };13pub const T = struct { x: u8 };
14#}14#}
15#update {15#update "T is struct"
16T is struct#}
17#check errors {16#check errors {
18main.zig:3:5: error: found compile log statement17main.zig:3:5: error: found compile log statement
1918
...@@ -25,8 +24,7 @@ Compile Log Output:...@@ -25,8 +24,7 @@ Compile Log Output:
25#write foo.zig {24#write foo.zig {
26pub const T = union {};25pub const T = union {};
27#}26#}
28#update {27#update "T is union"
29T is union#}
30#check errors {28#check errors {
31main.zig:3:5: error: found compile log statement29main.zig:3:5: error: found compile log statement
3230
...@@ -38,8 +36,7 @@ Compile Log Output:...@@ -38,8 +36,7 @@ Compile Log Output:
38#write foo.zig {36#write foo.zig {
39pub const T = enum {};37pub const T = enum {};
40#}38#}
41#update {39#update "T is enum"
42T is enum#}
43#check errors {40#check errors {
44main.zig:3:5: error: found compile log statement41main.zig:3:5: error: found compile log statement
4542
...@@ -51,8 +48,7 @@ Compile Log Output:...@@ -51,8 +48,7 @@ Compile Log Output:
51#write foo.zig {48#write foo.zig {
52pub const T = opaque {};49pub const T = opaque {};
53#}50#}
54#update {51#update "T is opaque"
55T is opaque#}
56#check errors {52#check errors {
57main.zig:3:5: error: found compile log statement53main.zig:3:5: error: found compile log statement
5854
...@@ -64,8 +60,7 @@ Compile Log Output:...@@ -64,8 +60,7 @@ Compile Log Output:
64#write foo.zig {60#write foo.zig {
65pub const T = packed struct {};61pub const T = packed struct {};
66#}62#}
67#update {63#update "T is packed struct"
68T is packed struct#}
69#check errors {64#check errors {
70main.zig:3:5: error: found compile log statement65main.zig:3:5: error: found compile log statement
7166
...@@ -77,8 +72,7 @@ Compile Log Output:...@@ -77,8 +72,7 @@ Compile Log Output:
77#write foo.zig {72#write foo.zig {
78pub const T = packed union { x: void }; // packed unions need at least 1 field73pub const T = packed union { x: void }; // packed unions need at least 1 field
79#}74#}
80#update {75#update "T is packed union"
81T is packed union#}
82#check errors {76#check errors {
83main.zig:3:5: error: found compile log statement77main.zig:3:5: error: found compile log statement
8478
...@@ -90,8 +84,7 @@ Compile Log Output:...@@ -90,8 +84,7 @@ Compile Log Output:
90#write foo.zig {84#write foo.zig {
91pub const T = extern struct {};85pub const T = extern struct {};
92#}86#}
93#update {87#update "T is extern struct"
94T is extern struct#}
95#check errors {88#check errors {
96main.zig:3:5: error: found compile log statement89main.zig:3:5: error: found compile log statement
9790
...@@ -103,8 +96,7 @@ Compile Log Output:...@@ -103,8 +96,7 @@ Compile Log Output:
103#write foo.zig {96#write foo.zig {
104pub const T = extern union { x: void }; // extern unions need at least 1 field97pub const T = extern union { x: void }; // extern unions need at least 1 field
105#}98#}
106#update {99#update "T is extern union"
107T is extern union#}
108#check errors {100#check errors {
109main.zig:3:5: error: found compile log statement101main.zig:3:5: error: found compile log statement
110102
test/incremental/change_embed_file+5-10
...@@ -21,15 +21,13 @@ Hello, World!...@@ -21,15 +21,13 @@ Hello, World!
21#write string.txt {21#write string.txt {
22Hello again, World!22Hello again, World!
23#}23#}
24#update {24#update "change file contents"
25change file contents#}
26#check stdout {25#check stdout {
27Hello again, World!26Hello again, World!
28#}27#}
2928
30#delete string.txt29#delete string.txt
31#update {30#update "delete file"
32delete file#}
33#check errors {31#check errors {
34main.zig:2:27: error: failed opening "string.txt": FileNotFound32main.zig:2:27: error: failed opening "string.txt": FileNotFound
35#}33#}
...@@ -42,8 +40,7 @@ pub fn main() !void {...@@ -42,8 +40,7 @@ pub fn main() !void {
42}40}
43const io = std.Io.Threaded.global_single_threaded.io();41const io = std.Io.Threaded.global_single_threaded.io();
44#}42#}
45#update {43#update "remove reference to file"
46remove reference to file#}
47#check stdout {44#check stdout {
48a hardcoded string45a hardcoded string
49#}46#}
...@@ -56,8 +53,7 @@ pub fn main() !void {...@@ -56,8 +53,7 @@ pub fn main() !void {
56}53}
57const io = std.Io.Threaded.global_single_threaded.io();54const io = std.Io.Threaded.global_single_threaded.io();
58#}55#}
59#update {56#update "re-introduce reference to file"
60re-introduce reference to file#}
61#check errors {57#check errors {
62main.zig:2:27: error: failed opening "string.txt": FileNotFound58main.zig:2:27: error: failed opening "string.txt": FileNotFound
63#}59#}
...@@ -65,8 +61,7 @@ main.zig:2:27: error: failed opening "string.txt": FileNotFound...@@ -65,8 +61,7 @@ main.zig:2:27: error: failed opening "string.txt": FileNotFound
65#write string.txt {61#write string.txt {
66We're back, World!62We're back, World!
67#}63#}
68#update {64#update "recreate file"
69recreate file#}
70#check stdout {65#check stdout {
71We're back, World!66We're back, World!
72#}67#}
test/incremental/change_enum_tag_type/manifest+9-13
...@@ -2,29 +2,26 @@...@@ -2,29 +2,26 @@
2-Mroot=main.zig2-Mroot=main.zig
3#}3#}
44
5#write main.zig 0/main.zig5#write main.zig @0/main.zig
6#update6#update
7#check stdout {7#check stdout {
8a8a
9#}9#}
1010
11#write main.zig 1/main.zig11#write main.zig @1/main.zig
12#update {12#update "too many enum fields"
13too many enum fields#}
14#check errors {13#check errors {
15main.zig:7:5: error: enum tag value '4' too large for type 'u2'14main.zig:7:5: error: enum tag value '4' too large for type 'u2'
16#}15#}
1716
18#write main.zig 2/main.zig17#write main.zig @2/main.zig
19#update {18#update "increase tag size"
20increase tag size#}
21#check stdout {19#check stdout {
22a20a
23#}21#}
2422
25#write main.zig 3/main.zig23#write main.zig @3/main.zig
26#update {24#update "specify tag directly"
27specify tag directly#}
28#check errors {25#check errors {
29main.zig:9:5: error: found compile log statement26main.zig:9:5: error: found compile log statement
3027
...@@ -32,9 +29,8 @@ Compile Log Output:...@@ -32,9 +29,8 @@ Compile Log Output:
32@as(type, u3)29@as(type, u3)
33#}30#}
3431
35#write main.zig 4/main.zig32#write main.zig @4/main.zig
36#update {33#update "change directly-specified tag type"
37change directly-specified tag type#}
38#check errors {34#check errors {
39main.zig:9:5: error: found compile log statement35main.zig:9:5: error: found compile log statement
4036
test/incremental/change_exports/manifest+14-21
...@@ -2,50 +2,43 @@...@@ -2,50 +2,43 @@
2-Mroot=main.zig2-Mroot=main.zig
3#}3#}
44
5#write main.zig 0/main.zig5#write main.zig @0/main.zig
6#update6#update
7#check stdout {7#check stdout {
81238123
9#}9#}
1010
11#write main.zig 1/main.zig11#write main.zig @1/main.zig
12#update {12#update "add conflict"
13add conflict#}
14#check errors {13#check errors {
15main.zig:6:5: error: exported symbol collision: foo14main.zig:6:5: error: exported symbol collision: foo
16main.zig:1:1: note: other symbol here15main.zig:1:1: note: other symbol here
17#}16#}
1817
19#write main.zig 2/main.zig18#write main.zig @2/main.zig
20#update {19#update "resolve conflict"
21resolve conflict#}
22#check stdout {20#check stdout {
23123 45621123 456
24#}22#}
2523
26#write main.zig 3/main.zig24#write main.zig @3/main.zig
27#update {25#update "put exports in decl"
28put exports in decl#}
29#check stdout {26#check stdout {
30123 45627123 456
31#}28#}
3229
33#write main.zig 4/main.zig30#write main.zig @4/main.zig
34#update {31#update "remove reference to exporting decl"
35remove reference to exporting decl#}32#check stdout
36#check stdout {
37#}
3833
39#write main.zig 5/main.zig34#write main.zig @5/main.zig
40#update {35#update "mark consts as export"
41mark consts as export#}
42#check stdout {36#check stdout {
43123 45637123 456
44#}38#}
4539
46#write main.zig 6/main.zig40#write main.zig @6/main.zig
47#update {41#update "reintroduce reference to exporting decl, introducing conflict"
48reintroduce reference to exporting decl, introducing conflict#}
49#check errors {42#check errors {
50main.zig:5:5: error: exported symbol collision: bar43main.zig:5:5: error: exported symbol collision: bar
51main.zig:2:1: note: other symbol here44main.zig:2:1: note: other symbol here
test/incremental/change_fn_type+2-4
...@@ -29,8 +29,7 @@ fn foo(x: i64) !void {...@@ -29,8 +29,7 @@ fn foo(x: i64) !void {
29const std = @import("std");29const std = @import("std");
30const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
31#}31#}
32#update {32#update "change function type"
33change function type#}
34#check stdout {33#check stdout {
3512334123
36#}35#}
...@@ -46,8 +45,7 @@ fn foo(x: i64) !void {...@@ -46,8 +45,7 @@ fn foo(x: i64) !void {
46const std = @import("std");45const std = @import("std");
47const io = std.Io.Threaded.global_single_threaded.io();46const io = std.Io.Threaded.global_single_threaded.io();
48#}47#}
49#update {48#update "change function argument"
50change function argument#}
51#check stdout {49#check stdout {
52-4250-42
53#}51#}
test/incremental/change_generic_line_number+1-2
...@@ -39,8 +39,7 @@ pub fn main() !void {...@@ -39,8 +39,7 @@ pub fn main() !void {
39 try Printer("bar\n").print();39 try Printer("bar\n").print();
40}40}
41#}41#}
42#update {42#update "change line number"
43change line number#}
44#check stdout {43#check stdout {
45foo44foo
46bar45bar
test/incremental/change_line_number+1-2
...@@ -22,8 +22,7 @@ pub fn main() !void {...@@ -22,8 +22,7 @@ pub fn main() !void {
22}22}
23const io = std.Io.Threaded.global_single_threaded.io();23const io = std.Io.Threaded.global_single_threaded.io();
24#}24#}
25#update {25#update "change line number"
26change line number#}
27#check stdout {26#check stdout {
28foo27foo
29#}28#}
test/incremental/change_module+4-8
...@@ -41,8 +41,7 @@ comptime {...@@ -41,8 +41,7 @@ comptime {
41 //_ = @import("other.zig");41 //_ = @import("other.zig");
42}42}
43#}43#}
44#update {44#update "change module of other.zig"
45change module of other.zig#}
46#check errors {45#check errors {
47other.zig:2:5: error: found compile log statement46other.zig:2:5: error: found compile log statement
4847
...@@ -61,8 +60,7 @@ comptime {...@@ -61,8 +60,7 @@ comptime {
61 _ = @import("other.zig");60 _ = @import("other.zig");
62}61}
63#}62#}
64#update {63#update "put other.zig in both modules"
65put other.zig in both modules#}
66#check errors {64#check errors {
67other.zig:1:1: error: file exists in modules 'root' and 'foo'65other.zig:1:1: error: file exists in modules 'root' and 'foo'
68other.zig:1:1: note: files must belong to only one module66other.zig:1:1: note: files must belong to only one module
...@@ -81,7 +79,5 @@ comptime {...@@ -81,7 +79,5 @@ comptime {
81 //_ = @import("other.zig");79 //_ = @import("other.zig");
82}80}
83#}81#}
84#update {82#update "put other.zig in no modules"
85put other.zig in no modules#}83#check stdout
86#check stdout {
87#}
test/incremental/change_panic_handler+2-4
...@@ -39,8 +39,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {...@@ -39,8 +39,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn {
39const std = @import("std");39const std = @import("std");
40const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
41#}41#}
42#update {42#update "change the panic handler body"
43change the panic handler body#}
44#check stdout {43#check stdout {
45new panic message: integer overflow44new panic message: integer overflow
46#}45#}
...@@ -61,8 +60,7 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {...@@ -61,8 +60,7 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn {
61const std = @import("std");60const std = @import("std");
62const io = std.Io.Threaded.global_single_threaded.io();61const io = std.Io.Threaded.global_single_threaded.io();
63#}62#}
64#update {63#update "change the panic handler function value"
65change the panic handler function value#}
66#check stdout {64#check stdout {
67third panic message: integer overflow65third panic message: integer overflow
68#}66#}
test/incremental/change_panic_handler_explicit/manifest+5-7
...@@ -2,22 +2,20 @@...@@ -2,22 +2,20 @@
2-Mroot=main.zig2-Mroot=main.zig
3#}3#}
44
5#write main.zig 0/main.zig5#write main.zig @0/main.zig
6#update6#update
7#check stdout {7#check stdout {
8panic message: integer overflow8panic message: integer overflow
9#}9#}
1010
11#write main.zig 1/main.zig11#write main.zig @1/main.zig
12#update {12#update "change the panic handler body"
13change the panic handler body#}
14#check stdout {13#check stdout {
15new panic message: integer overflow14new panic message: integer overflow
16#}15#}
1716
18#write main.zig 2/main.zig17#write main.zig @2/main.zig
19#update {18#update "change the panic handler function value"
20change the panic handler function value#}
21#check stdout {19#check stdout {
22third panic message: integer overflow20third panic message: integer overflow
23#}21#}
test/incremental/change_reify_struct_field_type+3-6
...@@ -13,8 +13,7 @@ const Enum = enum { foo, bar };...@@ -13,8 +13,7 @@ const Enum = enum { foo, bar };
13const std = @import("std");13const std = @import("std");
14#}14#}
15#update15#update
16#check stdout {16#check stdout "foo"
17foo#}
1817
19#write main.zig {18#write main.zig {
20fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {19fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum {
...@@ -26,7 +25,5 @@ pub fn main(init: std.process.Init) !void {...@@ -26,7 +25,5 @@ pub fn main(init: std.process.Init) !void {
26const Enum = enum { foo, bar };25const Enum = enum { foo, bar };
27const std = @import("std");26const std = @import("std");
28#}27#}
29#update {28#update "change field type"
30change field type#}29#check stdout "bar"
31#check stdout {
32bar#}
test/incremental/change_shift_op+1-2
...@@ -29,8 +29,7 @@ fn foo(x: u16) !void {...@@ -29,8 +29,7 @@ fn foo(x: u16) !void {
29const std = @import("std");29const std = @import("std");
30const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
31#}31#}
32#update {32#update "change to right shift"
33change to right shift#}
34#check stdout {33#check stdout {
350x130340x130
36#}35#}
test/incremental/change_struct_same_fields+2-4
...@@ -39,8 +39,7 @@ fn foo(val: *const S) !void {...@@ -39,8 +39,7 @@ fn foo(val: *const S) !void {
39const std = @import("std");39const std = @import("std");
40const io = std.Io.Threaded.global_single_threaded.io();40const io = std.Io.Threaded.global_single_threaded.io();
41#}41#}
42#update {42#update "change struct layout"
43change struct layout#}
44#check stdout {43#check stdout {
45100 20044100 200
46#}45#}
...@@ -61,8 +60,7 @@ fn foo(val: *const S) !void {...@@ -61,8 +60,7 @@ fn foo(val: *const S) !void {
61const std = @import("std");60const std = @import("std");
62const io = std.Io.Threaded.global_single_threaded.io();61const io = std.Io.Threaded.global_single_threaded.io();
63#}62#}
64#update {63#update "change values"
65change values#}
66#check stdout {64#check stdout {
671234 5678651234 5678
68#}66#}
test/incremental/change_union_tag_type+2-4
...@@ -29,8 +29,7 @@ pub fn main(init: std.process.Init) !void {...@@ -29,8 +29,7 @@ pub fn main(init: std.process.Init) !void {
29}29}
30const std = @import("std");30const std = @import("std");
31#}31#}
32#update {32#update "change tag type"
33change tag type#}
34#check errors {33#check errors {
35main.zig:3:24: error: no field named 'a' in enum 'main.B'34main.zig:3:24: error: no field named 'a' in enum 'main.B'
36main.zig:2:11: note: enum declared here35main.zig:2:11: note: enum declared here
...@@ -47,8 +46,7 @@ pub fn main(init: std.process.Init) !void {...@@ -47,8 +46,7 @@ pub fn main(init: std.process.Init) !void {
47}46}
48const std = @import("std");47const std = @import("std");
49#}48#}
50#update {49#update "change field name to match new tag type"
51change field name to match new tag type#}
52#check stdout {50#check stdout {
53b51b
54#}52#}
test/incremental/change_zon_file+5-10
...@@ -21,15 +21,13 @@ Hello, World!...@@ -21,15 +21,13 @@ Hello, World!
21#write message.zon {21#write message.zon {
22"Hello again, World!\n"22"Hello again, World!\n"
23#}23#}
24#update {24#update "change ZON file contents"
25change ZON file contents#}
26#check stdout {25#check stdout {
27Hello again, World!26Hello again, World!
28#}27#}
2928
30#delete message.zon29#delete message.zon
31#update {30#update "delete file"
32delete file#}
33#check errors {31#check errors {
34message.zon:1:1: error: unable to load "message.zon": FileNotFound32message.zon:1:1: error: unable to load "message.zon": FileNotFound
35main.zig:2:37: note: file imported here33main.zig:2:37: note: file imported here
...@@ -43,8 +41,7 @@ pub fn main() !void {...@@ -43,8 +41,7 @@ pub fn main() !void {
43}41}
44const io = std.Io.Threaded.global_single_threaded.io();42const io = std.Io.Threaded.global_single_threaded.io();
45#}43#}
46#update {44#update "remove reference to ZON file"
47remove reference to ZON file#}
48#check errors {45#check errors {
49message.zon:1:1: error: unable to load "message.zon": FileNotFound46message.zon:1:1: error: unable to load "message.zon": FileNotFound
50main.zig:2:37: note: file imported here47main.zig:2:37: note: file imported here
...@@ -53,8 +50,7 @@ main.zig:2:37: note: file imported here...@@ -53,8 +50,7 @@ main.zig:2:37: note: file imported here
53#write message.zon {50#write message.zon {
54"We're back, World!\n"51"We're back, World!\n"
55#}52#}
56#update {53#update "recreate ZON file"
57recreate ZON file#}
58#check stdout {54#check stdout {
59a hardcoded string55a hardcoded string
60#}56#}
...@@ -67,8 +63,7 @@ pub fn main() !void {...@@ -67,8 +63,7 @@ pub fn main() !void {
67}63}
68const io = std.Io.Threaded.global_single_threaded.io();64const io = std.Io.Threaded.global_single_threaded.io();
69#}65#}
70#update {66#update "re-introduce reference to ZON file"
71re-introduce reference to ZON file#}
72#check stdout {67#check stdout {
73We're back, World!68We're back, World!
74#}69#}
test/incremental/change_zon_file_no_result_type+1-2
...@@ -26,8 +26,7 @@ Hello, World!...@@ -26,8 +26,7 @@ Hello, World!
26 .b_number = 0,26 .b_number = 0,
27}27}
28#}28#}
29#update {29#update "change ZON file"
30change ZON file#}
31#check stdout {30#check stdout {
32Hello again, World!31Hello again, World!
33#}32#}
test/incremental/compile_error_then_log+2-4
...@@ -11,8 +11,7 @@ comptime {...@@ -11,8 +11,7 @@ comptime {
11 @compileLog("this is a log");11 @compileLog("this is a log");
12}12}
13#}13#}
14#update {14#update "compile error"
15compile error#}
16#check errors {15#check errors {
17main.zig:3:5: error: this is an error16main.zig:3:5: error: this is an error
1817
...@@ -29,8 +28,7 @@ comptime {...@@ -29,8 +28,7 @@ comptime {
29 @compileLog("this is a log");28 @compileLog("this is a log");
30}29}
31#}30#}
32#update {31#update "remove the compile error"
33remove the compile error#}
34#check errors {32#check errors {
35main.zig:6:5: error: found compile log statement33main.zig:6:5: error: found compile log statement
3634
test/incremental/compile_log+3-6
...@@ -9,8 +9,7 @@ pub fn main() !void {...@@ -9,8 +9,7 @@ pub fn main() !void {
9}9}
10const io = std.Io.Threaded.global_single_threaded.io();10const io = std.Io.Threaded.global_single_threaded.io();
11#}11#}
12#update {12#update "no compile log"
13no compile log#}
14#check stdout {13#check stdout {
15Hello, World!14Hello, World!
16#}15#}
...@@ -23,8 +22,7 @@ pub fn main() !void {...@@ -23,8 +22,7 @@ pub fn main() !void {
23}22}
24const io = std.Io.Threaded.global_single_threaded.io();23const io = std.Io.Threaded.global_single_threaded.io();
25#}24#}
26#update {25#update "add compile log"
27add compile log#}
28#check errors {26#check errors {
29main.zig:4:5: error: found compile log statement27main.zig:4:5: error: found compile log statement
3028
...@@ -39,8 +37,7 @@ pub fn main() !void {...@@ -39,8 +37,7 @@ pub fn main() !void {
39}37}
40const io = std.Io.Threaded.global_single_threaded.io();38const io = std.Io.Threaded.global_single_threaded.io();
41#}39#}
42#update {40#update "remove compile log"
43remove compile log#}
44#check stdout {41#check stdout {
45Hello, World!42Hello, World!
46#}43#}
test/incremental/delete_comptime_decls+1-2
...@@ -44,8 +44,7 @@ comptime {...@@ -44,8 +44,7 @@ comptime {
44 _ = y;44 _ = y;
45}45}
46#}46#}
47#update {47#update "delete and modify comptime decls"
48delete and modify comptime decls#}
49#check errors {48#check errors {
50main.zig:6:16: error: slice of null pointer49main.zig:6:16: error: slice of null pointer
51#}50#}
test/incremental/dependency_on_type_of_inferred_global+2-4
...@@ -15,8 +15,7 @@ comptime {...@@ -15,8 +15,7 @@ comptime {
15pub fn main() void {}15pub fn main() void {}
16#}16#}
17#update17#update
18#check stdout {18#check stdout
19#}
2019
21#write main.zig {20#write main.zig {
22const foo = @as(u16, 123);21const foo = @as(u16, 123);
...@@ -30,8 +29,7 @@ comptime {...@@ -30,8 +29,7 @@ comptime {
30}29}
31pub fn main() void {}30pub fn main() void {}
32#}31#}
33#update {32#update "change the type"
34change the type#}
35#check errors {33#check errors {
36main.zig:8:37: error: reached unreachable code34main.zig:8:37: error: reached unreachable code
37#}35#}
test/incremental/do_nothing+4-9
...@@ -1,6 +1,4 @@...@@ -1,6 +1,4 @@
1#todo {1#todo "it'd be great if we could actually check that no analysis happened!"
2it'd be great if we could actually check that no analysis happened!
3#}
4#exe {2#exe {
5-Mroot=main.zig3-Mroot=main.zig
6#}4#}
...@@ -25,8 +23,7 @@ const O = opaque {...@@ -25,8 +23,7 @@ const O = opaque {
25};23};
26#}24#}
27#update25#update
28#check stdout {26#check stdout
29#}
3027
31#write main.zig {28#write main.zig {
32pub fn main() void {29pub fn main() void {
...@@ -47,7 +44,5 @@ const O = opaque {...@@ -47,7 +44,5 @@ const O = opaque {
47 }44 }
48};45};
49#}46#}
50#update {47#update "do literally nothing"
51do literally nothing#}48#check stdout
52#check stdout {
53#}
test/incremental/fix_astgen_failure+4-8
...@@ -12,8 +12,7 @@ pub fn hello() !void {...@@ -12,8 +12,7 @@ pub fn hello() !void {
12 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");12 try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n");
13}13}
14#}14#}
15#update {15#update "error"
16error#}
17#check errors {16#check errors {
18foo.zig:2:9: error: use of undeclared identifier 'std'17foo.zig:2:9: error: use of undeclared identifier 'std'
19#}18#}
...@@ -25,8 +24,7 @@ pub fn hello() !void {...@@ -25,8 +24,7 @@ pub fn hello() !void {
25}24}
26const io = std.Io.Threaded.global_single_threaded.io();25const io = std.Io.Threaded.global_single_threaded.io();
27#}26#}
28#update {27#update "fix the error"
29fix the error#}
30#check stdout {28#check stdout {
31Hello, World!29Hello, World!
32#}30#}
...@@ -38,8 +36,7 @@ pub fn hello() !void {...@@ -38,8 +36,7 @@ pub fn hello() !void {
38}36}
39const io = std.Io.Threaded.global_single_threaded.io();37const io = std.Io.Threaded.global_single_threaded.io();
40#}38#}
41#update {39#update "add new error"
42add new error#}
43#check errors {40#check errors {
44foo.zig:3:52: error: use of undeclared identifier 'hello_str'41foo.zig:3:52: error: use of undeclared identifier 'hello_str'
45#}42#}
...@@ -52,8 +49,7 @@ pub fn hello() !void {...@@ -52,8 +49,7 @@ pub fn hello() !void {
52}49}
53const io = std.Io.Threaded.global_single_threaded.io();50const io = std.Io.Threaded.global_single_threaded.io();
54#}51#}
55#update {52#update "fix the new error"
56fix the new error#}
57#check stdout {53#check stdout {
58Hello, World! Again!54Hello, World! Again!
59#}55#}
test/incremental/function_becomes_inline+3-6
...@@ -12,8 +12,7 @@ fn foo() !void {...@@ -12,8 +12,7 @@ fn foo() !void {
12const std = @import("std");12const std = @import("std");
13const io = std.Io.Threaded.global_single_threaded.io();13const io = std.Io.Threaded.global_single_threaded.io();
14#}14#}
15#update {15#update "non-inline version"
16non-inline version#}
17#check stdout {16#check stdout {
18Hello, World!17Hello, World!
19#}18#}
...@@ -28,8 +27,7 @@ inline fn foo() !void {...@@ -28,8 +27,7 @@ inline fn foo() !void {
28const std = @import("std");27const std = @import("std");
29const io = std.Io.Threaded.global_single_threaded.io();28const io = std.Io.Threaded.global_single_threaded.io();
30#}29#}
31#update {30#update "make function inline"
32make function inline#}
33#check stdout {31#check stdout {
34Hello, World!32Hello, World!
35#}33#}
...@@ -44,8 +42,7 @@ inline fn foo() !void {...@@ -44,8 +42,7 @@ inline fn foo() !void {
44const std = @import("std");42const std = @import("std");
45const io = std.Io.Threaded.global_single_threaded.io();43const io = std.Io.Threaded.global_single_threaded.io();
46#}44#}
47#update {45#update "change string"
48change string#}
49#check stdout {46#check stdout {
50Hello, `inline` World!47Hello, `inline` World!
51#}48#}
test/incremental/hello+1-2
...@@ -21,8 +21,7 @@ pub fn main() !void {...@@ -21,8 +21,7 @@ pub fn main() !void {
21 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");21 try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n");
22}22}
23#}23#}
24#update {24#update "change the string"
25change the string#}
26#check stdout {25#check stdout {
27おはようございます26おはようございます
28#}27#}
test/incremental/increase_array_field_length+1-2
...@@ -35,8 +35,7 @@ pub fn main(init: std.process.Init) !void {...@@ -35,8 +35,7 @@ pub fn main(init: std.process.Init) !void {
35}35}
36const std = @import("std");36const std = @import("std");
37#}37#}
38#update {38#update "increase array length"
39increase array length#}
40#check stdout {39#check stdout {
41arr[999] = 23440arr[999] = 234
42#}41#}
test/incremental/make_decl_pub+1-2
...@@ -28,8 +28,7 @@ pub fn hello() !void {...@@ -28,8 +28,7 @@ pub fn hello() !void {
28}28}
29const io = std.Io.Threaded.global_single_threaded.io();29const io = std.Io.Threaded.global_single_threaded.io();
30#}30#}
31#update {31#update "make hello pub"
32make hello pub#}
33#check stdout {32#check stdout {
34Hello, World!33Hello, World!
35#}34#}
test/incremental/matrix.zon created+51
...@@ -0,0 +1,51 @@
1.{
2 // Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others
3 // to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang
4 // or LLVM). We just have a couple here to make sure that it works.
5 .{
6 .cpu = .{ .x86_64 = .{} },
7 .os = .{ .linux = .{} },
8 .abi = .{ .musl = .{} },
9 .cache_mode = .incremental,
10 .backend = .cbe,
11 .linker = .old,
12 .pic = .nopic,
13 },
14 .{
15 .cpu = .{ .x86_64 = .{} },
16 .os = .{ .linux = .{} },
17 .abi = .{ .none = .{} },
18 .cache_mode = .incremental,
19 .backend = .llvm,
20 .linker = .lld,
21 .pic = .nopic,
22 },
23
24 .{
25 .cpu = .{ .x86_64 = .{} },
26 .os = .{ .linux = .{} },
27 .abi = .{ .none = .{} },
28 .cache_mode = .incremental,
29 .backend = .selfhosted,
30 .linker = .new,
31 .pic = .nopic,
32 },
33 .{
34 .cpu = .{ .x86_64 = .{} },
35 .os = .{ .windows = .{} },
36 .abi = .{ .none = .{} },
37 .cache_mode = .incremental,
38 .backend = .selfhosted,
39 .linker = .old,
40 .pic = .pic,
41 },
42 .{
43 .cpu = .{ .wasm32 = .{} },
44 .os = .{ .wasi = .{} },
45 .abi = .{ .none = .{} },
46 .cache_mode = .incremental,
47 .backend = .selfhosted,
48 .linker = .old,
49 .pic = .nopic,
50 },
51}
test/incremental/modify_inline_fn+1-2
...@@ -29,8 +29,7 @@ inline fn getStr() []const u8 {...@@ -29,8 +29,7 @@ inline fn getStr() []const u8 {
29}29}
30const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
31#}31#}
32#update {32#update "change the string"
33change the string#}
34#check stdout {33#check stdout {
35bar34bar
36#}35#}
test/incremental/move_src+1-2
...@@ -36,8 +36,7 @@ fn bar() u32 {...@@ -36,8 +36,7 @@ fn bar() u32 {
36}36}
37const io = std.Io.Threaded.global_single_threaded.io();37const io = std.Io.Threaded.global_single_threaded.io();
38#}38#}
39#update {39#update "add newline"
40add newline#}
41#check stdout {40#check stdout {
428 123418 123
43#}42#}
test/incremental/pointer_to_decl_with_astgen_error+4-8
...@@ -9,8 +9,7 @@ pub fn main() void {...@@ -9,8 +9,7 @@ pub fn main() void {
9}9}
10#}10#}
11#update11#update
12#check stdout {12#check stdout
13#}
1413
15#write main.zig {14#write main.zig {
16const foo = something;15const foo = something;
...@@ -18,8 +17,7 @@ pub fn main() void {...@@ -18,8 +17,7 @@ pub fn main() void {
18 _ = &foo;17 _ = &foo;
19}18}
20#}19#}
21#update {20#update "introduce use of undeclared identifier"
22introduce use of undeclared identifier#}
23#check errors {21#check errors {
24main.zig:1:13: error: use of undeclared identifier 'something'22main.zig:1:13: error: use of undeclared identifier 'something'
25#}23#}
...@@ -30,7 +28,5 @@ pub fn main() void {...@@ -30,7 +28,5 @@ pub fn main() void {
30 _ = &foo;28 _ = &foo;
31}29}
32#}30#}
33#update {31#update "revert use of undeclared identifier"
34revert use of undeclared identifier#}32#check stdout
35#check stdout {
36#}
test/incremental/recursive_function_becomes_non_recursive+1-2
...@@ -31,8 +31,7 @@ fn foo(recurse: bool) !void {...@@ -31,8 +31,7 @@ fn foo(recurse: bool) !void {
31const std = @import("std");31const std = @import("std");
32const io = std.Io.Threaded.global_single_threaded.io();32const io = std.Io.Threaded.global_single_threaded.io();
33#}33#}
34#update {34#update "eliminate recursion and change argument"
35eliminate recursion and change argument#}
36#check stdout {35#check stdout {
37x==136x==1
38#}37#}
test/incremental/remove_enum_field+1-2
...@@ -31,8 +31,7 @@ pub fn main() !void {...@@ -31,8 +31,7 @@ pub fn main() !void {
31const std = @import("std");31const std = @import("std");
32const io = std.Io.Threaded.global_single_threaded.io();32const io = std.Io.Threaded.global_single_threaded.io();
33#}33#}
34#update {34#update "remove enum field"
35remove enum field#}
36#check errors {35#check errors {
37main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo'36main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo'
38main.zig:1:16: note: enum declared here37main.zig:1:16: note: enum declared here
test/incremental/remove_function_with_changed_callee+3-6
...@@ -28,8 +28,7 @@ pub fn main() !void {...@@ -28,8 +28,7 @@ pub fn main() !void {
28}28}
29#}29#}
30#update30#update
31#check stdout {31#check stdout "0"
320#}
3332
34#write main.zig {33#write main.zig {
35//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.34//! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type.
...@@ -54,7 +53,5 @@ pub fn main() !void {...@@ -54,7 +53,5 @@ pub fn main() !void {
54 try bar(.one);53 try bar(.one);
55}54}
56#}55#}
57#update {56#update "remove foo and change bar wasm function type"
58remove foo and change bar wasm function type#}57#check stdout "1"
59#check stdout {
601#}
test/incremental/remove_invalid_union_backing_enum+2-4
...@@ -33,7 +33,5 @@ pub fn main() void {...@@ -33,7 +33,5 @@ pub fn main() void {
33 _ = u;33 _ = u;
34}34}
35#}35#}
36#update {36#update "remove invalid backing enum"
37remove invalid backing enum#}37#check stdout
38#check stdout {
39#}
test/incremental/struct_reification_becomes_anon_init+1-2
...@@ -23,8 +23,7 @@ pub fn main(init: std.process.Init) !void {...@@ -23,8 +23,7 @@ pub fn main(init: std.process.Init) !void {
23}23}
24const std = @import("std");24const std = @import("std");
25#}25#}
26#update {26#update "change to `@TypeOf` anonymous init"
27change to `@TypeOf` anonymous init#}
28#check stdout {27#check stdout {
29anon_field28anon_field
30#}29#}
test/incremental/tag_name+5-10
...@@ -11,8 +11,7 @@ pub fn main() !void {...@@ -11,8 +11,7 @@ pub fn main() !void {
11}11}
12#}12#}
13#update13#update
14#check stdout {14#check stdout "first"
15first#}
1615
17#write main.zig {16#write main.zig {
18const std = @import("std");17const std = @import("std");
...@@ -22,10 +21,8 @@ pub fn main() !void {...@@ -22,10 +21,8 @@ pub fn main() !void {
22 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));21 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
23}22}
24#}23#}
25#update {24#update "no change"
26no change#}25#check stdout "first"
27#check stdout {
28first#}
2926
30#write main.zig {27#write main.zig {
31const std = @import("std");28const std = @import("std");
...@@ -35,7 +32,5 @@ pub fn main() !void {...@@ -35,7 +32,5 @@ pub fn main() !void {
35 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));32 try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum));
36}33}
37#}34#}
38#update {35#update "swap fields"
39swap fields#}36#check stdout "first"
40#check stdout {
41first#}
test/incremental/temporary_analysis_error_in_generic_signature+2-4
...@@ -33,8 +33,7 @@ fn bar(comptime x: u8) @This().FooAlias {...@@ -33,8 +33,7 @@ fn bar(comptime x: u8) @This().FooAlias {
33}33}
34const std = @import("std");34const std = @import("std");
35#}35#}
36#update {36#update "change generic signature to use non-existent member"
37change generic signature to use non-existent member#}
38#check errors {37#check errors {
39main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'38main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias'
40main.zig:1:1: note: struct declared here39main.zig:1:1: note: struct declared here
...@@ -54,8 +53,7 @@ fn bar(comptime x: u8) @This().FooAlias {...@@ -54,8 +53,7 @@ fn bar(comptime x: u8) @This().FooAlias {
54}53}
55const std = @import("std");54const std = @import("std");
56#}55#}
57#update {56#update "add that member, fixing the error"
58add that member, fixing the error#}
59#check stdout {57#check stdout {
60Z58Z
61#}59#}
test/incremental/temporary_parse_error+4-8
...@@ -7,14 +7,12 @@ const std = @import("std");...@@ -7,14 +7,12 @@ const std = @import("std");
7pub fn main() !void {}7pub fn main() !void {}
8#}8#}
9#update9#update
10#check stdout {10#check stdout
11#}
1211
13#write main.zig {12#write main.zig {
14pub fn main() !void {13pub fn main() !void {
15#}14#}
16#update {15#update "introduce parse error"
17introduce parse error#}
18#check errors {16#check errors {
19main.zig:2:1: error: expected statement, found 'EOF'17main.zig:2:1: error: expected statement, found 'EOF'
20#}18#}
...@@ -22,7 +20,5 @@ main.zig:2:1: error: expected statement, found 'EOF'...@@ -22,7 +20,5 @@ main.zig:2:1: error: expected statement, found 'EOF'
22#write main.zig {20#write main.zig {
23pub fn main() !void {}21pub fn main() !void {}
24#}22#}
25#update {23#update "fix parse error"
26fix parse error#}24#check stdout
27#check stdout {
28#}
test/incremental/type_becomes_comptime_only+5-10
...@@ -14,8 +14,7 @@ pub fn main() void {...@@ -14,8 +14,7 @@ pub fn main() void {
14}14}
15#}15#}
16#update16#update
17#check stdout {17#check stdout
18#}
1918
20#write main.zig {19#write main.zig {
21const SomeType = comptime_int;20const SomeType = comptime_int;
...@@ -28,10 +27,8 @@ pub fn main() void {...@@ -28,10 +27,8 @@ pub fn main() void {
28 s.foo();27 s.foo();
29}28}
30#}29#}
31#update {30#update "make S comptime-only"
32make S comptime-only#}31#check stdout
33#check stdout {
34#}
3532
36#write main.zig {33#write main.zig {
37const SomeType = u16;34const SomeType = u16;
...@@ -44,7 +41,5 @@ pub fn main() void {...@@ -44,7 +41,5 @@ pub fn main() void {
44 s.foo();41 s.foo();
45}42}
46#}43#}
47#update {44#update "make S runtime again"
48make S runtime again#}45#check stdout
49#check stdout {
50#}
test/incremental/type_dependency_loop+7-14
...@@ -24,10 +24,8 @@ pub fn main() void {...@@ -24,10 +24,8 @@ pub fn main() void {
24 _ = B;24 _ = B;
25}25}
26#}26#}
27#update {27#update "remove reference to dependency loop"
28remove reference to dependency loop#}28#check stdout
29#check stdout {
30#}
3129
32#write main.zig {30#write main.zig {
33pub const A = struct { b: B };31pub const A = struct { b: B };
...@@ -36,10 +34,8 @@ pub fn main() void {...@@ -36,10 +34,8 @@ pub fn main() void {
36 _ = B;34 _ = B;
37}35}
38#}36#}
39#update {37#update "change dependency loop without fixing it"
40change dependency loop without fixing it#}38#check stdout
41#check stdout {
42#}
4339
44#write main.zig {40#write main.zig {
45pub const A = struct { b: B };41pub const A = struct { b: B };
...@@ -48,8 +44,7 @@ pub fn main() void {...@@ -48,8 +44,7 @@ pub fn main() void {
48 _ = @as(B, undefined);44 _ = @as(B, undefined);
49}45}
50#}46#}
51#update {47#update "reference dependency loop again"
52reference dependency loop again#}
53#check errors {48#check errors {
54error: dependency loop with length 249error: dependency loop with length 2
55 main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here50 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 {...@@ -64,7 +59,5 @@ pub fn main() void {
64 _ = @as(B, undefined);59 _ = @as(B, undefined);
65}60}
66#}61#}
67#update {62#update "fix dependency loop"
68fix dependency loop#}63#check stdout
69#check stdout {
70#}
test/incremental/unreferenced_error+3-6
...@@ -23,8 +23,7 @@ pub fn main() !void {...@@ -23,8 +23,7 @@ pub fn main() !void {
23const a = @compileError("bad a");23const a = @compileError("bad a");
24const io = std.Io.Threaded.global_single_threaded.io();24const io = std.Io.Threaded.global_single_threaded.io();
25#}25#}
26#update {26#update "introduce compile error"
27introduce compile error#}
28#check errors {27#check errors {
29main.zig:5:11: error: bad a28main.zig:5:11: error: bad a
30#}29#}
...@@ -38,8 +37,7 @@ const a = @compileError("bad a");...@@ -38,8 +37,7 @@ const a = @compileError("bad a");
38const b = "Hi there!\n";37const b = "Hi there!\n";
39const io = std.Io.Threaded.global_single_threaded.io();38const io = std.Io.Threaded.global_single_threaded.io();
40#}39#}
41#update {40#update "remove error reference"
42remove error reference#}
43#check stdout {41#check stdout {
44Hi there!42Hi there!
45#}43#}
...@@ -53,8 +51,7 @@ const a = "Back to a\n";...@@ -53,8 +51,7 @@ const a = "Back to a\n";
53const b = @compileError("bad b");51const b = @compileError("bad b");
54const io = std.Io.Threaded.global_single_threaded.io();52const io = std.Io.Threaded.global_single_threaded.io();
55#}53#}
56#update {54#update "introduce and remove reference to error"
57introduce and remove reference to error#}
58#check stdout {55#check stdout {
59Back to a56Back to a
60#}57#}
test/llvm/allowzero created+98
...@@ -0,0 +1,98 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic
6
7#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic
8
9#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
10#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
11
12#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
13#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
14
15#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
16#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
17#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
18
19#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
20#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
21#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
22
23#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
24#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
25#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
26
27#obj {
28--name test -fno-lld -fno-new-linker -ofmt=llvmir
29-Mroot=test.zig
30#}
31
32#write test.zig {
33export fn entry(ptr: *allowzero i16) i16 {
34 return ptr.*;
35}
36#}
37#update "load"
38#check llvm {
39define #...@test.entry(ptr #...%0) #...#0 #...{
40#...load i16, ptr %0#...
41}
42
43#...
44attributes #0 = {#... null_pointer_is_valid #...}
45#}
46
47#write test.zig {
48export fn entry(ptr: *allowzero i16) void {
49 ptr.* = 42;
50}
51#}
52#update "store"
53#check llvm {
54define #...@test.entry(ptr #...%0) #...#0 #...{
55#...store i16 42, ptr %0#...
56}
57
58#...
59attributes #0 = {#... null_pointer_is_valid #...}
60#}
61
62#write test.zig {
63export fn entry(ptr: *allowzero i16) i16 {
64 return entry2(ptr[0..1]);
65}
66fn entry2(slice: []allowzero i16) i16 {
67 @setRuntimeSafety(false);
68 return slice[0];
69}
70#}
71#update "slice load"
72#check llvm {
73define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{
74#...load i16, ptr %#...
75}
76
77#...
78attributes #2 = {#... null_pointer_is_valid #...}
79#}
80
81#write test.zig {
82export fn entry(ptr: *allowzero i16) void {
83 entry2(ptr[0..1]);
84}
85fn entry2(slice: []allowzero i16) void {
86 @setRuntimeSafety(false);
87 slice[0] = 42;
88}
89#}
90#update "slice store"
91#check llvm {
92define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{
93#...store i16 42, ptr %#...
94}
95
96#...
97attributes #2 = {#... null_pointer_is_valid #...}
98#}
test/llvm/array_to_vector created+109
...@@ -0,0 +1,109 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic
6
7#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic
8
9#skip loongarch32-freestanding-none-baseline-whole-llvm-lld-pic
10#skip loongarch32-linux-gnu-baseline-whole-llvm-lld-pic
11#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic
12#skip loongarch32-linux-gnusf-baseline-whole-llvm-lld-pic
13#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic
14#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic
15#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic
16#skip loongarch32-linux-none-baseline-whole-llvm-lld-pic
17#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic
18
19#skip loongarch64-freestanding-none-baseline-whole-llvm-lld-pic
20#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic
21#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
22#skip loongarch64-linux-gnusf-baseline-whole-llvm-lld-pic
23#skip loongarch64-linux-musl-baseline-whole-llvm-lld-pic
24#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic
25#skip loongarch64-linux-muslsf-baseline-whole-llvm-lld-pic
26#skip loongarch64-linux-none-baseline-whole-llvm-lld-pic
27#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic
28
29#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
30#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
31
32#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
33#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
34
35#skip riscv32-freestanding-none-baseline-whole-llvm-lld-pic
36#skip riscv32-linux-gnu-baseline-whole-llvm-lld-pic
37#skip riscv32-linux-musl-baseline-whole-llvm-lld-pic
38#skip riscv32-linux-none-baseline-whole-llvm-lld-pic
39#skip riscv32-netbsd-none-baseline-whole-llvm-lld-pic
40#skip riscv32-rtems-none-baseline-whole-llvm-lld-pic
41#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic
42#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic
43
44#skip riscv64-freebsd-none-baseline-whole-llvm-lld-pic
45#skip riscv64-freestanding-none-baseline-whole-llvm-lld-pic
46#skip riscv64-fuchsia-none-baseline-whole-llvm-lld-pic
47#skip riscv64-haiku-none-baseline-whole-llvm-lld-pic
48#skip riscv64-hurd-gnu-baseline-whole-llvm-lld-pic
49#skip riscv64-linux-android-baseline-whole-llvm-lld-pic
50#skip riscv64-linux-gnu-baseline-whole-llvm-lld-pic
51#skip riscv64-linux-musl-baseline-whole-llvm-lld-pic
52#skip riscv64-linux-none-baseline-whole-llvm-lld-pic
53#skip riscv64-netbsd-none-baseline-whole-llvm-lld-pic
54#skip riscv64-openbsd-none-baseline-whole-llvm-lld-pic
55#skip riscv64-rtems-none-baseline-whole-llvm-lld-pic
56#skip riscv64-serenity-none-baseline-whole-llvm-lld-pic
57#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic
58#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic
59
60#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
61#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
62#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
63
64#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
65#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
66#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
67
68#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
69#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
70#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
71
72#obj {
73--name test -fno-lld -fno-new-linker -ofmt=llvmir
74-Mroot=test.zig
75#}
76
77#write test.zig {
78export fn entry(arr: *const [16]u8) @Vector(16, u8) {
79 return arr.*;
80}
81#}
82#update "one vector load"
83#check llvm {
84define #...<16 x i8> @test.entry(#...) #...{
85#...
86 %1 = alloca [16 x i8], align 1#...
87 %3 = load <16 x i8>, ptr %1, align 1#...
88 ret <16 x i8> %3#...
89#}
90
91#write test.zig {
92export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void {
93 const q: @Vector(16, u8) = src[0..16].*;
94 a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 });
95 b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 });
96}
97#}
98#update "feeding overlapping shuffles"
99#check llvm {
100define #...void @test.entry(ptr #...%0, ptr #...%1, #...) #...{
101#...
102 %11 = load <16 x i8>, ptr %#...
103 %12 = shufflevector <16 x i8> %11, #...
104 store <8 x i8> %12, ptr %0, align 8#...
105 %13 = shufflevector <16 x i8> %11, #...
106 store <8 x i8> %13, ptr %1, align 8#...
107 ret void#...
108}
109#}
test/llvm/dead_store created+65
...@@ -0,0 +1,65 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
6#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
7
8#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
9#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
10
11#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
12#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
13#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
14
15#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
16#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
17#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
18
19#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
20#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
21#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
22
23#obj {
24--name test -fno-lld -fno-new-linker -ofmt=llvmir
25-Mroot=test.zig
26#}
27
28#write test.zig {
29export fn entry(ptr: *volatile i16) void {
30 ptr.* = 123;
31 ptr.* = 321;
32}
33#}
34#update "volatile"
35#check llvm {
36define #...@test.entry(ptr #...%0) #...{
37#...store volatile i16 123, ptr %0#...
38#...store volatile i16 321, ptr %0#...
39}
40
41#}
42
43#write test.zig {
44export fn entry(ptr: *volatile i16) void {
45 entry2(ptr[0..1]);
46}
47fn entry2(slice: []volatile i16) void {
48 @setRuntimeSafety(false);
49 slice[0] = 123;
50 slice[0] = 321;
51}
52#}
53#update "volatile slice"
54#check llvm {
55define #...@test.entry(#...) #...{
56#...
57}
58
59#...
60define #...@test.entry2(#...) #...{
61#...store volatile i16 123, ptr %#...
62#...store volatile i16 321, ptr %#...
63}
64
65#}
test/llvm/empty_analyze created+50
...@@ -0,0 +1,50 @@
1#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
3
4#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic
5#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic
6
7#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic
8#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic
9#skip csky-linux-eabi-baseline-whole-llvm-lld-pic
10#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic
11#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic
12#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic
13
14#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic
15#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic
16#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic
17#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic
18#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic
19
20#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
21#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic
22#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic
23
24#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic
25
26#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic
27
28#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic
29
30#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic
31
32#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic
33
34#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
35#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
36#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
37
38#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
39#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
40#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
41
42#obj {
43--name test
44-Mroot=test.zig
45-fno-emit-asm -fno-emit-bin
46#}
47
48#write test.zig
49#update
50#check errors
test/llvm/empty_assembly created+55
...@@ -0,0 +1,55 @@
1#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
3
4#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic
5#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic
6
7#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic
8#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic
9#skip csky-linux-eabi-baseline-whole-llvm-lld-pic
10#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic
11#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic
12#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic
13
14#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic
15#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic
16#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic
17#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic
18#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic
19
20#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
21#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic
22#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic
23
24#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic
25
26#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic
27
28#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic
29
30#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic
31
32#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic
33
34#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
35#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
36#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
37
38#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
39#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
40#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
41
42#skip xtensa-freestanding-call0-baseline-whole-llvm-lld-pic
43#skip xtensa-freestanding-none-baseline-whole-llvm-lld-pic
44#skip xtensa-linux-call0-baseline-whole-llvm-lld-pic
45#skip xtensa-linux-none-baseline-whole-llvm-lld-pic
46
47#obj {
48--name test
49-Mroot=test.zig
50-femit-asm -fno-emit-bin
51#}
52
53#write test.zig
54#update
55#check errors
test/llvm/empty_object created+67
...@@ -0,0 +1,67 @@
1#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
3
4#skip arc-freestanding-none-baseline-whole-llvm-lld-pic
5#skip arc-linux-gnu-baseline-whole-llvm-lld-pic
6#skip arc-linux-none-baseline-whole-llvm-lld-pic
7
8#skip arm-uefi-eabi-baseline-whole-llvm-lld-pic
9#skip arm-uefi-eabihf-baseline-whole-llvm-lld-pic
10
11#skip csky-freestanding-eabi-baseline-whole-llvm-lld-pic
12#skip csky-freestanding-eabihf-baseline-whole-llvm-lld-pic
13#skip csky-linux-eabi-baseline-whole-llvm-lld-pic
14#skip csky-linux-eabihf-baseline-whole-llvm-lld-pic
15#skip csky-linux-gnueabi-baseline-whole-llvm-lld-pic
16#skip csky-linux-gnueabihf-baseline-whole-llvm-lld-pic
17
18#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic
19#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic
20#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic
21#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic
22#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic
23
24#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
25#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic
26#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic
27
28#skip mipsel-psx-eabi-baseline-whole-llvm-lld-pic
29
30#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
31#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
32
33#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
34#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
35
36#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic
37
38#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic
39
40#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic
41
42#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic
43
44#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
45#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
46#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
47
48#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
49#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
50#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
51
52#skip xcore-freestanding-none-baseline-whole-llvm-lld-pic
53
54#skip xtensa-freestanding-call0-baseline-whole-llvm-lld-pic
55#skip xtensa-freestanding-none-baseline-whole-llvm-lld-pic
56#skip xtensa-linux-call0-baseline-whole-llvm-lld-pic
57#skip xtensa-linux-none-baseline-whole-llvm-lld-pic
58
59#obj {
60--name test
61-Mroot=test.zig
62-fno-emit-asm -femit-bin
63#}
64
65#write test.zig
66#update
67#check errors
test/llvm/load_store_bool created+95
...@@ -0,0 +1,95 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip bpfeb-freestanding-none-baseline-whole-llvm-lld-pic
6
7#skip bpfel-freestanding-none-baseline-whole-llvm-lld-pic
8
9#skip loongarch32-freestanding-none-baseline-whole-llvm-lld-pic
10#skip loongarch32-linux-gnu-baseline-whole-llvm-lld-pic
11#skip loongarch32-linux-gnuf32-baseline-whole-llvm-lld-pic
12#skip loongarch32-linux-gnusf-baseline-whole-llvm-lld-pic
13#skip loongarch32-linux-musl-baseline-whole-llvm-lld-pic
14#skip loongarch32-linux-muslf32-baseline-whole-llvm-lld-pic
15#skip loongarch32-linux-muslsf-baseline-whole-llvm-lld-pic
16#skip loongarch32-linux-none-baseline-whole-llvm-lld-pic
17#skip loongarch32-uefi-none-baseline-whole-llvm-lld-pic
18
19#skip loongarch64-freestanding-none-baseline-whole-llvm-lld-pic
20#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic
21#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
22#skip loongarch64-linux-gnu-baseline-whole-llvm-lld-pic
23#skip loongarch64-linux-gnuf32-baseline-whole-llvm-lld-pic
24#skip loongarch64-linux-gnusf-baseline-whole-llvm-lld-pic
25#skip loongarch64-linux-musl-baseline-whole-llvm-lld-pic
26#skip loongarch64-linux-muslf32-baseline-whole-llvm-lld-pic
27#skip loongarch64-linux-muslsf-baseline-whole-llvm-lld-pic
28#skip loongarch64-linux-none-baseline-whole-llvm-lld-pic
29#skip loongarch64-uefi-none-baseline-whole-llvm-lld-pic
30
31#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
32#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
33
34#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
35#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
36
37#skip riscv32-freestanding-none-baseline-whole-llvm-lld-pic
38#skip riscv32-linux-gnu-baseline-whole-llvm-lld-pic
39#skip riscv32-linux-musl-baseline-whole-llvm-lld-pic
40#skip riscv32-linux-none-baseline-whole-llvm-lld-pic
41#skip riscv32-netbsd-none-baseline-whole-llvm-lld-pic
42#skip riscv32-rtems-none-baseline-whole-llvm-lld-pic
43#skip riscv32-uefi-none-baseline-whole-llvm-lld-pic
44
45#skip riscv32be-freestanding-none-baseline-whole-llvm-lld-pic
46
47#skip riscv64-freebsd-none-baseline-whole-llvm-lld-pic
48#skip riscv64-freestanding-none-baseline-whole-llvm-lld-pic
49#skip riscv64-fuchsia-none-baseline-whole-llvm-lld-pic
50#skip riscv64-haiku-none-baseline-whole-llvm-lld-pic
51#skip riscv64-hurd-gnu-baseline-whole-llvm-lld-pic
52#skip riscv64-linux-android-baseline-whole-llvm-lld-pic
53#skip riscv64-linux-gnu-baseline-whole-llvm-lld-pic
54#skip riscv64-linux-musl-baseline-whole-llvm-lld-pic
55#skip riscv64-linux-none-baseline-whole-llvm-lld-pic
56#skip riscv64-netbsd-none-baseline-whole-llvm-lld-pic
57#skip riscv64-openbsd-none-baseline-whole-llvm-lld-pic
58#skip riscv64-rtems-none-baseline-whole-llvm-lld-pic
59#skip riscv64-serenity-none-baseline-whole-llvm-lld-pic
60#skip riscv64-uefi-none-baseline-whole-llvm-lld-pic
61
62#skip riscv64be-freestanding-none-baseline-whole-llvm-lld-pic
63
64#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
65#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
66#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
67
68#obj {
69--name test -fno-lld -fno-new-linker -ofmt=llvmir
70-Mroot=test.zig
71#}
72
73#write test.zig {
74export fn foo(a: *bool, b: *align(2) bool) void {
75 const tmp = a.*;
76 a.* = b.*;
77 b.* = tmp;
78}
79#}
80#update
81#check llvm {
82define #...void @test.foo(ptr #...%0, ptr #...%1) #...{
83#...
84 %5 = load i8, ptr %0, align 1#...
85 %6 = trunc nuw i8 %5 to i1#...
86 %8 = load i8, ptr %1, align 2#...
87 %9 = trunc nuw i8 %8 to i1#...
88 %10 = zext i1 %9 to i8#...
89 store i8 %10, ptr %0, align 1#...
90 %11 = zext i1 %6 to i8#...
91 store i8 %11, ptr %1, align 2#...
92 ret void#...
93}
94
95#}
test/llvm/matrix.zon created+355
...@@ -0,0 +1,355 @@
1.{
2 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .driverkit = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
3 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
4 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
5 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
6 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
7 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
8 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .ios = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
9 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .ios = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
10 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
11 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
12 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
13 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
14 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
15 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .maccatalyst = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
16 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .macos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
17 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
18 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
19 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
20 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
21 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .@"switch" = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
22 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .tvos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
23 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .tvos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
24 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
25 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .visionos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
26 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .visionos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
27 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .ilp32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
28 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
29 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .watchos = .{} }, .abi = .{ .simulator = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
30 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
31 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
32 .{ .cpu = .{ .aarch64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
33
34 .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
35 .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
36 .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
37 .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
38 .{ .cpu = .{ .aarch64_be = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
39
40 .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .amdhsa = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
41 .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .amdpal = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
42 .{ .cpu = .{ .amdgcn = .{} }, .os = .{ .mesa3d = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
43
44 .{ .cpu = .{ .arc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
45 .{ .cpu = .{ .arc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
46 .{ .cpu = .{ .arc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
47
48 .{ .cpu = .{ .arm = .{} }, .os = .{ .@"3ds" = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
49 .{ .cpu = .{ .arm = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
50 .{ .cpu = .{ .arm = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
51 .{ .cpu = .{ .arm = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
52 .{ .cpu = .{ .arm = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
53 .{ .cpu = .{ .arm = .{} }, .os = .{ .gba = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
54 .{ .cpu = .{ .arm = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
55 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .androideabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
56 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
57 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
58 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
59 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
60 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
61 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
62 .{ .cpu = .{ .arm = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohoseabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
63 .{ .cpu = .{ .arm = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
64 .{ .cpu = .{ .arm = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
65 .{ .cpu = .{ .arm = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
66 .{ .cpu = .{ .arm = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
67 .{ .cpu = .{ .arm = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
68 .{ .cpu = .{ .arm = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
69 .{ .cpu = .{ .arm = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
70 .{ .cpu = .{ .arm = .{} }, .os = .{ .vita = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
71
72 .{ .cpu = .{ .armeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
73 .{ .cpu = .{ .armeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
74 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
75 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
76 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
77 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
78 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
79 .{ .cpu = .{ .armeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
80 .{ .cpu = .{ .armeb = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
81 .{ .cpu = .{ .armeb = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
82 .{ .cpu = .{ .armeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
83 .{ .cpu = .{ .armeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
84
85 .{ .cpu = .{ .avr = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
86 .{ .cpu = .{ .avr = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
87
88 .{ .cpu = .{ .bpfeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
89
90 .{ .cpu = .{ .bpfel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
91
92 .{ .cpu = .{ .csky = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
93 .{ .cpu = .{ .csky = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
94 .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
95 .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
96 .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
97 .{ .cpu = .{ .csky = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
98
99 .{ .cpu = .{ .hexagon = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
100 .{ .cpu = .{ .hexagon = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
101 .{ .cpu = .{ .hexagon = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
102
103 .{ .cpu = .{ .lanai = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
104
105 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
106 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
107 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
108 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnusf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
109 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
110 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
111 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslsf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
112 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
113 .{ .cpu = .{ .loongarch32 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
114
115 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
116 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
117 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
118 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnusf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
119 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
120 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslf32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
121 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslsf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
122 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
123 .{ .cpu = .{ .loongarch64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
124
125 .{ .cpu = .{ .m68k = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
126 .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
127 .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
128 .{ .cpu = .{ .m68k = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
129 .{ .cpu = .{ .m68k = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
130 .{ .cpu = .{ .m68k = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
131
132 .{ .cpu = .{ .mips = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
133 .{ .cpu = .{ .mips = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
134 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
135 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
136 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
137 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
138 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
139 .{ .cpu = .{ .mips = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
140 .{ .cpu = .{ .mips = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
141 .{ .cpu = .{ .mips = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
142 .{ .cpu = .{ .mips = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
143 .{ .cpu = .{ .mips = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
144
145 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
146 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
147 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
148 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
149 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
150 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnueabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
151 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
152 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
153 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
154 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
155 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .psx = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
156 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .psp = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
157 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
158 .{ .cpu = .{ .mipsel = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
159
160 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
161 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .abin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
162 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
163 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
164 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
165 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
166 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
167 .{ .cpu = .{ .mips64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
168
169 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
170 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .abin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
171 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
172 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnuabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
173 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabi64 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
174 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslabin32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
175 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
176 .{ .cpu = .{ .mips64el = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
177
178 .{ .cpu = .{ .msp430 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
179
180 .{ .cpu = .{ .nvptx = .{} }, .os = .{ .cuda = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
181 .{ .cpu = .{ .nvptx = .{} }, .os = .{ .nvcl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
182
183 .{ .cpu = .{ .nvptx64 = .{} }, .os = .{ .cuda = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
184 .{ .cpu = .{ .nvptx64 = .{} }, .os = .{ .nvcl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
185
186 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
187 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
188 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
189 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
190 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
191 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
192 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
193 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
194 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
195 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
196 .{ .cpu = .{ .powerpc = .{} }, .os = .{ .wiiu = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
197
198 .{ .cpu = .{ .powerpcle = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
199 .{ .cpu = .{ .powerpcle = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
200
201 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
202 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
203 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
204 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
205 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
206 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .ps3 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
207 .{ .cpu = .{ .powerpc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
208
209 .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
210 .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
211 .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
212 .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
213 .{ .cpu = .{ .powerpc64le = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
214
215 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
216 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
217 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
218 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
219 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
220 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
221 .{ .cpu = .{ .riscv32 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
222
223 .{ .cpu = .{ .riscv32be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
224
225 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
226 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
227 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
228 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
229 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
230 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
231 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
232 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
233 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
234 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
235 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
236 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
237 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
238 .{ .cpu = .{ .riscv64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
239
240 .{ .cpu = .{ .riscv64be = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
241
242 .{ .cpu = .{ .s390x = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
243 .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
244 .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
245 .{ .cpu = .{ .s390x = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
246
247 .{ .cpu = .{ .sparc = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
248 .{ .cpu = .{ .sparc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
249 .{ .cpu = .{ .sparc = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
250 .{ .cpu = .{ .sparc = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
251 .{ .cpu = .{ .sparc = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
252
253 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
254 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
255 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
256 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
257 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
258 .{ .cpu = .{ .sparc64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
259
260 .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opencl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
261 .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .opengl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
262 .{ .cpu = .{ .spirv32 = .{} }, .os = .{ .vulkan = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
263
264 .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .amdhsa = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
265 .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .opencl = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
266 .{ .cpu = .{ .spirv64 = .{} }, .os = .{ .vulkan = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
267
268 .{ .cpu = .{ .thumb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
269 .{ .cpu = .{ .thumb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
270 .{ .cpu = .{ .thumb = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
271 .{ .cpu = .{ .thumb = .{} }, .os = .{ .gba = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
272 .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
273 .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
274 .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
275 .{ .cpu = .{ .thumb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
276 .{ .cpu = .{ .thumb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
277 .{ .cpu = .{ .thumb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
278 .{ .cpu = .{ .thumb = .{} }, .os = .{ .vita = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
279 .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
280 .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
281 .{ .cpu = .{ .thumb = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
282
283 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
284 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
285 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
286 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
287 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
288 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musleabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
289 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabi = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
290 .{ .cpu = .{ .thumbeb = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .eabihf = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
291
292 .{ .cpu = .{ .ve = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
293 .{ .cpu = .{ .ve = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
294
295 .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .emscripten = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
296 .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
297 .{ .cpu = .{ .wasm32 = .{} }, .os = .{ .wasi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
298
299 .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .emscripten = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
300 .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
301 .{ .cpu = .{ .wasm64 = .{} }, .os = .{ .wasi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
302
303 .{ .cpu = .{ .x86 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
304 .{ .cpu = .{ .x86 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
305 .{ .cpu = .{ .x86 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
306 .{ .cpu = .{ .x86 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
307 .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
308 .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
309 .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
310 .{ .cpu = .{ .x86 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
311 .{ .cpu = .{ .x86 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
312 .{ .cpu = .{ .x86 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
313 .{ .cpu = .{ .x86 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
314 .{ .cpu = .{ .x86 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
315 .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
316 .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
317 .{ .cpu = .{ .x86 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
318
319 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freebsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
320 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
321 .{ .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 },
322 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .fuchsia = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
323 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .dragonfly = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
324 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .driverkit = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
325 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .haiku = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
326 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .hurd = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
327 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .illumos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
328 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .android = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
329 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
330 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .gnux32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
331 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .musl = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
332 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .muslx32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
333 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
334 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .ohos = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
335 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .linux = .{} }, .abi = .{ .x32 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
336 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .maccatalyst = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
337 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .macos = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .old, .pic = .pic },
338 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .netbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
339 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .openbsd = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
340 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps4 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
341 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .ps5 = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
342 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .rtems = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
343 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .serenity = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .new, .pic = .pic },
344 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .uefi = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
345 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .gnu = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
346 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .itanium = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
347 .{ .cpu = .{ .x86_64 = .{} }, .os = .{ .windows = .{} }, .abi = .{ .msvc = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
348
349 .{ .cpu = .{ .xcore = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
350
351 .{ .cpu = .{ .xtensa = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .call0 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
352 .{ .cpu = .{ .xtensa = .{} }, .os = .{ .freestanding = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
353 .{ .cpu = .{ .xtensa = .{} }, .os = .{ .linux = .{} }, .abi = .{ .call0 = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
354 .{ .cpu = .{ .xtensa = .{} }, .os = .{ .linux = .{} }, .abi = .{ .none = .{} }, .cache_mode = .whole, .backend = .llvm, .linker = .lld, .pic = .pic },
355}
test/llvm/nonnull created+44
...@@ -0,0 +1,44 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
6#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
7
8#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
9#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
10
11#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
12#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
13#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
14
15#obj {
16--name test -fno-lld -fno-new-linker -ofmt=llvmir
17-Mroot=test.zig
18#}
19
20#write test.zig {
21export fn entry(ptr: *i16) i16 {
22 return ptr.*;
23}
24#}
25#update "store"
26#check llvm {
27define #...@test.entry(ptr #...nonnull #...%0) #...{
28#...load i16, ptr %0#...
29}
30
31#}
32
33#write test.zig {
34export fn entry(ptr: *i16) void {
35 ptr.* = 42;
36}
37#}
38#update "load"
39#check llvm {
40define #...@test.entry(ptr #...nonnull #...%0) #...{
41#...store i16 42, ptr %0#...
42}
43
44#}
test/llvm/unused_load created+109
...@@ -0,0 +1,109 @@
1#skip amdgcn-amdhsa-none-baseline-whole-llvm-lld-pic
2#skip amdgcn-amdpal-none-baseline-whole-llvm-lld-pic
3#skip amdgcn-mesa3d-none-baseline-whole-llvm-lld-pic
4
5#skip nvptx-cuda-none-baseline-whole-llvm-lld-pic
6#skip nvptx-nvcl-none-baseline-whole-llvm-lld-pic
7
8#skip nvptx64-cuda-none-baseline-whole-llvm-lld-pic
9#skip nvptx64-nvcl-none-baseline-whole-llvm-lld-pic
10
11#skip spirv32-opencl-none-baseline-whole-llvm-lld-pic
12#skip spirv32-opengl-none-baseline-whole-llvm-lld-pic
13#skip spirv32-vulkan-none-baseline-whole-llvm-lld-pic
14
15#skip spirv64-amdhsa-none-baseline-whole-llvm-lld-pic
16#skip spirv64-opencl-none-baseline-whole-llvm-lld-pic
17#skip spirv64-vulkan-none-baseline-whole-llvm-lld-pic
18
19#skip wasm32-emscripten-none-baseline-whole-llvm-lld-pic
20#skip wasm32-freestanding-none-baseline-whole-llvm-lld-pic
21#skip wasm32-wasi-none-baseline-whole-llvm-lld-pic
22
23#skip wasm64-emscripten-none-baseline-whole-llvm-lld-pic
24#skip wasm64-freestanding-none-baseline-whole-llvm-lld-pic
25#skip wasm64-wasi-none-baseline-whole-llvm-lld-pic
26
27#skip x86_64-linux-gnux32-baseline-whole-llvm-new-pic
28#skip x86_64-linux-muslx32-baseline-whole-llvm-new-pic
29#skip x86_64-linux-x32-baseline-whole-llvm-new-pic
30
31#obj {
32--name test -fno-lld -fno-new-linker -ofmt=llvmir
33-Mroot=test.zig
34#}
35
36#write test.zig {
37export fn entry(ptr: *i16) void {
38 _ = @atomicLoad(i16, ptr, .acquire);
39}
40#}
41#update "atomic acquire"
42#check llvm {
43define #...@test.entry(ptr #...%0) #...{
44#...load atomic i16, ptr %0 acquire#...
45}
46
47#}
48
49#write test.zig {
50export fn entry(ptr: *volatile i16) void {
51 _ = @atomicLoad(i16, ptr, .unordered);
52}
53#}
54#update "atomic volatile unordered"
55#check llvm {
56define #...@test.entry(ptr #...%0) #...{
57#...load atomic volatile i16, ptr %0 unordered#...
58}
59
60#}
61
62#write test.zig {
63export fn entry(ptr: *volatile i16) void {
64 _ = ptr.*;
65}
66#}
67#update "volatile"
68#check llvm {
69define #...@test.entry(ptr #...%0) #...{
70#...load volatile i16, ptr %0#...
71}
72
73#}
74
75#write test.zig {
76export fn entry(ptr: *volatile i16) void {
77 entry2(ptr[0..1]);
78}
79fn entry2(slice: []volatile i16) void {
80 @setRuntimeSafety(false);
81 _ = slice[0];
82}
83#}
84#update "volatile slice"
85#check llvm {
86define #...@test.entry(#...) #...{
87#...
88}
89
90#...
91define #...@test.entry2(#...) #...{
92#...load volatile i16, ptr %#...
93}
94
95#}
96
97#write test.zig {
98const S = packed struct(u16) { a: u2, b: u8, c: u6 };
99export fn entry(ptr: *volatile S) void {
100 _ = ptr.b;
101}
102#}
103#update "volatile packed"
104#check llvm {
105define #...@test.entry(ptr #...%0) #...{
106#...load volatile i16, ptr %#...
107}
108
109#}
test/llvm_ir.zig deleted-170
...@@ -1,170 +0,0 @@
1pub fn addCases(cases: *tests.LlvmIrContext) void {
2 cases.addMatches("nonnull ptr load",
3 \\export fn entry(ptr: *i16) i16 {
4 \\ return ptr.*;
5 \\}
6 , &.{
7 "ptr nonnull",
8 "load i16, ptr %0",
9 }, .{});
10
11 cases.addMatches("nonnull ptr store",
12 \\export fn entry(ptr: *i16) void {
13 \\ ptr.* = 42;
14 \\}
15 , &.{
16 "ptr nonnull",
17 "store i16 42, ptr %0",
18 }, .{});
19
20 cases.addMatches("unused acquire atomic ptr load",
21 \\export fn entry(ptr: *i16) void {
22 \\ _ = @atomicLoad(i16, ptr, .acquire);
23 \\}
24 , &.{
25 "load atomic i16, ptr %0 acquire",
26 }, .{});
27
28 cases.addMatches("unused unordered atomic volatile ptr load",
29 \\export fn entry(ptr: *volatile i16) void {
30 \\ _ = @atomicLoad(i16, ptr, .unordered);
31 \\}
32 , &.{
33 "load atomic volatile i16, ptr %0 unordered",
34 }, .{});
35
36 cases.addMatches("unused volatile ptr load",
37 \\export fn entry(ptr: *volatile i16) void {
38 \\ _ = ptr.*;
39 \\}
40 , &.{
41 "load volatile i16, ptr %0",
42 }, .{});
43
44 cases.addMatches("dead volatile ptr store",
45 \\export fn entry(ptr: *volatile i16) void {
46 \\ ptr.* = 123;
47 \\ ptr.* = 321;
48 \\}
49 , &.{
50 "store volatile i16 123, ptr %0",
51 "store volatile i16 321, ptr %0",
52 }, .{});
53
54 cases.addMatches("unused volatile slice load",
55 \\export fn entry(ptr: *volatile i16) void {
56 \\ entry2(ptr[0..1]);
57 \\}
58 \\fn entry2(ptr: []volatile i16) void {
59 \\ _ = ptr[0];
60 \\}
61 , &.{
62 "load volatile i16, ptr",
63 }, .{});
64
65 cases.addMatches("dead volatile slice store",
66 \\export fn entry(ptr: *volatile i16) void {
67 \\ entry2(ptr[0..1]);
68 \\}
69 \\fn entry2(ptr: []volatile i16) void {
70 \\ ptr[0] = 123;
71 \\ ptr[0] = 321;
72 \\}
73 , &.{
74 "store volatile i16 123, ptr",
75 "store volatile i16 321, ptr",
76 }, .{});
77
78 cases.addMatches("unused volatile packed pointer load",
79 \\const S = packed struct(u16) { a: u2, b: u8, c: u6 };
80 \\export fn entry(ptr: *volatile S) void {
81 \\ _ = ptr.b;
82 \\}
83 , &.{
84 "load volatile i16, ptr",
85 }, .{});
86
87 cases.addMatches("allowzero ptr load",
88 \\export fn entry(ptr: *allowzero i16) i16 {
89 \\ return ptr.*;
90 \\}
91 , &.{
92 "null_pointer_is_valid",
93 "load i16, ptr %0",
94 }, .{});
95
96 cases.addMatches("allowzero ptr store",
97 \\export fn entry(ptr: *allowzero i16) void {
98 \\ ptr.* = 42;
99 \\}
100 , &.{
101 "null_pointer_is_valid",
102 "store i16 42, ptr %0",
103 }, .{});
104
105 cases.addMatches("allowzero slice load",
106 \\export fn entry(ptr: *allowzero i16) i16 {
107 \\ return entry2(ptr[0..1]);
108 \\}
109 \\fn entry2(ptr: []allowzero i16) i16 {
110 \\ return ptr[0];
111 \\}
112 , &.{
113 "null_pointer_is_valid",
114 "load i16, ptr",
115 }, .{});
116
117 cases.addMatches("allowzero slice store",
118 \\export fn entry(ptr: *allowzero i16) void {
119 \\ entry2(ptr[0..1]);
120 \\}
121 \\fn entry2(ptr: []allowzero i16) void {
122 \\ ptr[0] = 42;
123 \\}
124 , &.{
125 "null_pointer_is_valid",
126 "store i16 42, ptr",
127 }, .{});
128
129 cases.addMatches("load and store bool",
130 \\export fn foo(a: *bool, b: *align(2) bool) void {
131 \\ const tmp = a.*;
132 \\ a.* = b.*;
133 \\ b.* = tmp;
134 \\}
135 , &.{
136 // TODO: this should all be one multiline string literal, but `-femit-llvm-ir` is currently
137 // emitting CRLF on Windows, which is a pain to handle here. In future that option will emit
138 // unoptimized LLVM IR emitted directly from Zig, so that bug will go away.
139 " %3 = load i8, ptr %0, align 1",
140 " %4 = trunc nuw i8 %3 to i1",
141 " %5 = load i8, ptr %1, align 2",
142 " %6 = trunc nuw i8 %5 to i1",
143 " %7 = zext i1 %6 to i8",
144 " store i8 %7, ptr %0, align 1",
145 " %8 = zext i1 %4 to i8",
146 " store i8 %8, ptr %1, align 2",
147 }, .{ .strip = true });
148
149 cases.addMatches("array to vector coercion is one vector load",
150 \\export fn entry(arr: *const [16]u8) @Vector(16, u8) {
151 \\ return arr.*;
152 \\}
153 , &.{
154 "load <16 x i8>, ptr",
155 }, .{});
156
157 cases.addMatches("array to vector coercion feeding overlapping shuffles",
158 \\export fn entry(a: *@Vector(8, u8), b: *@Vector(8, u8), src: [*]const u8) void {
159 \\ const q: @Vector(16, u8) = src[0..16].*;
160 \\ a.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 0, 1, 2, 3, 4, 5, 6, 7 });
161 \\ b.* = @shuffle(u8, q, undefined, @Vector(8, i32){ 7, 8, 9, 10, 11, 12, 13, 14 });
162 \\}
163 , &.{
164 "load <16 x i8>, ptr",
165 "shufflevector <16 x i8>",
166 }, .{});
167}
168
169const std = @import("std");
170const tests = @import("tests.zig");
test/llvm_targets.zig deleted-382
...@@ -1,382 +0,0 @@
1const std = @import("std");
2const Cases = @import("src/Cases.zig");
3
4const targets = [_]std.Target.Query{
5 .{ .cpu_arch = .aarch64, .os_tag = .driverkit, .abi = .none },
6 .{ .cpu_arch = .aarch64, .os_tag = .freebsd, .abi = .none },
7 .{ .cpu_arch = .aarch64, .os_tag = .freestanding, .abi = .none },
8 .{ .cpu_arch = .aarch64, .os_tag = .fuchsia, .abi = .none },
9 .{ .cpu_arch = .aarch64, .os_tag = .haiku, .abi = .none },
10 .{ .cpu_arch = .aarch64, .os_tag = .hurd, .abi = .gnu },
11 .{ .cpu_arch = .aarch64, .os_tag = .ios, .abi = .none },
12 .{ .cpu_arch = .aarch64, .os_tag = .ios, .abi = .simulator },
13 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .android },
14 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .gnu },
15 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .musl },
16 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .none },
17 .{ .cpu_arch = .aarch64, .os_tag = .linux, .abi = .ohos },
18 .{ .cpu_arch = .aarch64, .os_tag = .maccatalyst, .abi = .none },
19 .{ .cpu_arch = .aarch64, .os_tag = .macos, .abi = .none },
20 .{ .cpu_arch = .aarch64, .os_tag = .netbsd, .abi = .none },
21 .{ .cpu_arch = .aarch64, .os_tag = .openbsd, .abi = .none },
22 .{ .cpu_arch = .aarch64, .os_tag = .rtems, .abi = .none },
23 .{ .cpu_arch = .aarch64, .os_tag = .serenity, .abi = .none },
24 .{ .cpu_arch = .aarch64, .os_tag = .@"switch", .abi = .none },
25 .{ .cpu_arch = .aarch64, .os_tag = .tvos, .abi = .none },
26 .{ .cpu_arch = .aarch64, .os_tag = .tvos, .abi = .simulator },
27 .{ .cpu_arch = .aarch64, .os_tag = .uefi, .abi = .none },
28 .{ .cpu_arch = .aarch64, .os_tag = .visionos, .abi = .none },
29 .{ .cpu_arch = .aarch64, .os_tag = .visionos, .abi = .simulator },
30 .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .ilp32 },
31 .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .none },
32 .{ .cpu_arch = .aarch64, .os_tag = .watchos, .abi = .simulator },
33 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .gnu },
34 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .itanium },
35 .{ .cpu_arch = .aarch64, .os_tag = .windows, .abi = .msvc },
36
37 .{ .cpu_arch = .aarch64_be, .os_tag = .freestanding, .abi = .none },
38 .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .gnu },
39 .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .musl },
40 .{ .cpu_arch = .aarch64_be, .os_tag = .linux, .abi = .none },
41 .{ .cpu_arch = .aarch64_be, .os_tag = .netbsd, .abi = .none },
42
43 .{ .cpu_arch = .amdgcn, .os_tag = .amdhsa, .abi = .none },
44 // .{ .cpu_arch = .amdgcn, .os_tag = .amdpal, .abi = .none },
45 // .{ .cpu_arch = .amdgcn, .os_tag = .mesa3d, .abi = .none },
46
47 .{ .cpu_arch = .arc, .os_tag = .freestanding, .abi = .none },
48 .{ .cpu_arch = .arc, .os_tag = .linux, .abi = .gnu },
49 .{ .cpu_arch = .arc, .os_tag = .linux, .abi = .none },
50
51 .{ .cpu_arch = .arm, .os_tag = .@"3ds", .abi = .eabihf },
52 .{ .cpu_arch = .arm, .os_tag = .freebsd, .abi = .eabihf },
53 .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .eabi },
54 .{ .cpu_arch = .arm, .os_tag = .freestanding, .abi = .eabihf },
55 .{ .cpu_arch = .arm, .os_tag = .fuchsia, .abi = .eabihf },
56 .{ .cpu_arch = .arm, .os_tag = .gba, .abi = .eabi },
57 .{ .cpu_arch = .arm, .os_tag = .haiku, .abi = .eabihf },
58 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .androideabi },
59 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .eabi },
60 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .eabihf },
61 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .gnueabi },
62 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .gnueabihf },
63 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabi },
64 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .musleabihf },
65 .{ .cpu_arch = .arm, .os_tag = .linux, .abi = .ohoseabi },
66 .{ .cpu_arch = .arm, .os_tag = .netbsd, .abi = .eabi },
67 .{ .cpu_arch = .arm, .os_tag = .netbsd, .abi = .eabihf },
68 .{ .cpu_arch = .arm, .os_tag = .openbsd, .abi = .eabi },
69 .{ .cpu_arch = .arm, .os_tag = .rtems, .abi = .eabi },
70 .{ .cpu_arch = .arm, .os_tag = .rtems, .abi = .eabihf },
71 // .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .eabi },
72 // .{ .cpu_arch = .arm, .os_tag = .uefi, .abi = .eabihf },
73 .{ .cpu_arch = .arm, .os_tag = .vita, .abi = .eabihf },
74
75 .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .eabi },
76 .{ .cpu_arch = .armeb, .os_tag = .freestanding, .abi = .eabihf },
77 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .eabi },
78 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .eabihf },
79 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .gnueabi },
80 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .gnueabihf },
81 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .musleabi },
82 .{ .cpu_arch = .armeb, .os_tag = .linux, .abi = .musleabihf },
83 .{ .cpu_arch = .armeb, .os_tag = .netbsd, .abi = .eabi },
84 .{ .cpu_arch = .armeb, .os_tag = .netbsd, .abi = .eabihf },
85 .{ .cpu_arch = .armeb, .os_tag = .rtems, .abi = .eabi },
86 .{ .cpu_arch = .armeb, .os_tag = .rtems, .abi = .eabihf },
87
88 .{ .cpu_arch = .avr, .os_tag = .freestanding, .abi = .none },
89 .{ .cpu_arch = .avr, .os_tag = .rtems, .abi = .none },
90
91 .{ .cpu_arch = .bpfeb, .os_tag = .freestanding, .abi = .none },
92
93 .{ .cpu_arch = .bpfel, .os_tag = .freestanding, .abi = .none },
94
95 // .{ .cpu_arch = .csky, .os_tag = .freestanding, .abi = .eabi },
96 // .{ .cpu_arch = .csky, .os_tag = .freestanding, .abi = .eabihf },
97 // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .eabi },
98 // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .eabihf },
99 // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .gnueabi },
100 // .{ .cpu_arch = .csky, .os_tag = .linux, .abi = .gnueabihf },
101
102 .{ .cpu_arch = .hexagon, .os_tag = .freestanding, .abi = .none },
103 .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .musl },
104 .{ .cpu_arch = .hexagon, .os_tag = .linux, .abi = .none },
105
106 .{ .cpu_arch = .lanai, .os_tag = .freestanding, .abi = .none },
107
108 .{ .cpu_arch = .loongarch32, .os_tag = .freestanding, .abi = .none },
109 .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnu },
110 // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnuf32 },
111 .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .gnusf },
112 // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .musl },
113 // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslf32 },
114 // .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .muslsf },
115 .{ .cpu_arch = .loongarch32, .os_tag = .linux, .abi = .none },
116 // .{ .cpu_arch = .loongarch32, .os_tag = .uefi, .abi = .none },
117
118 .{ .cpu_arch = .loongarch64, .os_tag = .freestanding, .abi = .none },
119 .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnu },
120 // .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnuf32 },
121 .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .gnusf },
122 .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .musl },
123 // .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .muslf32 },
124 .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .muslsf },
125 .{ .cpu_arch = .loongarch64, .os_tag = .linux, .abi = .none },
126 // .{ .cpu_arch = .loongarch64, .os_tag = .uefi, .abi = .none },
127
128 .{ .cpu_arch = .m68k, .os_tag = .freestanding, .abi = .none },
129 .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .gnu },
130 .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .musl },
131 .{ .cpu_arch = .m68k, .os_tag = .linux, .abi = .none },
132 .{ .cpu_arch = .m68k, .os_tag = .netbsd, .abi = .none },
133 .{ .cpu_arch = .m68k, .os_tag = .rtems, .abi = .none },
134
135 .{ .cpu_arch = .mips, .os_tag = .freestanding, .abi = .eabi },
136 .{ .cpu_arch = .mips, .os_tag = .freestanding, .abi = .eabihf },
137 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .eabi },
138 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .eabihf },
139 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabi },
140 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .gnueabihf },
141 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musleabi },
142 .{ .cpu_arch = .mips, .os_tag = .linux, .abi = .musleabihf },
143 .{ .cpu_arch = .mips, .os_tag = .netbsd, .abi = .eabi },
144 .{ .cpu_arch = .mips, .os_tag = .netbsd, .abi = .eabihf },
145 .{ .cpu_arch = .mips, .os_tag = .rtems, .abi = .eabi },
146 .{ .cpu_arch = .mips, .os_tag = .rtems, .abi = .eabihf },
147
148 .{ .cpu_arch = .mipsel, .os_tag = .freestanding, .abi = .eabi },
149 .{ .cpu_arch = .mipsel, .os_tag = .freestanding, .abi = .eabihf },
150 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .eabi },
151 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .eabihf },
152 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabi },
153 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .gnueabihf },
154 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musleabi },
155 .{ .cpu_arch = .mipsel, .os_tag = .linux, .abi = .musleabihf },
156 .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabi },
157 .{ .cpu_arch = .mipsel, .os_tag = .netbsd, .abi = .eabihf },
158 // .{ .cpu_arch = .mipsel, .os_tag = .psx, .abi = .eabi },
159 .{ .cpu_arch = .mipsel, .os_tag = .psp, .abi = .eabihf },
160 .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabi },
161 .{ .cpu_arch = .mipsel, .os_tag = .rtems, .abi = .eabihf },
162
163 .{ .cpu_arch = .mips64, .os_tag = .freestanding, .abi = .none },
164 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .abin32 },
165 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabi64 },
166 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .gnuabin32 },
167 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .muslabi64 },
168 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .muslabin32 },
169 .{ .cpu_arch = .mips64, .os_tag = .linux, .abi = .none },
170 .{ .cpu_arch = .mips64, .os_tag = .openbsd, .abi = .none },
171
172 .{ .cpu_arch = .mips64el, .os_tag = .freestanding, .abi = .none },
173 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .abin32 },
174 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabi64 },
175 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .gnuabin32 },
176 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .muslabi64 },
177 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .muslabin32 },
178 .{ .cpu_arch = .mips64el, .os_tag = .linux, .abi = .none },
179 .{ .cpu_arch = .mips64el, .os_tag = .openbsd, .abi = .none },
180
181 .{ .cpu_arch = .msp430, .os_tag = .freestanding, .abi = .none },
182
183 .{ .cpu_arch = .nvptx, .os_tag = .cuda, .abi = .none },
184 .{ .cpu_arch = .nvptx, .os_tag = .nvcl, .abi = .none },
185
186 .{ .cpu_arch = .nvptx64, .os_tag = .cuda, .abi = .none },
187 .{ .cpu_arch = .nvptx64, .os_tag = .nvcl, .abi = .none },
188
189 .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabi },
190 .{ .cpu_arch = .powerpc, .os_tag = .freestanding, .abi = .eabihf },
191 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .eabi },
192 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .eabihf },
193 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musleabi },
194 .{ .cpu_arch = .powerpc, .os_tag = .linux, .abi = .musleabihf },
195 .{ .cpu_arch = .powerpc, .os_tag = .netbsd, .abi = .eabihf },
196 .{ .cpu_arch = .powerpc, .os_tag = .openbsd, .abi = .eabihf },
197 .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabi },
198 .{ .cpu_arch = .powerpc, .os_tag = .rtems, .abi = .eabihf },
199 .{ .cpu_arch = .powerpc, .os_tag = .wiiu, .abi = .eabihf },
200
201 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabi },
202 .{ .cpu_arch = .powerpcle, .os_tag = .freestanding, .abi = .eabihf },
203
204 .{ .cpu_arch = .powerpc64, .os_tag = .freebsd, .abi = .none },
205 .{ .cpu_arch = .powerpc64, .os_tag = .freestanding, .abi = .none },
206 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .musl },
207 .{ .cpu_arch = .powerpc64, .os_tag = .linux, .abi = .none },
208 .{ .cpu_arch = .powerpc64, .os_tag = .openbsd, .abi = .none },
209 .{ .cpu_arch = .powerpc64, .os_tag = .ps3, .abi = .ilp32 },
210 .{ .cpu_arch = .powerpc64, .os_tag = .rtems, .abi = .none },
211
212 .{ .cpu_arch = .powerpc64le, .os_tag = .freebsd, .abi = .none },
213 .{ .cpu_arch = .powerpc64le, .os_tag = .freestanding, .abi = .none },
214 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .gnu },
215 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .musl },
216 .{ .cpu_arch = .powerpc64le, .os_tag = .linux, .abi = .none },
217
218 .{ .cpu_arch = .riscv32, .os_tag = .freestanding, .abi = .none },
219 .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .gnu },
220 .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .musl },
221 .{ .cpu_arch = .riscv32, .os_tag = .linux, .abi = .none },
222 .{ .cpu_arch = .riscv32, .os_tag = .netbsd, .abi = .none },
223 .{ .cpu_arch = .riscv32, .os_tag = .rtems, .abi = .none },
224 // .{ .cpu_arch = .riscv32, .os_tag = .uefi, .abi = .none },
225
226 // .{ .cpu_arch = .riscv32be, .os_tag = .freestanding, .abi = .none },
227
228 .{ .cpu_arch = .riscv64, .os_tag = .freebsd, .abi = .none },
229 .{ .cpu_arch = .riscv64, .os_tag = .freestanding, .abi = .none },
230 .{ .cpu_arch = .riscv64, .os_tag = .fuchsia, .abi = .none },
231 .{ .cpu_arch = .riscv64, .os_tag = .haiku, .abi = .none },
232 .{ .cpu_arch = .riscv64, .os_tag = .hurd, .abi = .gnu },
233 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .android },
234 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .gnu },
235 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .musl },
236 .{ .cpu_arch = .riscv64, .os_tag = .linux, .abi = .none },
237 .{ .cpu_arch = .riscv64, .os_tag = .netbsd, .abi = .none },
238 .{ .cpu_arch = .riscv64, .os_tag = .openbsd, .abi = .none },
239 .{ .cpu_arch = .riscv64, .os_tag = .rtems, .abi = .none },
240 .{ .cpu_arch = .riscv64, .os_tag = .serenity, .abi = .none },
241 // .{ .cpu_arch = .riscv64, .os_tag = .uefi, .abi = .none },
242
243 // .{ .cpu_arch = .riscv64be, .os_tag = .freestanding, .abi = .none },
244
245 .{ .cpu_arch = .s390x, .os_tag = .freestanding, .abi = .none },
246 .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .gnu },
247 .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .musl },
248 .{ .cpu_arch = .s390x, .os_tag = .linux, .abi = .none },
249
250 .{ .cpu_arch = .sparc, .os_tag = .freestanding, .abi = .none },
251 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .gnu },
252 .{ .cpu_arch = .sparc, .os_tag = .linux, .abi = .none },
253 .{ .cpu_arch = .sparc, .os_tag = .netbsd, .abi = .none },
254 .{ .cpu_arch = .sparc, .os_tag = .rtems, .abi = .none },
255
256 .{ .cpu_arch = .sparc64, .os_tag = .freestanding, .abi = .none },
257 .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .gnu },
258 .{ .cpu_arch = .sparc64, .os_tag = .linux, .abi = .none },
259 .{ .cpu_arch = .sparc64, .os_tag = .netbsd, .abi = .none },
260 .{ .cpu_arch = .sparc64, .os_tag = .openbsd, .abi = .none },
261 .{ .cpu_arch = .sparc64, .os_tag = .rtems, .abi = .none },
262
263 // .{ .cpu_arch = .spirv32, .os_tag = .opencl, .abi = .none },
264 // .{ .cpu_arch = .spirv32, .os_tag = .opengl, .abi = .none },
265 // .{ .cpu_arch = .spirv32, .os_tag = .vulkan, .abi = .none },
266 // .{ .cpu_arch = .spirv64, .os_tag = .amdhsa, .abi = .none },
267 // .{ .cpu_arch = .spirv64, .os_tag = .opencl, .abi = .none },
268 // .{ .cpu_arch = .spirv64, .os_tag = .vulkan, .abi = .none },
269
270 .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabi },
271 .{ .cpu_arch = .thumb, .os_tag = .freestanding, .abi = .eabihf },
272 .{ .cpu_arch = .thumb, .os_tag = .fuchsia, .abi = .eabihf },
273 .{ .cpu_arch = .thumb, .os_tag = .gba, .abi = .eabi },
274 .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabi },
275 .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .eabihf },
276 .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabi },
277 .{ .cpu_arch = .thumb, .os_tag = .linux, .abi = .musleabihf },
278 .{ .cpu_arch = .thumb, .os_tag = .rtems, .abi = .eabi },
279 .{ .cpu_arch = .thumb, .os_tag = .rtems, .abi = .eabihf },
280 .{ .cpu_arch = .thumb, .os_tag = .vita, .abi = .eabihf },
281 .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .gnu },
282 .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .itanium },
283 .{ .cpu_arch = .thumb, .os_tag = .windows, .abi = .msvc },
284
285 .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .eabi },
286 .{ .cpu_arch = .thumbeb, .os_tag = .freestanding, .abi = .eabihf },
287 .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .eabi },
288 .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .eabihf },
289 .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .musleabi },
290 .{ .cpu_arch = .thumbeb, .os_tag = .linux, .abi = .musleabihf },
291 .{ .cpu_arch = .thumbeb, .os_tag = .rtems, .abi = .eabi },
292 .{ .cpu_arch = .thumbeb, .os_tag = .rtems, .abi = .eabihf },
293
294 .{ .cpu_arch = .ve, .os_tag = .freestanding, .abi = .none },
295 .{ .cpu_arch = .ve, .os_tag = .linux, .abi = .none },
296
297 .{ .cpu_arch = .wasm32, .os_tag = .emscripten, .abi = .none },
298 .{ .cpu_arch = .wasm32, .os_tag = .freestanding, .abi = .none },
299 .{ .cpu_arch = .wasm32, .os_tag = .wasi, .abi = .none },
300
301 .{ .cpu_arch = .wasm64, .os_tag = .emscripten, .abi = .none },
302 .{ .cpu_arch = .wasm64, .os_tag = .freestanding, .abi = .none },
303 .{ .cpu_arch = .wasm64, .os_tag = .wasi, .abi = .none },
304
305 .{ .cpu_arch = .x86, .os_tag = .freestanding, .abi = .none },
306 .{ .cpu_arch = .x86, .os_tag = .haiku, .abi = .none },
307 .{ .cpu_arch = .x86, .os_tag = .hurd, .abi = .gnu },
308 .{ .cpu_arch = .x86, .os_tag = .illumos, .abi = .none },
309 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .android },
310 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .gnu },
311 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .musl },
312 .{ .cpu_arch = .x86, .os_tag = .linux, .abi = .none },
313 .{ .cpu_arch = .x86, .os_tag = .netbsd, .abi = .none },
314 .{ .cpu_arch = .x86, .os_tag = .openbsd, .abi = .none },
315 .{ .cpu_arch = .x86, .os_tag = .rtems, .abi = .none },
316 .{ .cpu_arch = .x86, .os_tag = .uefi, .abi = .none },
317 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .gnu },
318 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .itanium },
319 .{ .cpu_arch = .x86, .os_tag = .windows, .abi = .msvc },
320
321 .{ .cpu_arch = .x86_64, .os_tag = .freebsd, .abi = .none },
322 .{ .cpu_arch = .x86_64, .os_tag = .freestanding, .abi = .none },
323 .{
324 .cpu_arch = .x86_64,
325 .os_tag = .freestanding,
326 .abi = .none,
327 .cpu_features_add = std.Target.x86.featureSet(&.{.soft_float}),
328 .cpu_features_sub = std.Target.x86.featureSet(&.{ .mmx, .sse, .sse2, .avx, .avx2 }),
329 },
330 .{ .cpu_arch = .x86_64, .os_tag = .fuchsia, .abi = .none },
331 .{ .cpu_arch = .x86_64, .os_tag = .dragonfly, .abi = .none },
332 .{ .cpu_arch = .x86_64, .os_tag = .driverkit, .abi = .none },
333 .{ .cpu_arch = .x86_64, .os_tag = .haiku, .abi = .none },
334 .{ .cpu_arch = .x86_64, .os_tag = .hurd, .abi = .gnu },
335 .{ .cpu_arch = .x86_64, .os_tag = .illumos, .abi = .none },
336 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .android },
337 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnu },
338 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .gnux32 },
339 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .musl },
340 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .muslx32 },
341 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .none },
342 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .ohos },
343 .{ .cpu_arch = .x86_64, .os_tag = .linux, .abi = .x32 },
344 .{ .cpu_arch = .x86_64, .os_tag = .maccatalyst, .abi = .none },
345 .{ .cpu_arch = .x86_64, .os_tag = .macos, .abi = .none },
346 .{ .cpu_arch = .x86_64, .os_tag = .netbsd, .abi = .none },
347 .{ .cpu_arch = .x86_64, .os_tag = .openbsd, .abi = .none },
348 .{ .cpu_arch = .x86_64, .os_tag = .ps4, .abi = .none },
349 .{ .cpu_arch = .x86_64, .os_tag = .ps5, .abi = .none },
350 .{ .cpu_arch = .x86_64, .os_tag = .rtems, .abi = .none },
351 .{ .cpu_arch = .x86_64, .os_tag = .serenity, .abi = .none },
352 .{ .cpu_arch = .x86_64, .os_tag = .uefi, .abi = .none },
353 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .gnu },
354 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .itanium },
355 .{ .cpu_arch = .x86_64, .os_tag = .windows, .abi = .msvc },
356
357 .{ .cpu_arch = .xcore, .os_tag = .freestanding, .abi = .none },
358
359 .{ .cpu_arch = .xtensa, .os_tag = .freestanding, .abi = .call0 },
360 .{ .cpu_arch = .xtensa, .os_tag = .freestanding, .abi = .none },
361 .{ .cpu_arch = .xtensa, .os_tag = .linux, .abi = .call0 },
362 .{ .cpu_arch = .xtensa, .os_tag = .linux, .abi = .none },
363};
364
365pub fn addCases(
366 ctx: *Cases,
367 build_options: @import("cases.zig").BuildOptions,
368 b: *std.Build,
369) !void {
370 if (!build_options.enable_llvm) return;
371 for (targets) |target_query| {
372 if (target_query.cpu_arch) |arch| switch (arch) {
373 .m68k => if (!build_options.llvm_has_m68k) continue,
374 .csky => if (!build_options.llvm_has_csky) continue,
375 .arc => if (!build_options.llvm_has_arc) continue,
376 .xtensa => if (!build_options.llvm_has_xtensa) continue,
377 else => {},
378 };
379 var case = ctx.addObjLlvm("llvm_targets", b.resolveTargetQuery(target_query));
380 case.addCompile("");
381 }
382}
test/src/Cases.zig-33
...@@ -75,7 +75,6 @@ pub const Case = struct {...@@ -75,7 +75,6 @@ pub const Case = struct {
7575
76 emit_asm: bool = false,76 emit_asm: bool = false,
77 emit_bin: bool = true,77 emit_bin: bool = true,
78 emit_h: bool = false,
79 is_test: bool = false,78 is_test: bool = false,
80 expect_exact: bool = false,79 expect_exact: bool = false,
81 backend: Backend = .auto,80 backend: Backend = .auto,
...@@ -165,38 +164,6 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target_query: std.Target....@@ -165,38 +164,6 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target_query: std.Target.
165 return &ctx.cases.items[ctx.cases.items.len - 1];164 return &ctx.cases.items[ctx.cases.items.len - 1];
166}165}
167166
168pub fn addObjLlvm(ctx: *Cases, name: []const u8, target: std.Build.ResolvedTarget) *Case {
169 const can_emit_asm = switch (target.result.cpu.arch) {
170 .csky,
171 .xtensa,
172 => false,
173 else => true,
174 };
175 const can_emit_bin = switch (target.result.cpu.arch) {
176 .arc,
177 .csky,
178 .nvptx,
179 .nvptx64,
180 .xcore,
181 .xtensa,
182 => false,
183 else => true,
184 };
185
186 ctx.cases.append(.{
187 .name = name,
188 .target = target,
189 .files = .init(ctx.arena),
190 .case = null,
191 .output_mode = .Obj,
192 .deps = std.array_list.Managed(DepModule).init(ctx.arena),
193 .backend = .llvm,
194 .emit_bin = can_emit_bin,
195 .emit_asm = can_emit_asm,
196 }) catch @panic("out of memory");
197 return &ctx.cases.items[ctx.cases.items.len - 1];
198}
199
200pub fn addObj(167pub fn addObj(
201 ctx: *Cases,168 ctx: *Cases,
202 name: []const u8,169 name: []const u8,
test/src/LlvmIr.zig deleted-135
...@@ -1,135 +0,0 @@
1b: *std.Build,
2options: Options,
3root_step: *std.Build.Step,
4
5pub const Options = struct {
6 enable_llvm: bool,
7 test_filters: []const []const u8,
8 test_target_filters: []const []const u8,
9};
10
11const TestCase = struct {
12 name: []const u8,
13 source: []const u8,
14 check: union(enum) {
15 matches: []const []const u8,
16 exact: []const u8,
17 },
18 params: Params,
19
20 pub const Params = struct {
21 code_model: std.builtin.CodeModel = .default,
22 dll_export_fns: ?bool = null,
23 dwarf_format: ?std.dwarf.Format = null,
24 error_tracing: ?bool = null,
25 no_builtin: ?bool = null,
26 omit_frame_pointer: ?bool = null,
27 // For most cases, we want to test the LLVM IR that we output; we don't want to be in the
28 // business of testing LLVM's optimization passes. `Debug` gets us the closest to that as it
29 // disables the vast majority of passes in LLVM.
30 optimize: std.builtin.Optimize = .debug,
31 pic: ?bool = null,
32 pie: ?bool = null,
33 red_zone: ?bool = null,
34 sanitize_thread: ?bool = null,
35 single_threaded: ?bool = null,
36 stack_check: ?bool = null,
37 stack_protector: ?bool = null,
38 strip: ?bool = null,
39 target: std.Target.Query = .{},
40 unwind_tables: ?std.builtin.UnwindTables = null,
41 valgrind: ?bool = null,
42 };
43};
44
45pub fn addMatches(
46 self: *LlvmIr,
47 name: []const u8,
48 source: []const u8,
49 matches: []const []const u8,
50 params: TestCase.Params,
51) void {
52 self.addCase(.{
53 .name = name,
54 .source = source,
55 .check = .{ .matches = matches },
56 .params = params,
57 });
58}
59
60pub fn addExact(
61 self: *LlvmIr,
62 name: []const u8,
63 source: []const u8,
64 expected: []const []const u8,
65 params: TestCase.Params,
66) void {
67 self.addCase(.{
68 .name = name,
69 .source = source,
70 .check = .{ .exact = expected },
71 .params = params,
72 });
73}
74
75pub fn addCase(self: *LlvmIr, case: TestCase) void {
76 const target = self.b.resolveTargetQuery(case.params.target);
77 if (self.options.test_target_filters.len > 0) {
78 const triple_txt = target.query.zigTriple(self.b.allocator) catch @panic("OOM");
79 for (self.options.test_target_filters) |filter| {
80 if (std.mem.find(u8, triple_txt, filter) != null) break;
81 } else return;
82 }
83
84 const name = std.fmt.allocPrint(self.b.allocator, "check llvm-ir {s}", .{case.name}) catch @panic("OOM");
85 if (self.options.test_filters.len > 0) {
86 for (self.options.test_filters) |filter| {
87 if (std.mem.find(u8, name, filter) != null) break;
88 } else return;
89 }
90
91 const obj = self.b.addObject(.{
92 .name = "test",
93 .root_module = self.b.createModule(.{
94 .root_source_file = self.b.addWriteFiles().add("test.zig", case.source),
95
96 .code_model = case.params.code_model,
97 .error_tracing = case.params.error_tracing,
98 .omit_frame_pointer = case.params.omit_frame_pointer,
99 .optimize = case.params.optimize,
100 .pic = case.params.pic,
101 .sanitize_thread = case.params.sanitize_thread,
102 .single_threaded = case.params.single_threaded,
103 .strip = case.params.strip,
104 .target = target,
105 .unwind_tables = case.params.unwind_tables,
106 }),
107 .use_llvm = true,
108 });
109
110 obj.dll_export_fns = case.params.dll_export_fns;
111 obj.pie = case.params.pie;
112
113 obj.root_module.dwarf_format = case.params.dwarf_format;
114 obj.root_module.no_builtin = case.params.no_builtin;
115 obj.root_module.red_zone = case.params.red_zone;
116 obj.root_module.stack_check = case.params.stack_check;
117 obj.root_module.stack_protector = case.params.stack_protector;
118 obj.root_module.valgrind = case.params.valgrind;
119
120 // This is not very sophisticated at the moment. Eventually, we should move towards something
121 // like LLVM's `FileCheck` utility (https://llvm.org/docs/CommandGuide/FileCheck.html), though
122 // likely a more simplified version as we probably don't want a full-blown regex engine in the
123 // standard library...
124 const check = self.b.addCheckFile(obj.getEmittedLlvmIr(), switch (case.check) {
125 .matches => |m| .{ .expected_matches = m },
126 .exact => |e| .{ .expected_exact = e },
127 });
128 check.setName(name);
129 check.max_bytes = 64 * 1024 * 1024; // allow fairly big LLVM IR files
130
131 self.root_step.dependOn(&check.step);
132}
133
134const LlvmIr = @This();
135const std = @import("std");
test/src/Runner.zig deleted-2140
...@@ -1,2140 +0,0 @@
1const assert = std.debug.assert;
2const builtin = @import("builtin");
3const std = @import("std");
4const Runner = @This();
5
6gpa: std.mem.Allocator,
7arena: *std.heap.ArenaAllocator,
8environ_map: std.process.Environ.Map,
9io: std.Io,
10prog_node: std.Progress.Node,
11args: Args,
12host: std.Target,
13server: std.zig.Server,
14eb_wip: std.zig.ErrorBundle.Wip,
15
16const Args = struct {
17 @"test": ?struct {
18 input_dir: std.zig.Server.Message.InputDir,
19 dir: std.Io.Dir,
20 },
21 manifest_file: ?std.Io.File,
22 zig_exe: ?std.Io.File,
23 lib_dir: ?std.Io.Dir,
24 src_dir: ?std.Io.Dir,
25 targets: std.ArrayList(u32),
26 target_bytes: std.ArrayList(u8),
27
28 libc_runtimes_dir: ?std.Io.Dir,
29 enable_darling: bool,
30 enable_qemu: bool,
31 enable_rosetta: bool,
32 enable_wasmtime: bool,
33 enable_wine: bool,
34
35 gdb_exe: ?std.Io.File,
36 lldb_exe: ?std.Io.File,
37
38 quiet: bool,
39
40 fn deinit(args: *Args, gpa: std.mem.Allocator) void {
41 args.targets.deinit(gpa);
42 args.target_bytes.deinit(gpa);
43 args.* = undefined;
44 }
45
46 fn addTarget(args: *Args, gpa: std.mem.Allocator, target: []const u8) std.mem.Allocator.Error!void {
47 try args.target_bytes.ensureUnusedCapacity(gpa, target.len + 1);
48 try args.targets.append(gpa, @intCast(args.target_bytes.items.len));
49 args.target_bytes.appendSliceAssumeCapacity(target);
50 args.target_bytes.appendAssumeCapacity(0);
51 }
52};
53
54fn deinit(runner: *Runner) void {
55 runner.environ_map.deinit();
56 runner.prog_node.end();
57 runner.args.deinit(runner.gpa);
58 runner.eb_wip.deinit();
59 runner.* = undefined;
60}
61
62const FailError = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable;
63fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError {
64 return runner.failString(try runner.eb_wip.printString(fmt, args));
65}
66fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError {
67 try runner.eb_wip.addRootErrorMessage(.{
68 .msg = msg,
69 });
70 return error.AlreadyReported;
71}
72
73pub const ProtocolError = error{
74 ServerReadFailed,
75 ServerWriteFailed,
76 ServerEndOfStream,
77} || FailError;
78pub fn runServer(runner: *Runner) ProtocolError {
79 runner.server.serveStringMessage(.zig_version, builtin.zig_version_string) catch |err| switch (err) {
80 error.WriteFailed => return error.ServerWriteFailed,
81 };
82 while (true) {
83 _ = runner.arena.reset(.retain_capacity);
84 const arena = runner.arena.allocator();
85 const hdr = runner.server.receiveMessage() catch |err| switch (err) {
86 error.ReadFailed => return error.ServerReadFailed,
87 error.EndOfStream => return error.ServerEndOfStream,
88 };
89 switch (hdr.tag) {
90 else => |tag| return runner.fail("unsupported message: {t}", .{tag}),
91 .exit => std.process.exit(0),
92 .args => {
93 const args_body = try arena.alloc(u8, hdr.bytes_len);
94 runner.server.in.readSliceAll(args_body) catch unreachable;
95 const State = enum {
96 positional,
97 @"--zig",
98 @"--lib",
99 @"--src",
100 @"--target",
101 @"--libc-runtimes",
102 @"--gdb",
103 @"--lldb",
104 };
105 var state: State = .positional;
106 const state_expected: std.enums.EnumArray(
107 State,
108 enum { path, dir, file, string },
109 ) = .init(.{
110 .positional = .path,
111 .@"--zig" = .file,
112 .@"--lib" = .dir,
113 .@"--src" = .dir,
114 .@"--target" = .string,
115 .@"--libc-runtimes" = .dir,
116 .@"--gdb" = .file,
117 .@"--lldb" = .file,
118 });
119 var input_dir: std.zig.Server.Message.InputDir = .cwd;
120 var args_body_offset: usize = 0;
121 while (args_body.len - args_body_offset > 0) {
122 const arg: std.zig.Client.Message.Arg =
123 @fromBackingInt(args_body[args_body_offset]);
124 args_body_offset += 1;
125 arg: switch (arg) {
126 .string => {
127 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
128 const string = args_body[args_body_offset..end];
129 args_body_offset = end + 1;
130 switch (state) {
131 .positional => if (std.mem.eql(u8, string, "--target")) {
132 state = .@"--target";
133 continue;
134 } else if (std.mem.cutPrefix(u8, string, "--target=")) |target| {
135 try runner.args.addTarget(runner.gpa, target);
136 } else if (std.mem.eql(u8, string, "--libc-runtimes")) {
137 state = .@"--libc-runtimes";
138 continue;
139 } else if (std.mem.eql(u8, string, "-fdarling")) {
140 runner.args.enable_darling = true;
141 } else if (std.mem.eql(u8, string, "-fqemu")) {
142 runner.args.enable_qemu = true;
143 } else if (std.mem.eql(u8, string, "-frosetta")) {
144 runner.args.enable_rosetta = true;
145 } else if (std.mem.eql(u8, string, "-fwasmtime")) {
146 runner.args.enable_wasmtime = true;
147 } else if (std.mem.eql(u8, string, "-fwine")) {
148 runner.args.enable_wine = true;
149 } else if (std.mem.eql(u8, string, "--gdb")) {
150 state = .@"--gdb";
151 continue;
152 } else if (std.mem.eql(u8, string, "--lldb")) {
153 state = .@"--lldb";
154 continue;
155 } else if (std.mem.eql(u8, string, "--quiet")) {
156 runner.args.quiet = true;
157 },
158 .@"--target" => try runner.args.addTarget(runner.gpa, string),
159 else => return runner.fail(
160 "\"{t}\" expected {t}, got {t}",
161 .{ state, state_expected.get(state), arg },
162 ),
163 }
164 },
165 .prefix => {
166 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
167 const string = args_body[args_body_offset..end];
168 args_body_offset = end + 1;
169 assert(state == .positional);
170 state = if (std.mem.eql(u8, string, "--zig="))
171 .@"--zig"
172 else if (std.mem.eql(u8, string, "--lib="))
173 .@"--lib"
174 else if (std.mem.eql(u8, string, "--src="))
175 .@"--src"
176 else if (std.mem.eql(u8, string, "--libc-runtimes="))
177 .@"--libc-runtimes"
178 else if (std.mem.eql(u8, string, "--gdb="))
179 .@"--gdb"
180 else if (std.mem.eql(u8, string, "--lldb="))
181 .@"--lldb"
182 else
183 return runner.fail("unsupported arg prefix: {q}", .{string});
184 continue;
185 },
186 .suffix => {
187 const end = std.mem.findScalarPos(u8, args_body, args_body_offset, 0).?;
188 const string = args_body[args_body_offset..end];
189 args_body_offset = end + 1;
190 return runner.fail("unsupported arg suffix: {q}", .{string});
191 },
192 .input_dir => {
193 input_dir = @fromBackingInt(@backingInt(input_dir) + 1);
194 continue :arg .output_dir;
195 },
196 .output_dir => {
197 const dir_handle: *align(1) const std.Io.Dir.Handle = @ptrCast(
198 args_body[args_body_offset..][0..@sizeOf(std.Io.Dir.Handle)],
199 );
200 args_body_offset += @sizeOf(std.Io.Dir.Handle);
201 const dir = runner.io.vtable.inheritParentDir(
202 runner.io.userdata,
203 dir_handle.*,
204 ) catch |err| switch (err) {
205 error.Canceled => |e| return e,
206 else => |e| return runner.fail(
207 "unable to inherit parent dir: {t}",
208 .{e},
209 ),
210 };
211 switch (state) {
212 .positional => {
213 if (runner.args.@"test" != null or
214 runner.args.manifest_file != null) return runner.fail(
215 "{t} specified multiple times",
216 .{state},
217 );
218 runner.args.@"test" = .{ .input_dir = input_dir, .dir = dir };
219 const manifest_path = "manifest";
220 runner.args.manifest_file = dir.openFile(
221 runner.io,
222 manifest_path,
223 .{},
224 ) catch |err| switch (err) {
225 error.Canceled => |e| return e,
226 else => |e| return runner.fail(
227 "unable to open manifest file: {t}",
228 .{e},
229 ),
230 };
231 try runner.discoverInput(input_dir, manifest_path);
232 },
233 .@"--lib" => {
234 if (runner.args.lib_dir != null) return runner.fail(
235 "\"{t}\" specified multiple times",
236 .{state},
237 );
238 runner.args.lib_dir = dir;
239 },
240 .@"--src" => {
241 if (runner.args.src_dir != null) return runner.fail(
242 "\"{t}\" specified multiple times",
243 .{state},
244 );
245 runner.args.src_dir = dir;
246 },
247 .@"--libc-runtimes" => {
248 if (runner.args.libc_runtimes_dir != null) return runner.fail(
249 "\"{t}\" specified multiple times",
250 .{state},
251 );
252 runner.args.libc_runtimes_dir = dir;
253 },
254 else => return runner.fail(
255 "\"{t}\" expected {t}, got {t}",
256 .{ state, state_expected.get(state), arg },
257 ),
258 }
259 },
260 .input_file, .input_file_content, .output_file => {
261 const file_handle: *align(1) const std.Io.File.Handle = @ptrCast(
262 args_body[args_body_offset..][0..@sizeOf(std.Io.File.Handle)],
263 );
264 args_body_offset += @sizeOf(std.Io.File.Handle);
265 const file = runner.io.vtable.inheritParentFile(
266 runner.io.userdata,
267 file_handle.*,
268 .{ .nonblocking = false },
269 ) catch |err| switch (err) {
270 error.Canceled => |e| return e,
271 else => |e| return runner.fail(
272 "unable to inherit parent file: {t}",
273 .{e},
274 ),
275 };
276 switch (state) {
277 .positional => {
278 if (runner.args.@"test" != null or
279 runner.args.manifest_file != null) return runner.fail(
280 "{t} specified multiple times",
281 .{state},
282 );
283 runner.args.manifest_file = file;
284 },
285 .@"--zig" => {
286 if (runner.args.zig_exe != null) return runner.fail(
287 "\"{t}\" specified multiple times",
288 .{state},
289 );
290 runner.args.zig_exe = file;
291 },
292 .@"--gdb" => {
293 if (runner.args.gdb_exe != null) return runner.fail(
294 "\"{t}\" specified multiple times",
295 .{state},
296 );
297 runner.args.gdb_exe = file;
298 },
299 .@"--lldb" => {
300 if (runner.args.lldb_exe != null) return runner.fail(
301 "\"{t}\" specified multiple times",
302 .{state},
303 );
304 runner.args.lldb_exe = file;
305 },
306 else => return runner.fail(
307 "\"{t}\" expected {t}, got {t}",
308 .{ state, state_expected.get(state), arg },
309 ),
310 }
311 },
312 }
313 state = .positional;
314 }
315 },
316 .query_test_metadata => {
317 const expected_panic_msgs = try arena.alloc(u32, runner.args.targets.items.len);
318 @memset(expected_panic_msgs, 0);
319 runner.server.serveTestMetadata(.{
320 .names = runner.args.targets.items,
321 .expected_panic_msgs = expected_panic_msgs,
322 .string_bytes = runner.args.target_bytes.items,
323 }) catch |err| switch (err) {
324 error.WriteFailed => return error.ServerWriteFailed,
325 };
326 },
327 .run_test => {
328 const test_index = runner.server.receiveBody_u32() catch unreachable;
329 runner.server.serveBodylessMessage(.test_started) catch |err| switch (err) {
330 error.WriteFailed => return error.ServerWriteFailed,
331 };
332 runner.server.serveTestResults(.{
333 .index = test_index,
334 .flags = .{
335 .status = if (runner.testOne(test_index))
336 .pass
337 else |err| status: switch (err) {
338 error.Canceled,
339 error.OutOfMemory,
340 error.ServerWriteFailed,
341 => |e| return e,
342 error.AlreadyReported => {
343 var eb = try runner.eb_wip.toOwnedBundle("");
344 defer eb.deinit(runner.gpa);
345 assert(eb.errorMessageCount() > 0); // already reported what?
346 runner.server.serveErrorBundle(
347 .error_bundle,
348 eb,
349 ) catch |server_err| switch (server_err) {
350 error.WriteFailed => return error.ServerWriteFailed,
351 };
352 const eb_wip: std.zig.ErrorBundle.Wip = try .init(runner.gpa);
353 runner.eb_wip.deinit();
354 runner.eb_wip = eb_wip;
355 break :status .fail;
356 },
357 error.SkipTest => .skip,
358 },
359 .fuzz = false,
360 .log_err_count = 0,
361 .leak_count = 0,
362 },
363 }) catch |err| switch (err) {
364 error.WriteFailed => return error.ServerWriteFailed,
365 };
366 assert(runner.eb_wip.root_list.items.len == 0); // failed to report
367 },
368 }
369 }
370}
371
372fn discoverInput(
373 runner: *Runner,
374 dir: std.zig.Server.Message.InputDir,
375 sub_path: []const u8,
376) error{ServerWriteFailed}!void {
377 return runner.discoverInputInner(dir, sub_path) catch |err| switch (err) {
378 error.WriteFailed => return error.ServerWriteFailed,
379 };
380}
381fn discoverInputInner(
382 runner: *Runner,
383 dir: std.zig.Server.Message.InputDir,
384 sub_path: []const u8,
385) std.Io.Writer.Error!void {
386 try runner.server.serveMessageHeader(.{
387 .tag = .discovered_inputs,
388 .bytes_len = @intCast(@sizeOf(std.zig.Server.Message.InputDir) +
389 sub_path.len + 1),
390 });
391 try runner.server.out.writeInt(u32, @backingInt(dir), .little);
392 try runner.server.out.writeAll(sub_path);
393 try runner.server.out.writeByte(0);
394 try runner.server.out.flush();
395}
396
397pub const SourceReader = struct {
398 const Io = std.Io;
399
400 backing: *std.Io.Reader,
401 line_aw: std.Io.Writer.Allocating,
402 interface: std.Io.Reader,
403 line: u32,
404 eb_wip: *std.zig.ErrorBundle.Wip,
405 src_path: std.zig.ErrorBundle.String,
406
407 pub fn init(
408 reader: *Io.Reader,
409 gpa: std.mem.Allocator,
410 eb_wip: *std.zig.ErrorBundle.Wip,
411 src_path: std.zig.ErrorBundle.String,
412 ) SourceReader {
413 return .{
414 .backing = reader,
415 .line_aw = .init(gpa),
416 .interface = .{
417 .vtable = &.{
418 .stream = stream,
419 .discard = discard,
420 .readVec = readVec,
421 .rebase = rebase,
422 },
423 .buffer = &.{},
424 .seek = 0,
425 .end = 0,
426 },
427 .line = 0,
428 .eb_wip = eb_wip,
429 .src_path = src_path,
430 };
431 }
432 fn deinit(s: *SourceReader) void {
433 s.line_aw.deinit();
434 }
435 fn stream(r: *Io.Reader, _: *Io.Writer, _: Io.Limit) Io.Reader.StreamError!usize {
436 const s: *SourceReader = @fieldParentPtr("interface", r);
437 try s.bufferLine();
438 return 0;
439 }
440 fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
441 const s: *SourceReader = @fieldParentPtr("interface", r);
442 const remaining = r.buffered();
443 if (remaining.len > 0) {
444 const n = limit.minInt(remaining.len);
445 r.toss(n);
446 return n;
447 }
448 try s.bufferLine();
449 return 0;
450 }
451 fn readVec(r: *Io.Reader, _: [][]u8) Io.Reader.Error!usize {
452 const s: *SourceReader = @fieldParentPtr("interface", r);
453 try s.bufferLine();
454 return 0;
455 }
456 fn rebase(r: *Io.Reader, capacity: usize) Io.Reader.RebaseError!void {
457 const s: *SourceReader = @fieldParentPtr("interface", r);
458 defer s.updateBuffer();
459 s.line_aw.ensureUnusedCapacity(capacity) catch |err| switch (err) {
460 error.OutOfMemory => return error.ReadFailed,
461 };
462 }
463 fn updateBuffer(s: *SourceReader) void {
464 s.interface.buffer = s.line_aw.writer.buffer;
465 s.interface.end = s.line_aw.writer.end;
466 }
467 fn bufferLine(s: *SourceReader) Io.Reader.Error!void {
468 defer s.updateBuffer();
469 {
470 const written = s.line_aw.written();
471 const start = if (std.mem.findScalarLast(u8, written[0..s.interface.seek], '\n')) |newline|
472 newline + 1
473 else
474 0;
475 s.line += @intCast(std.mem.countScalar(u8, written[0..start], '\n'));
476 const preserve = written[start..];
477 @memmove(written[0..preserve.len], preserve);
478 s.line_aw.shrinkRetainingCapacity(preserve.len);
479 s.interface.seek -= start;
480 }
481 const n = s.backing.streamDelimiterEnding(&s.line_aw.writer, '\n') catch |err| switch (err) {
482 error.ReadFailed => |e| return e,
483 error.WriteFailed => return error.ReadFailed,
484 };
485 if (std.mem.endsWith(u8, s.line_aw.written(), "\r")) s.line_aw.writer.end -= 1;
486 const buffered = s.backing.buffered();
487 if (n == 0 and buffered.len == 0) return error.EndOfStream;
488 if (std.mem.startsWith(u8, buffered, "\n")) {
489 s.line_aw.writer.writeByte('\n') catch |err| switch (err) {
490 error.WriteFailed => return error.ReadFailed,
491 };
492 s.backing.toss(1);
493 }
494 }
495 fn fail(
496 s: *SourceReader,
497 src_loc: []const u8,
498 comptime fmt: []const u8,
499 args: anytype,
500 ) FailError {
501 return s.failString(src_loc, try s.eb_wip.printString(fmt, args));
502 }
503 fn failString(
504 s: *SourceReader,
505 src_loc: []const u8,
506 msg: std.zig.ErrorBundle.String,
507 ) FailError {
508 const line: u32, const column: u32, const source_line = src_loc: {
509 const pos = src_loc.ptr - s.interface.buffer.ptr;
510 const end = std.mem.findScalarPos(u8, s.interface.buffer, pos, '\n') orelse
511 s.interface.buffer.len;
512 const start = if (std.mem.findScalarLast(u8, s.interface.buffer[0..end], '\n')) |newline|
513 newline + 1
514 else
515 0;
516 break :src_loc .{
517 @intCast(s.line + std.mem.countScalar(u8, s.interface.buffer[0..start], '\n')),
518 @intCast(pos - start),
519 s.interface.buffer[start..end],
520 };
521 };
522 try s.eb_wip.addRootErrorMessage(.{
523 .msg = msg,
524 .src_loc = try s.eb_wip.addSourceLocation(.{
525 .src_path = s.src_path,
526 .line = line,
527 .column = column,
528 .span_start = column,
529 .span_main = column,
530 .span_end = @intCast(column + src_loc.len),
531 .source_line = try s.eb_wip.addString(source_line),
532 }),
533 });
534 return error.AlreadyReported;
535 }
536};
537pub const DelimitedReader = struct {
538 const Io = std.Io;
539
540 unlimited: *Io.Reader,
541 remaining: Io.Limit,
542 delimiter: []const u8,
543 interface: Io.Reader,
544
545 pub fn init(reader: *Io.Reader, delimiter: []const u8, buffer: []u8) DelimitedReader {
546 return .{
547 .unlimited = reader,
548 .remaining = .nothing,
549 .delimiter = delimiter,
550 .interface = .{
551 .vtable = &.{
552 .stream = stream,
553 .discard = discard,
554 },
555 .buffer = buffer,
556 .seek = 0,
557 .end = 0,
558 },
559 };
560 }
561 fn stream(r: *Io.Reader, w: *Io.Writer, limit: Io.Limit) Io.Reader.StreamError!usize {
562 const d: *DelimitedReader = @fieldParentPtr("interface", r);
563 const block = try d.unlimited.peekGreedy(d.delimiter.len);
564 d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse
565 block.len - d.delimiter.len + 1);
566 if (d.remaining == .nothing) return error.EndOfStream;
567 const n = try d.unlimited.stream(w, limit.min(d.remaining));
568 d.remaining = d.remaining.subtract(n).?;
569 return n;
570 }
571 fn discard(r: *Io.Reader, limit: Io.Limit) Io.Reader.Error!usize {
572 const d: *DelimitedReader = @fieldParentPtr("interface", r);
573 const block = try d.unlimited.peekGreedy(d.delimiter.len);
574 d.remaining = .limited(std.mem.findPos(u8, block, d.remaining.toInt().?, d.delimiter) orelse
575 block.len - d.delimiter.len + 1);
576 if (d.remaining == .nothing) return error.EndOfStream;
577 const n = try d.unlimited.discard(limit.min(d.remaining));
578 d.remaining = d.remaining.subtract(n).?;
579 return n;
580 }
581};
582
583const Update = struct {
584 target_query: []const u8,
585 manifest_sr: SourceReader,
586 compiler: ?Compiler,
587 src_dir: std.Io.Dir,
588 prog_node: std.Progress.Node,
589 mtime: std.Io.Timestamp,
590 num: usize,
591 allow_skip: bool,
592};
593
594const TestError = error{
595 SkipTest,
596} || FailError;
597fn testOne(runner: *Runner, test_index: u32) (error{ServerWriteFailed} || TestError)!void {
598 const target_query =
599 std.mem.sliceTo(runner.args.target_bytes.items[runner.args.targets.items[test_index]..], 0);
600 const manifest_file = runner.args.manifest_file orelse
601 return runner.fail("missing \"path/to/test\" arg", .{});
602 var manifest_buffer: [512]u8 = undefined;
603 var manifest_fr = manifest_file.reader(runner.io, &manifest_buffer);
604 var update: Update = .{
605 .target_query = target_query,
606 .manifest_sr = .init(&manifest_fr.interface, runner.gpa, &runner.eb_wip, src_path_string: {
607 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
608 const src_path = src_path: {
609 break :src_path path_buffer[0 .. manifest_file.realPath(
610 runner.io,
611 &path_buffer,
612 ) catch |err| switch (err) {
613 error.Canceled => |e| return e,
614 else => break :src_path "manifest",
615 }];
616 };
617 break :src_path_string try runner.eb_wip.addString(src_path);
618 }),
619 .compiler = null,
620 .src_dir = (runner.args.src_dir orelse
621 return runner.fail("missing \"--src=path/to/src\" arg", .{})).createDirPathOpen(
622 runner.io,
623 target_query,
624 .{},
625 ) catch |err| switch (err) {
626 error.Canceled => |e| return e,
627 else => |e| return runner.fail("unable to create {q}: {t}", .{ target_query, e }),
628 },
629 .prog_node = .none,
630 .mtime = .now(runner.io, .real),
631 .num = 0,
632 .allow_skip = true,
633 };
634 defer {
635 update.manifest_sr.deinit();
636 update.src_dir.close(runner.io);
637 update.prog_node.end();
638 }
639
640 // hack around `std.Io.Reader` interface bugs by ensuring the
641 // buffer is larger than the longest supported manifest line
642 try update.manifest_sr.line_aw.ensureTotalCapacityPrecise(512);
643 update.manifest_sr.updateBuffer();
644
645 var skip_delimiter = false;
646 while (update.manifest_sr.interface.takeSentinel('\n')) |line| {
647 var line_it = std.mem.tokenizeScalar(u8, line, ' ');
648 const cmd_src_loc = line_it.next() orelse continue;
649 if (skip_delimiter) {
650 assert(std.mem.eql(u8, cmd_src_loc, "#}"));
651 skip_delimiter = false;
652 const unexpected = line_it.rest();
653 if (unexpected.len > 0)
654 return update.manifest_sr.fail(unexpected, "unexpected argument {q}", .{unexpected});
655 continue;
656 }
657 const cmd = std.meta.stringToEnum(Command, std.mem.cutPrefix(u8, cmd_src_loc, "#") orelse
658 return update.manifest_sr.fail(cmd_src_loc, "expected command", .{})) orelse
659 return update.manifest_sr.fail(cmd_src_loc, "unknown command", .{});
660 const arg = switch (cmd) {
661 .todo, .exe, .lib, .obj, .update => null,
662 .skip, .write, .delete, .check => line_it.next() orelse
663 return update.manifest_sr.fail(line_it.rest()[0..0], "missing argument", .{}),
664 };
665 var contents_file: ?std.Io.File = null;
666 defer if (contents_file) |file| file.close(runner.io);
667 var contents_buffer: [512]u8 = undefined;
668 var contents_impl: union(enum) {
669 ending: std.Io.Reader,
670 dr: DelimitedReader,
671 fr: std.Io.File.Reader,
672 } = undefined;
673 const contents_r: *std.Io.Reader = contents_r: switch (cmd) {
674 .skip, .delete => {
675 const unexpected = line_it.rest();
676 if (unexpected.len > 0) return update.manifest_sr.fail(
677 unexpected,
678 "unexpected argument {q}",
679 .{unexpected},
680 );
681 contents_impl = .{ .ending = .ending_instance };
682 break :contents_r &contents_impl.ending;
683 },
684 else => {
685 const contents_path = line_it.rest();
686 if (contents_path.len == 0) {
687 contents_impl = .{ .ending = .ending_instance };
688 break :contents_r &contents_impl.ending;
689 }
690
691 if (std.mem.eql(u8, contents_path, "{")) {
692 contents_impl = .{
693 .dr = .init(&update.manifest_sr.interface, "#}", &contents_buffer),
694 };
695 skip_delimiter = true;
696 break :contents_r &contents_impl.dr.interface;
697 }
698
699 const args_test = runner.args.@"test" orelse return update.manifest_sr.fail(
700 contents_path,
701 "contents file requires directory test",
702 .{},
703 );
704 try runner.discoverInput(args_test.input_dir, contents_path);
705
706 contents_file =
707 args_test.dir.openFile(runner.io, contents_path, .{}) catch |err| switch (err) {
708 error.Canceled => |e| return e,
709 else => |e| return update.manifest_sr.fail(
710 contents_path,
711 "unable to open contents file: {t}",
712 .{e},
713 ),
714 };
715 contents_impl = .{ .fr = contents_file.?.reader(runner.io, &contents_buffer) };
716 break :contents_r &contents_impl.fr.interface;
717 },
718 };
719
720 runner.handleCommand(&update, cmd_src_loc, cmd, arg, contents_r) catch |err| switch (err) {
721 error.Canceled,
722 error.OutOfMemory,
723 error.AlreadyReported,
724 error.SkipTest,
725 => |e| return e,
726 error.ContentsReadFailed => switch (contents_impl) {
727 .ending => unreachable,
728 .dr => switch (manifest_fr.err orelse return error.OutOfMemory) {
729 error.Canceled => |e| return e,
730 else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
731 },
732 .fr => |fr| switch (fr.err.?) {
733 error.Canceled => |e| return e,
734 else => |e| return runner.fail("unable to read contents file: {t}", .{e}),
735 },
736 },
737 };
738 } else |err| switch (err) {
739 error.ReadFailed => switch (manifest_fr.err orelse return error.OutOfMemory) {
740 error.Canceled => |e| return e,
741 else => |e| return runner.fail("unable to read manifest: {t}", .{e}),
742 },
743 error.StreamTooLong => unreachable,
744 error.EndOfStream => if (skip_delimiter)
745 return runner.fail("manifest missing \"#}}\" delimiter", .{}),
746 }
747 if (update.compiler) |*comp| {
748 if (comp.state != .idle) return runner.fail("missing \"#check\"", .{});
749 try comp.exit();
750 }
751}
752const Command = enum { todo, skip, exe, lib, obj, write, delete, update, check };
753fn handleCommand(
754 runner: *Runner,
755 update: *Update,
756 cmd_src_loc: []const u8,
757 cmd: Command,
758 arg: ?[]const u8,
759 contents_r: *std.Io.Reader,
760) (error{ContentsReadFailed} || TestError)!void {
761 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
762 const cmd_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "#{t}{s}{s}", .{
763 cmd, if (arg) |_| " " else "", arg orelse "",
764 }) catch &name_buffer, 0);
765 defer cmd_prog_node.end();
766
767 cmd: switch (cmd) {
768 .todo => _ = contents_r.discardRemaining() catch |err| switch (err) {
769 error.ReadFailed => {},
770 },
771 .skip => if (!update.allow_skip) return update.manifest_sr.fail(
772 cmd_src_loc,
773 "\"#skip\" must appear before other commands",
774 .{},
775 ) else if (std.mem.eql(u8, update.target_query, arg.?)) return error.SkipTest,
776 .exe, .lib, .obj => runner.spawnCompiler(&update.compiler, update.src_dir, switch (cmd) {
777 else => unreachable,
778 .exe => .Exe,
779 .lib => .Lib,
780 .obj => .Obj,
781 }, contents_r, target: {
782 var component_it = std.mem.splitBackwardsScalar(u8, update.target_query, '-');
783 const pic_str = component_it.next() orelse
784 return runner.fail("target {q} missing pic", .{update.target_query});
785 const pic = std.meta.stringToEnum(Compiler.Target.Pic, pic_str) orelse
786 return runner.fail("target {q} unknown pic {q}", .{ update.target_query, pic_str });
787 const linker_str = component_it.next() orelse
788 return runner.fail("target {q} missing linker", .{update.target_query});
789 const linker = std.meta.stringToEnum(Compiler.Target.Linker, linker_str) orelse
790 return runner.fail("target {q} unknown linker {q}", .{ update.target_query, linker_str });
791 const backend_str = component_it.next() orelse
792 return runner.fail("target {q} missing backend", .{update.target_query});
793 const backend = std.meta.stringToEnum(Compiler.Target.Backend, backend_str) orelse
794 return runner.fail("target {q} unknown backend {q}", .{ update.target_query, backend_str });
795 const cache_mode_str = component_it.next() orelse
796 return runner.fail("target {q} missing cache mode", .{update.target_query});
797 const cache_mode = std.meta.stringToEnum(Compiler.Target.CacheMode, cache_mode_str) orelse
798 return runner.fail("target {q} unknown cache mode {q}", .{ update.target_query, cache_mode_str });
799 const triple = component_it.rest();
800 break :target .{
801 .triple = triple,
802 .resolved = std.zig.system.resolveTargetQuery(
803 runner.io,
804 std.Build.parseTargetQuery(.{
805 .arch_os_abi = triple,
806 .object_format = switch (backend) {
807 .sema, .selfhosted, .llvm => null,
808 .cbe => "c",
809 },
810 }) catch |err| switch (err) {
811 error.ParseFailed => return runner.fail("unable to parse triple {q}", .{
812 triple,
813 }),
814 },
815 ) catch |err| switch (err) {
816 error.Canceled => |e| return e,
817 else => |e| return runner.fail("unable to resolve target {q}: {t}", .{ triple, e }),
818 },
819 .cache_mode = cache_mode,
820 .backend = backend,
821 .linker = linker,
822 .pic = pic,
823 };
824 }) catch |err| switch (err) {
825 error.Canceled, error.OutOfMemory, error.AlreadyReported => |e| return e,
826 error.ReadFailed => return error.ContentsReadFailed,
827 },
828 .write => {
829 const file = update.src_dir.createFile(runner.io, arg.?, .{}) catch |err| switch (err) {
830 error.Canceled => |e| return e,
831 else => |e| return update.manifest_sr.fail(arg.?, "unable to create file: {t}", .{e}),
832 };
833 defer file.close(runner.io);
834 var fw_buffer: [512]u8 = undefined;
835 var fw = file.writer(runner.io, &fw_buffer);
836 _ = contents_r.streamRemaining(&fw.interface) catch |err| switch (err) {
837 error.ReadFailed => return error.ContentsReadFailed,
838 error.WriteFailed => switch (fw.err.?) {
839 error.Canceled => |e| return e,
840 else => |e| return update.manifest_sr.fail(
841 arg.?,
842 "unable to write file: {t}",
843 .{e},
844 ),
845 },
846 };
847 fw.flush() catch |err| switch (err) {
848 error.Canceled => |e| return e,
849 else => |e| return update.manifest_sr.fail(
850 arg.?,
851 "unable to write file: {t}",
852 .{e},
853 ),
854 };
855 file.setTimestamps(runner.io, .{ .modify_timestamp = .{
856 .new = update.mtime,
857 } }) catch |err| switch (err) {
858 error.Canceled => |e| return e,
859 else => |e| return update.manifest_sr.fail(
860 arg.?,
861 "unable to update file timestamps: {t}",
862 .{e},
863 ),
864 };
865 },
866 .delete => update.src_dir.deleteFile(runner.io, arg.?) catch |err| switch (err) {
867 error.Canceled => |e| return e,
868 else => |e| return update.manifest_sr.fail(arg.?, "unable to delete file: {t}", .{e}),
869 },
870 .update => {
871 const comp = &(update.compiler orelse return update.manifest_sr.fail(
872 cmd_src_loc,
873 "missing \"#exe\", \"#lib\", or \"#obj\"",
874 .{},
875 ));
876 update.prog_node.end();
877 update.prog_node = runner.prog_node.start(
878 switch (contents_r.readSliceShort(&name_buffer) catch |err| switch (err) {
879 error.ReadFailed => return error.ContentsReadFailed,
880 }) {
881 0 => switch (update.num) {
882 0 => "initial update",
883 else => |num| std.mem.print(&name_buffer, "update {d}", .{num}) catch
884 &name_buffer,
885 },
886 else => |name_len| name_buffer[0..name_len],
887 },
888 0,
889 );
890 _ = contents_r.discardRemaining() catch |err| switch (err) {
891 error.ReadFailed => return error.ContentsReadFailed,
892 };
893 if (comp.state != .idle)
894 return update.manifest_sr.fail(cmd_src_loc, "missing \"#check\"", .{});
895 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
896 error.WriteFailed => switch (comp.fw.err.?) {
897 error.Canceled => |e| return e,
898 else => |e| return runner.fail("unable to send message to compiler: {t}", .{e}),
899 },
900 };
901 comp.state = .update;
902 update.mtime = update.mtime.addDuration(.fromSeconds(2));
903 update.num += 1;
904 },
905 .check => {
906 const check = std.meta.stringToEnum(Compiler.Check, arg.?) orelse
907 return update.manifest_sr.fail(arg.?, "unknown check", .{});
908 const expected =
909 contents_r.allocRemaining(runner.gpa, .unlimited) catch |err| switch (err) {
910 error.OutOfMemory => |e| return e,
911 error.ReadFailed => return error.ContentsReadFailed,
912 error.StreamTooLong => unreachable, // .unlimited
913 };
914 defer runner.gpa.free(expected);
915
916 const comp = &(update.compiler orelse return update.manifest_sr.fail(
917 cmd_src_loc,
918 "missing \"#exe\", \"#lib\", or \"#obj\"",
919 .{},
920 ));
921 if (comp.state != .update)
922 return update.manifest_sr.fail(cmd_src_loc, "missing \"#update\"", .{});
923 const stderr = comp.mr.reader(1);
924 while (try comp.receiveMessage()) |message| switch (message.tag) {
925 else => {}, // Ignore other messages,
926 .config => {
927 var body_r: std.Io.Reader = .fixed(message.body);
928 comp.config = body_r.takeStruct(std.zig.Server.Message.Config, .little) catch
929 unreachable;
930 },
931 .emit_digest => {
932 var body_r: std.Io.Reader = .fixed(message.body);
933 _ = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch
934 unreachable;
935 const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch
936 unreachable;
937 try comp.checkSuccess(check, expected, update.src_dir, digest);
938 },
939 .error_bundle => {
940 const eb = std.zig.Server.allocErrorBundle(
941 runner.arena.allocator(),
942 message.body,
943 ) catch |err| switch (err) {
944 error.OutOfMemory => |e| return e,
945 error.EndOfStream => return runner.fail("error bundle truncated", .{}),
946 };
947 switch (check) {
948 .errors => {
949 var error_aw: std.Io.Writer.Allocating = .init(runner.gpa);
950 defer error_aw.deinit();
951 eb.renderToWriter(.{
952 .include_reference_trace = false,
953 .include_source_line = false,
954 .include_log_text = true,
955 }, &error_aw.writer) catch |err| switch (err) {
956 error.WriteFailed => return error.OutOfMemory,
957 };
958 const actual = error_aw.written();
959 std.mem.replaceScalar(u8, actual, '\\', '/');
960 std.testing.expectEqualStrings(expected, actual) catch |err| switch (err) {
961 error.TestExpectedEqual => return runner.fail(
962 "errors did not match expected",
963 .{},
964 ),
965 };
966 },
967 .stdout, .exit, .gdb, .lldb => if (eb.errorMessageCount() > 0) {
968 eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) {
969 error.Canceled => {},
970 else => {},
971 };
972 return runner.fail("unexpected compile errors", .{});
973 },
974 }
975 comp.state = .idle;
976 break :cmd;
977 },
978 };
979
980 const buffered_stderr = stderr.buffered();
981 if (buffered_stderr.len > 0) {
982 if (comp.allow_compiler_stderr) {
983 std.log.info("stderr:\n{s}", .{buffered_stderr});
984 } else {
985 return runner.fail("unexpected stderr:\n{s}", .{buffered_stderr});
986 }
987 }
988
989 try comp.exit();
990 return runner.fail("compiler failed to send terminating error_bundle", .{});
991 },
992 }
993 assert(contents_r.discardRemaining() catch |err| switch (err) {
994 error.ReadFailed => return error.ContentsReadFailed,
995 } == 0);
996 switch (cmd) {
997 .todo, .skip => {},
998 else => update.allow_skip = false,
999 }
1000}
1001
1002fn spawnCompiler(
1003 runner: *Runner,
1004 compiler: *?Compiler,
1005 src_dir: std.Io.Dir,
1006 output_mode: std.lang.OutputMode,
1007 args_r: *std.Io.Reader,
1008 target: Compiler.Target,
1009) (std.Io.Reader.ShortError || FailError)!void {
1010 const gpa = runner.gpa;
1011 const arena = runner.arena.allocator();
1012 if (compiler.*) |*comp| {
1013 try comp.exit();
1014 compiler.* = null;
1015 }
1016
1017 var argv: std.ArrayList([]const u8) = .empty;
1018 defer argv.deinit(gpa);
1019 try argv.appendSlice(gpa, &.{
1020 "zig",
1021 switch (output_mode) {
1022 .Obj => "build-obj",
1023 .Exe => "build-exe",
1024 .Lib => "build-lib",
1025 },
1026 "-target",
1027 target.triple,
1028 "--cache-dir",
1029 ".zig-cache",
1030 });
1031 switch (target.cache_mode) {
1032 .whole => {},
1033 .incremental => try argv.append(gpa, "-fincremental"),
1034 }
1035 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
1036 if (target.backend) |b| switch (b) {
1037 .sema => try argv.append(gpa, "-fno-emit-bin"),
1038 .selfhosted => try argv.append(gpa, "-fno-llvm"),
1039 .llvm => try argv.append(gpa, "-fllvm"),
1040 .cbe => try argv.append(gpa, "-ofmt=c"),
1041 } else try argv.appendSlice(gpa, &.{ "-I", path_buffer[0 .. (runner.args.lib_dir orelse
1042 return runner.fail("\"--lib=path/to/lib\" arg required with cbe", .{}))
1043 .realPath(runner.io, &path_buffer) catch |err| switch (err) {
1044 error.Canceled => |e| return e,
1045 else => |e| return runner.fail("unable to get lib path: {t}", .{e}),
1046 }] });
1047 switch (target.linker) {
1048 .lld => try argv.appendSlice(gpa, &.{ "-flld", "-fno-new-linker" }),
1049 .old => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fno-new-linker" }),
1050 .new => try argv.appendSlice(gpa, &.{ "-fno-lld", "-fnew-linker" }),
1051 }
1052 switch (target.pic) {
1053 .nopic => try argv.appendSlice(gpa, &.{ "-fno-PIC", "-fno-PIE" }),
1054 .pic => try argv.appendSlice(gpa, &.{ "-fPIC", "-fno-PIE" }),
1055 .pie => try argv.appendSlice(gpa, &.{ "-fPIC", "-fPIE" }),
1056 }
1057
1058 var need: usize = 1;
1059 var state: enum { positional, @"--name" } = .positional;
1060 var root_name: ?[]const u8 = null;
1061 while (true) {
1062 const done = if (args_r.fill(need)) false else |err| switch (err) {
1063 error.ReadFailed => |e| return e,
1064 error.EndOfStream => true,
1065 };
1066 const buffered = args_r.buffered();
1067 const start = std.mem.findNone(u8, buffered, "\n ") orelse buffered.len;
1068 const end = std.mem.findAnyPos(u8, buffered, start, "\n ") orelse buffered.len;
1069 if (end - start > 0) {
1070 const arg = try arena.dupe(u8, buffered[start..end]);
1071 switch (state) {
1072 .positional => if (std.mem.eql(u8, arg, "--name")) {
1073 state = .@"--name";
1074 } else if (std.mem.cutPrefix(u8, arg, "-M")) |module| {
1075 var module_name_it = std.mem.splitScalar(u8, module, '=');
1076 const module_name = module_name_it.next().?;
1077 root_name = root_name orelse module_name;
1078 },
1079 .@"--name" => {
1080 root_name = arg;
1081 state = .positional;
1082 },
1083 }
1084 try argv.append(gpa, arg);
1085 args_r.toss(end);
1086 need = 1;
1087 } else {
1088 args_r.toss(start);
1089 need = buffered.len - start + 1;
1090 }
1091 if (done) break;
1092 }
1093 try argv.append(gpa, "--listen=-");
1094
1095 const out_name = try std.zig.EmitArtifact.bin.cacheName(arena, .{
1096 .root_name = root_name orelse "root",
1097 .cpu_arch = target.resolved.cpu.arch,
1098 .os_tag = target.resolved.os.tag,
1099 .ofmt = target.resolved.ofmt,
1100 .abi = target.resolved.abi,
1101 .output_mode = output_mode,
1102 });
1103
1104 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1105 const comp_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "compile {s}", .{
1106 out_name,
1107 }) catch &name_buffer, 0);
1108 errdefer comp_prog_node.end();
1109
1110 const child = std.process.spawn(runner.io, .{
1111 .exe = .{ .file = runner.args.zig_exe orelse
1112 return runner.fail("missing \"--zig=path/to/zig\" arg", .{}) },
1113 .argv = argv.items,
1114 .cwd = .{ .dir = src_dir },
1115 .progress_node = comp_prog_node,
1116 .stdin = .pipe,
1117 .stdout = .pipe,
1118 .stderr = .pipe,
1119 }) catch |err| switch (err) {
1120 error.Canceled, error.OutOfMemory => |e| return e,
1121 else => |e| return runner.fail("unable to spawn compiler: {t}", .{e}),
1122 };
1123 compiler.* = .{
1124 .runner = runner,
1125 .prog_node = comp_prog_node,
1126 .allow_compiler_stderr = true,
1127 .output_mode = output_mode,
1128 .state = .idle,
1129 .child = child,
1130 .fw = undefined,
1131 .mr_buffer = undefined,
1132 .mr = undefined,
1133 .client = undefined,
1134 .target = target,
1135 .out_name = out_name,
1136 .config = null,
1137 };
1138 const comp = &compiler.*.?;
1139 comp.fw = child.stdin.?.writerStreaming(runner.io, &.{});
1140 comp.mr.init(gpa, runner.io, comp.mr_buffer.toStreams(), &.{
1141 child.stdout.?, child.stderr.?,
1142 });
1143 comp.client = .{ .in = comp.mr.reader(0), .out = &comp.fw.interface };
1144}
1145const Compiler = struct {
1146 runner: *Runner,
1147 prog_node: std.Progress.Node,
1148 allow_compiler_stderr: bool,
1149 output_mode: std.lang.OutputMode,
1150 state: enum { idle, update },
1151 child: std.process.Child,
1152 fw: std.Io.File.Writer,
1153 mr_buffer: std.Io.File.MultiReader.Buffer(2),
1154 mr: std.Io.File.MultiReader,
1155 client: std.zig.Client,
1156 target: Target,
1157 out_name: []const u8,
1158 config: ?std.zig.Server.Message.Config,
1159
1160 const Target = struct {
1161 triple: []const u8,
1162 resolved: std.Target,
1163 cache_mode: CacheMode,
1164 backend: ?Backend,
1165 linker: Linker,
1166 pic: Pic,
1167
1168 const CacheMode = enum { whole, incremental };
1169
1170 const Backend = enum {
1171 /// Run semantic analysis only. Runtime output will not be tested, but we still verify
1172 /// that compilation succeeds. Corresponds to `-fno-emit-bin`.
1173 sema,
1174 /// Use the self-hosted code generation backend for this target.
1175 /// Corresponds to `-fno-llvm -fno-lld`.
1176 selfhosted,
1177 /// Use the LLVM backend.
1178 /// Corresponds to `-fllvm -flld`.
1179 llvm,
1180 /// Use the C backend. The output is compiled with `zig cc`.
1181 /// Corresponds to `-ofmt=c`.
1182 cbe,
1183 };
1184
1185 const Linker = enum { old, new, lld };
1186
1187 const Pic = enum { nopic, pic, pie };
1188 };
1189
1190 fn receiveMessage(comp: *Compiler) FailError!?struct {
1191 tag: std.zig.Server.Message.Tag,
1192 body: []const u8,
1193 } {
1194 const header = comp.client.receiveMessageWithMultiReader(
1195 &comp.mr,
1196 .none,
1197 ) catch |err| switch (err) {
1198 error.Canceled, error.OutOfMemory => |e| return e,
1199 error.Timeout => unreachable,
1200 error.EndOfStream => return null,
1201 else => |e| return comp.runner.fail("unable to receive message: {t}", .{e}),
1202 };
1203 const body = comp.client.in.take(header.bytes_len) catch unreachable;
1204 const stderr = comp.mr.reader(1);
1205 if (stderr.bufferedLen() > 0) {
1206 if (comp.allow_compiler_stderr) {
1207 std.log.info("{t} stderr:\n{s}", .{ header.tag, stderr.buffered() });
1208 } else {
1209 return comp.runner.fail("{t} unexpected stderr:\n{s}", .{
1210 header.tag, stderr.buffered(),
1211 });
1212 }
1213 stderr.tossBuffered();
1214 }
1215 return .{ .tag = header.tag, .body = body };
1216 }
1217
1218 const Check = enum { errors, stdout, exit, gdb, lldb };
1219 fn checkSuccess(
1220 comp: *Compiler,
1221 check: Check,
1222 expected: []const u8,
1223 src_dir: std.Io.Dir,
1224 digest: *const std.Build.Cache.BinDigest,
1225 ) FailError!void {
1226 const runner = comp.runner;
1227 const gpa = runner.gpa;
1228 const arena = runner.arena.allocator();
1229 const io = runner.io;
1230 const target = &comp.target.resolved;
1231 const config = &comp.config.?;
1232 var path_buffer: [std.Io.Dir.max_path_bytes]u8 = undefined;
1233
1234 // After a failure while running a script, the debugger starts accepting commands from stdin, and
1235 // because it is empty, the debugger exits normally with status 0. Choose a non-zero status to
1236 // return from the debugger script instead to detect it running to completion and indicate success.
1237 const debug_success = 99;
1238
1239 const tmp_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++ "tmp";
1240 src_dir.createDirPath(io, tmp_dir_path) catch |err| switch (err) {
1241 error.Canceled => |e| return e,
1242 else => |e| return runner.fail("unable to create dir path {q}: {t}", .{
1243 tmp_dir_path, e,
1244 }),
1245 };
1246
1247 var argv: std.ArrayList([]const u8) = .initBuffer(try arena.alloc([]const u8, 5 + 4));
1248 var environ_map: std.process.Environ.Map = .init(gpa);
1249 defer environ_map.deinit();
1250 try environ_map.putAll(&runner.environ_map);
1251 var script_buffer: [512]u8 = undefined;
1252 const script_path, const script_file, var script_fw = script: switch (check) {
1253 .errors => return,
1254 .stdout, .exit => .{ undefined, null, undefined },
1255 .gdb => {
1256 const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "gdb";
1257 argv.appendSliceAssumeCapacity(&.{ "gdb", "--batch", "--command", script_path, "--args" });
1258 const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
1259 error.Canceled => |e| return e,
1260 else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{
1261 script_path, e,
1262 }),
1263 };
1264 errdefer script_file.close(io);
1265 var script_fw = script_file.writer(io, &script_buffer);
1266 script_fw.interface.writeAll(
1267 \\set remotetimeout 0
1268 \\
1269 \\
1270 ) catch |err| switch (err) {
1271 error.WriteFailed => switch (script_fw.err.?) {
1272 error.Canceled => |e| return e,
1273 else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }),
1274 },
1275 };
1276 break :script .{ script_path, script_file, script_fw };
1277 },
1278 .lldb => {
1279 const script_path = tmp_dir_path ++ std.Io.Dir.path.sep_str ++ "lldb";
1280 argv.appendSliceAssumeCapacity(&.{ "lldb", "--batch", "--source", script_path, "--" });
1281 try environ_map.put("LANG", "C.UTF-8"); // affects output formatting
1282 const script_file = src_dir.createFile(io, script_path, .{}) catch |err| switch (err) {
1283 error.Canceled => |e| return e,
1284 else => |e| return runner.fail("unable to create debugger script {q}: {t}", .{
1285 script_path,
1286 e,
1287 }),
1288 };
1289 errdefer script_file.close(io);
1290 var script_fw = script_file.writer(io, &script_buffer);
1291 script_fw.interface.writeAll(
1292 \\settings set frame-format 'frame #${frame.index}:{ ${module.file.basename}{\`${function.name-with-args}{${frame.no-debug}${function.pc-offset}}}}{ at ${line.file.basename}:${line.number}{:${line.column}}}{${function.is-optimized} [opt]}{${frame.is-artificial} [artificial]}\n'
1293 \\settings set plugin.process.gdb-remote.packet-timeout 0
1294 \\settings set stop-line-count-after 0
1295 \\settings set stop-line-count-before 0
1296 \\
1297 ) catch |err| switch (err) {
1298 error.WriteFailed => switch (script_fw.err.?) {
1299 error.Canceled => |e| return e,
1300 else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{ script_path, e }),
1301 },
1302 };
1303 break :script .{ script_path, script_file, script_fw };
1304 },
1305 };
1306 defer if (script_file) |file| file.close(io);
1307
1308 const out_dir_path = ".zig-cache" ++ std.Io.Dir.path.sep_str ++
1309 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);
1310 const out_path = try std.Io.Dir.path.join(arena, &.{ out_dir_path, comp.out_name });
1311 const bin_path = switch (comp.target.backend.?) {
1312 .sema => return,
1313 .selfhosted, .llvm => out_path,
1314 .cbe => try comp.compileC(src_dir, out_path),
1315 };
1316
1317 const need_cross_libc =
1318 target.os.tag == .linux and config.flags.link_libc and config.flags.link_mode == .dynamic;
1319 const use_executor = use_executor: switch (std.zig.system.getExternalExecutor(io, target, .{
1320 .host_cpu_arch = runner.host.cpu.arch,
1321 .host_os_tag = runner.host.os.tag,
1322 .qemu_fixes_dl = need_cross_libc and runner.args.libc_runtimes_dir != null,
1323 .link_mode = config.flags.link_mode,
1324 .link_libc = config.flags.link_libc,
1325 })) {
1326 .bad_dl, .bad_os_or_cpu => {
1327 // This binary cannot be executed on this host.
1328 if (!runner.args.quiet) std.log.warn("skipping execution because host {q} cannot " ++
1329 "execute binaries for foreign target {q}", .{
1330 try runner.host.zigTriple(arena), comp.target.triple,
1331 });
1332 return;
1333 },
1334 .native => false,
1335 .darling => |executor| if (runner.args.enable_darling) {
1336 argv.appendAssumeCapacity(executor);
1337 break :use_executor true;
1338 } else continue :use_executor .bad_os_or_cpu,
1339 .qemu => |executor| if (runner.args.enable_qemu) {
1340 argv.appendAssumeCapacity(executor);
1341 if (need_cross_libc) {
1342 const libc_runtimes_dir = runner.args.libc_runtimes_dir orelse
1343 continue :use_executor .bad_os_or_cpu;
1344 const libc_runtimes_path = path_buffer[0 .. libc_runtimes_dir.realPath(
1345 io,
1346 &path_buffer,
1347 ) catch |err| switch (err) {
1348 error.Canceled => |e| return e,
1349 else => |e| return runner.fail("unable to get libc runtimes path: {t}", .{e}),
1350 }];
1351 argv.appendSliceAssumeCapacity(&.{ "-L", try std.Io.Dir.path.join(arena, &.{
1352 libc_runtimes_path,
1353 try if (target.isGnuLibC()) std.zig.target.glibcRuntimeTriple(
1354 arena,
1355 target.cpu.arch,
1356 target.os.tag,
1357 target.abi,
1358 ) else if (target.isMuslLibC()) std.zig.target.muslRuntimeTriple(
1359 arena,
1360 target.cpu.arch,
1361 target.abi,
1362 ) else unreachable,
1363 }) });
1364 }
1365 break :use_executor true;
1366 } else continue :use_executor .bad_os_or_cpu,
1367 .rosetta => if (runner.args.enable_rosetta)
1368 true
1369 else
1370 continue :use_executor .bad_os_or_cpu,
1371 .wine => |executor| if (runner.args.enable_wine) {
1372 if (!environ_map.contains("WINEDEBUG")) try environ_map.put("WINEDEBUG", "-all");
1373 argv.appendAssumeCapacity(executor);
1374 break :use_executor true;
1375 } else continue :use_executor .bad_os_or_cpu,
1376 .wasmtime => |executor| if (runner.args.enable_wasmtime) {
1377 if (!environ_map.contains("WASMTIME_BACKTRACE_DETAILS"))
1378 try environ_map.put("WASMTIME_BACKTRACE_DETAILS", "1");
1379 argv.appendSliceAssumeCapacity(&.{ executor, "--dir=.", "-Sinherit-env" });
1380 break :use_executor true;
1381 } else continue :use_executor .bad_os_or_cpu,
1382 };
1383 argv.appendAssumeCapacity(bin_path);
1384
1385 if (!runner.args.quiet) std.log.info("{f}", .{std.zig.SubprocessCommand{
1386 .argv = argv.items,
1387 .cwd = cwd_path: {
1388 break :cwd_path path_buffer[0 .. src_dir.realPath(io, &path_buffer) catch |err| switch (err) {
1389 error.Canceled => |e| return e,
1390 else => break :cwd_path null,
1391 }];
1392 },
1393 .parent_env = &runner.environ_map,
1394 .child_env = &environ_map,
1395 }});
1396
1397 var name_buffer: [std.Progress.Node.max_name_len]u8 = undefined;
1398 const run_prog_node = runner.prog_node.start(std.mem.print(&name_buffer, "run {s}", .{
1399 comp.out_name,
1400 }) catch &name_buffer, 0);
1401 defer run_prog_node.end();
1402
1403 const bin_file = src_dir.openFile(io, bin_path, .{}) catch |err| switch (err) {
1404 error.Canceled => |e| return e,
1405 else => |e| return runner.fail("unable to open {q}: {t}", .{ bin_path, e }),
1406 };
1407 defer bin_file.close(io);
1408 const result = std.process.run(gpa, io, .{
1409 .exe = exe: switch (check) {
1410 .errors => unreachable,
1411 .stdout, .exit => if (use_executor) .search else .{ .file = bin_file },
1412 .gdb, .lldb => {
1413 if (use_executor) {
1414 if (!runner.args.quiet) std.log.warn(
1415 "skipping debugging of {q} via executor for foreign target {q}",
1416 .{ bin_path, comp.target.triple },
1417 );
1418 return;
1419 }
1420
1421 var line_it = std.mem.splitScalar(u8, expected, '\n');
1422 while (line_it.next()) |line| if (std.mem.cutPrefix(u8, line, switch (check) {
1423 else => unreachable,
1424 .gdb => "(gdb) ",
1425 .lldb => "(lldb) ",
1426 })) |cmd| script_fw.interface.print(
1427 \\{s}
1428 \\
1429 , .{cmd}) catch |err| switch (err) {
1430 error.WriteFailed => switch (script_fw.err.?) {
1431 error.Canceled => |e| return e,
1432 else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
1433 script_path, e,
1434 }),
1435 },
1436 };
1437 script_fw.interface.print(
1438 \\
1439 \\quit {d}
1440 \\
1441 , .{debug_success}) catch |err| switch (err) {
1442 error.WriteFailed => switch (script_fw.err.?) {
1443 error.Canceled => |e| return e,
1444 else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
1445 script_path, e,
1446 }),
1447 },
1448 };
1449 script_fw.flush() catch |err| switch (err) {
1450 error.Canceled => |e| return e,
1451 else => |e| return runner.fail("unable to write debugger script {q}: {t}", .{
1452 script_path, e,
1453 }),
1454 };
1455 break :exe .{ .file = switch (check) {
1456 else => unreachable,
1457 .gdb => runner.args.gdb_exe,
1458 .lldb => runner.args.lldb_exe,
1459 } orelse {
1460 if (!runner.args.quiet) std.log.warn(
1461 "skipping debugging of {q} because of missing \"--{t}=path/to/{[1]t}\" arg",
1462 .{ bin_path, check },
1463 );
1464 return;
1465 } };
1466 },
1467 },
1468 .argv = argv.items,
1469 .cwd = .{ .dir = src_dir },
1470 .environ_map = &environ_map,
1471 .progress_node = run_prog_node,
1472 }) catch |err| if (use_executor) {
1473 // Chances are the foreign executor isn't available. Skip this evaluation.
1474 if (!runner.args.quiet) std.log.warn(
1475 "skipping execution of {q} via executor for foreign target {q}: {t}",
1476 .{ bin_path, comp.target.triple, err },
1477 );
1478 return;
1479 } else return runner.fail("unable to run the generated executable {q}: {t}", .{
1480 bin_path, err,
1481 });
1482 defer {
1483 gpa.free(result.stdout);
1484 gpa.free(result.stderr);
1485 }
1486 switch (result.term) {
1487 .exited => |code| switch (check) {
1488 .errors => unreachable,
1489 .stdout => {
1490 if (code != 0) return runner.fail(
1491 "generated executable {q} failed with code {d}",
1492 .{ bin_path, code },
1493 );
1494 std.testing.expectEqualStrings(
1495 expected,
1496 result.stdout,
1497 ) catch |err| switch (err) {
1498 error.TestExpectedEqual => return runner.fail("stdout did not match expected", .{}),
1499 };
1500 },
1501 .exit => {
1502 var actual_code_buffer: [std.fmt.count("{d}", .{std.math.maxInt(u8)})]u8 = undefined;
1503 std.testing.expectEqualStrings(
1504 expected,
1505 std.mem.print(&actual_code_buffer, "{d}", .{code}) catch unreachable,
1506 ) catch |err| switch (err) {
1507 error.TestExpectedEqual => return runner.fail(
1508 "exit code did not match expected",
1509 .{},
1510 ),
1511 };
1512 },
1513 .gdb, .lldb => {
1514 if (code != debug_success) return runner.fail(
1515 "debugging {q} failed with code {d}",
1516 .{ bin_path, code },
1517 );
1518 var expected_match_it = std.mem.splitSequence(u8, expected, "#...");
1519 var pos: usize = 0;
1520 while (expected_match_it.next()) |expected_match| : (pos += expected_match.len) {
1521 var context_len: usize = expected_match.len;
1522 pos = while (true) : (context_len -= 1) break std.mem.findPos(
1523 u8,
1524 result.stdout,
1525 pos,
1526 expected_match[0..context_len],
1527 ) orelse continue;
1528 const actual_match = result.stdout[pos..];
1529 std.testing.expectEqualStrings(
1530 expected_match,
1531 actual_match[0..@min(actual_match.len, expected_match.len)],
1532 ) catch |err| switch (err) {
1533 error.TestExpectedEqual => {
1534 std.testing.failPrint("\n=============== full output: =========\n", .{});
1535 std.testing.failPrintWithVisibleNewlines(actual_match);
1536 std.testing.failPrint("\n======================================\n", .{});
1537 return runner.fail("stdout did not match expected", .{});
1538 },
1539 };
1540 }
1541 },
1542 },
1543 .signal => |sig| return runner.fail(
1544 "generated executable {q} terminated with signal {t}",
1545 .{ bin_path, sig },
1546 ),
1547 .stopped => |sig| return runner.fail(
1548 "generated executable {q} stopped with signal {t}",
1549 .{ bin_path, sig },
1550 ),
1551 .unknown => return runner.fail(
1552 "generated executable {q} terminated unexpectedly",
1553 .{bin_path},
1554 ),
1555 }
1556 if (!use_executor and result.stderr.len > 0) {
1557 std.log.err("generated executable {q} had unexpected stderr:\n{s}", .{
1558 bin_path, result.stderr,
1559 });
1560 }
1561 }
1562
1563 fn compileC(parent_comp: *Compiler, src_dir: std.Io.Dir, c_path: []const u8) FailError![]const u8 {
1564 const runner = parent_comp.runner;
1565 const arena = runner.arena.allocator();
1566 var compiler: ?Compiler = null;
1567 var args_r: std.Io.Reader = .fixed(c_path);
1568 parent_comp.runner.spawnCompiler(&compiler, src_dir, parent_comp.output_mode, &args_r, .{
1569 .triple = parent_comp.target.triple,
1570 .resolved = resolved: {
1571 var resolved = parent_comp.target.resolved;
1572 resolved.ofmt = .default(resolved.os.tag, resolved.cpu.arch);
1573 break :resolved resolved;
1574 },
1575 .cache_mode = .whole,
1576 .backend = null,
1577 .linker = .lld,
1578 .pic = parent_comp.target.pic,
1579 }) catch |err| switch (err) {
1580 error.Canceled, error.OutOfMemory, error.AlreadyReported => |e| return e,
1581 error.ReadFailed => unreachable, // .fixed
1582 };
1583 const comp = &compiler.?;
1584 comp.client.serveBodylessMessage(.update) catch |err| switch (err) {
1585 error.WriteFailed => switch (comp.fw.err.?) {
1586 error.Canceled => |e| return e,
1587 else => |e| return runner.fail("unable to send message: {t}", .{e}),
1588 },
1589 };
1590 comp.state = .update;
1591 var out_path: ?[]const u8 = null;
1592 while (try comp.receiveMessage()) |message| switch (message.tag) {
1593 else => {}, // Ignore other messages,
1594 .config => {
1595 var body_r: std.Io.Reader = .fixed(message.body);
1596 comp.config =
1597 body_r.takeStruct(std.zig.Server.Message.Config, .little) catch unreachable;
1598 },
1599 .emit_digest => {
1600 var body_r: std.Io.Reader = .fixed(message.body);
1601 _ = body_r.takeStruct(std.zig.Server.Message.EmitDigest, .little) catch unreachable;
1602 const digest = body_r.takeArray(std.Build.Cache.bin_digest_len) catch unreachable;
1603
1604 const out_dir = ".zig-cache" ++ std.Io.Dir.path.sep_str ++
1605 "o" ++ std.Io.Dir.path.sep_str ++ std.Build.Cache.binToHex(digest.*);
1606 out_path = try std.Io.Dir.path.join(arena, &.{ out_dir, comp.out_name });
1607 },
1608 .error_bundle => {
1609 const eb = std.zig.Server.allocErrorBundle(
1610 runner.arena.allocator(),
1611 message.body,
1612 ) catch |err| switch (err) {
1613 error.OutOfMemory => |e| return e,
1614 error.EndOfStream => return runner.fail("error bundle truncated", .{}),
1615 };
1616 if (eb.errorMessageCount() > 0) {
1617 try runner.eb_wip.addBundleAsRoots(eb);
1618 return runner.fail("unexpected compile errors", .{});
1619 }
1620 comp.state = .idle;
1621 break;
1622 },
1623 };
1624 try comp.exit();
1625 return out_path.?;
1626 }
1627
1628 fn exit(comp: *Compiler) FailError!void {
1629 const runner = comp.runner;
1630 comp.client.serveBodylessMessage(.exit) catch |err| switch (err) {
1631 error.WriteFailed => switch (comp.fw.err.?) {
1632 error.Canceled => |e| return e,
1633 error.BrokenPipe => {},
1634 else => |e| return comp.runner.fail("unable to send exit: {t}", .{e}),
1635 },
1636 };
1637 comp.child.stdin.?.close(runner.io);
1638 comp.child.stdin = null;
1639 while (try comp.receiveMessage()) |_| {}
1640 if (comp.client.in.bufferedLen() > 0) return runner.fail("unable to receive messages", .{});
1641 const term = comp.child.wait(runner.io) catch |err|
1642 return runner.fail("child process failed: {t}", .{err});
1643 comp.prog_node.end();
1644 switch (term) {
1645 .exited => |code| if (code != 0)
1646 return runner.fail("compiler failed with code {d}", .{code}),
1647 .signal => |sig| return runner.fail("compiler terminated with signal {t}", .{sig}),
1648 .stopped => |sig| return runner.fail("compiler stopped unexpectedly with signal {t}", .{
1649 sig,
1650 }),
1651 .unknown => return runner.fail("compiler terminated unexpectedly", .{}),
1652 }
1653 }
1654};
1655
1656const ClientArgs = struct {
1657 test_file: std.Io.File,
1658 test_kind: std.Io.File.Kind,
1659 zig_exe: std.Io.File,
1660 lib_dir: std.Io.Dir,
1661 src_dir: std.Io.Dir,
1662 targets: std.ArrayList([]const u8),
1663
1664 libc_runtimes_dir: ?std.Io.Dir,
1665 enable_darling: bool,
1666 enable_qemu: bool,
1667 enable_rosetta: bool,
1668 enable_wine: bool,
1669 enable_wasmtime: bool,
1670
1671 gdb_exe: ?std.Io.File,
1672 lldb_exe: ?std.Io.File,
1673
1674 quiet: bool,
1675 keep_src: bool,
1676};
1677pub fn main(init: std.process.Init) (std.mem.Allocator.Error || std.Io.Cancelable)!u8 {
1678 const fatal = struct {
1679 fn fatal(comptime fmt: []const u8, args: anytype) noreturn {
1680 std.log.err(fmt, args);
1681 std.process.exit(1);
1682 }
1683 }.fatal;
1684 const arena = init.arena.allocator();
1685
1686 var test_path_arg: ?[]const u8 = null;
1687 var zig_path_arg: ?[]const u8 = null;
1688 var lib_path_arg: ?[]const u8 = null;
1689 var libc_runtimes_path_arg: ?[]const u8 = null;
1690 var gdb_path_arg: ?[]const u8 = null;
1691 var lldb_path_arg: ?[]const u8 = null;
1692 var args: ClientArgs = .{
1693 .test_file = undefined,
1694 .test_kind = undefined,
1695 .zig_exe = undefined,
1696 .lib_dir = undefined,
1697 .src_dir = undefined,
1698 .targets = .empty,
1699
1700 .libc_runtimes_dir = null,
1701 .enable_darling = false,
1702 .enable_qemu = false,
1703 .enable_rosetta = false,
1704 .enable_wine = false,
1705 .enable_wasmtime = false,
1706
1707 .gdb_exe = null,
1708 .lldb_exe = null,
1709
1710 .quiet = false,
1711 .keep_src = false,
1712 };
1713 defer args.targets.deinit(init.gpa);
1714
1715 var arg_it = try init.minimal.args.iterateAllocator(arena);
1716 const self = arg_it.next().?;
1717 while (arg_it.next()) |arg| {
1718 if (std.mem.eql(u8, arg, "--listen=-")) {
1719 var stdin_buffer: [512]u8 = undefined;
1720 var stdin: std.Io.File.Reader = .initStreaming(.stdin(), init.io, &stdin_buffer);
1721 var stdout_buffer: [512]u8 = undefined;
1722 var stdout: std.Io.File.Writer = .initStreaming(.stdout(), init.io, &stdout_buffer);
1723 var runner: Runner = .{
1724 .gpa = init.gpa,
1725 .arena = init.arena,
1726 .environ_map = init.minimal.environ.createMap(init.gpa) catch |err| switch (err) {
1727 error.OutOfMemory => |e| return e,
1728 else => |e| fatal("unable to get environment: {t}", .{e}),
1729 },
1730 .io = init.io,
1731 .prog_node = std.Progress.start(init.io, .{}),
1732 .args = .{
1733 .@"test" = null,
1734 .manifest_file = null,
1735 .zig_exe = null,
1736 .lib_dir = null,
1737 .src_dir = null,
1738 .targets = .empty,
1739 .target_bytes = .empty,
1740
1741 .libc_runtimes_dir = null,
1742 .enable_darling = false,
1743 .enable_qemu = false,
1744 .enable_rosetta = false,
1745 .enable_wasmtime = false,
1746 .enable_wine = false,
1747
1748 .gdb_exe = null,
1749 .lldb_exe = null,
1750
1751 .quiet = false,
1752 },
1753 .host = std.zig.system.resolveTargetQuery(init.io, .{}) catch |err| switch (err) {
1754 error.Canceled => |e| return e,
1755 else => |e| fatal("unable to resolve host target: {t}", .{e}),
1756 },
1757 .server = .{
1758 .in = &stdin.interface,
1759 .out = &stdout.interface,
1760 },
1761 .eb_wip = try .init(init.gpa),
1762 };
1763 defer runner.deinit();
1764 switch (runner.runServer()) {
1765 error.Canceled, error.OutOfMemory => |e| return e,
1766 error.ServerReadFailed => switch (stdin.err.?) {
1767 error.Canceled => |e| return e,
1768 else => |e| fatal("unable to receive message: {t}", .{e}),
1769 },
1770 error.ServerWriteFailed => switch (stdout.err.?) {
1771 error.Canceled => |e| return e,
1772 else => |e| fatal("unable to send message: {t}", .{e}),
1773 },
1774 error.ServerEndOfStream => fatal("no more messages", .{}),
1775 error.AlreadyReported => {
1776 var eb = try runner.eb_wip.toOwnedBundle("");
1777 defer eb.deinit(init.gpa);
1778 eb.renderToStderr(runner.io, .{}, .auto) catch |err| switch (err) {
1779 error.Canceled => |e| return e,
1780 else => {},
1781 };
1782 std.process.exit(1);
1783 },
1784 }
1785 } else if (std.mem.eql(u8, arg, "--zig")) {
1786 zig_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1787 } else if (std.mem.cutPrefix(u8, arg, "--zig=")) |zig_path| {
1788 zig_path_arg = zig_path;
1789 } else if (std.mem.eql(u8, arg, "--lib")) {
1790 lib_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1791 } else if (std.mem.cutPrefix(u8, arg, "--lib=")) |lib_path| {
1792 lib_path_arg = lib_path;
1793 } else if (std.mem.eql(u8, arg, "--target")) {
1794 try args.targets.append(
1795 init.gpa,
1796 try arena.dupe(u8, arg_it.next() orelse fatal("missing arg after {q}", .{arg})),
1797 );
1798 } else if (std.mem.cutPrefix(u8, arg, "--target=")) |target| {
1799 try args.targets.append(init.gpa, try arena.dupe(u8, target));
1800 } else if (std.mem.eql(u8, arg, "--libc-runtimes")) {
1801 libc_runtimes_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1802 } else if (std.mem.cutPrefix(u8, arg, "--libc-runtimes=")) |libc_runtimes_path| {
1803 libc_runtimes_path_arg = libc_runtimes_path;
1804 } else if (std.mem.eql(u8, arg, "-fdarling")) {
1805 args.enable_darling = true;
1806 } else if (std.mem.eql(u8, arg, "-fqemu")) {
1807 args.enable_qemu = true;
1808 } else if (std.mem.eql(u8, arg, "-frosetta")) {
1809 args.enable_rosetta = true;
1810 } else if (std.mem.eql(u8, arg, "-fwine")) {
1811 args.enable_wine = true;
1812 } else if (std.mem.eql(u8, arg, "-fwasmtime")) {
1813 args.enable_wasmtime = true;
1814 } else if (std.mem.eql(u8, arg, "--gdb")) {
1815 gdb_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1816 } else if (std.mem.cutPrefix(u8, arg, "--gdb=")) |gdb_path| {
1817 gdb_path_arg = gdb_path;
1818 } else if (std.mem.eql(u8, arg, "--lldb")) {
1819 lldb_path_arg = arg_it.next() orelse fatal("missing arg after {q}", .{arg});
1820 } else if (std.mem.cutPrefix(u8, arg, "--lldb=")) |lldb_path| {
1821 lldb_path_arg = lldb_path;
1822 } else if (std.mem.eql(u8, arg, "--quiet")) {
1823 args.quiet = true;
1824 } else if (std.mem.eql(u8, arg, "--keep-src")) {
1825 args.keep_src = true;
1826 } else {
1827 if (test_path_arg) |_| fatal("unexpected arg {q}", .{arg});
1828 test_path_arg = arg;
1829 }
1830 }
1831
1832 const test_path = test_path_arg orelse fatal("missing \"path/to/test\" arg", .{});
1833 const zig_path = zig_path_arg orelse fatal("missing \"--zig=path/to/zig\" arg", .{});
1834 const lib_path = lib_path_arg orelse fatal("missing \"--lib=path/to/lib\" arg", .{});
1835
1836 const cwd: std.Io.Dir = .cwd();
1837 args.test_file = cwd.openFile(init.io, test_path, .{
1838 .allow_directory = true,
1839 }) catch |err| switch (err) {
1840 error.Canceled => |e| return e,
1841 else => |e| fatal("unable to open {q}: {t}", .{ test_path, e }),
1842 };
1843 defer args.test_file.close(init.io);
1844 args.test_kind = (args.test_file.stat(init.io) catch |err| switch (err) {
1845 error.Canceled => |e| return e,
1846 else => |e| fatal("unable to stat {q}: {t}", .{ test_path, e }),
1847 }).kind;
1848 args.zig_exe = cwd.openFile(init.io, zig_path, .{}) catch |err| switch (err) {
1849 error.Canceled => |e| return e,
1850 else => |e| fatal("unable to open {q}: {t}", .{ zig_path, e }),
1851 };
1852 defer args.zig_exe.close(init.io);
1853 args.lib_dir = cwd.openDir(init.io, lib_path, .{}) catch |err| switch (err) {
1854 error.Canceled => |e| return e,
1855 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
1856 };
1857 defer args.lib_dir.close(init.io);
1858 if (libc_runtimes_path_arg) |libc_runtimes_path| args.libc_runtimes_dir = cwd.openDir(
1859 init.io,
1860 libc_runtimes_path,
1861 .{},
1862 ) catch |err| switch (err) {
1863 error.Canceled => |e| return e,
1864 else => |e| fatal("unable to open {q}: {t}", .{ lib_path, e }),
1865 };
1866 defer if (args.libc_runtimes_dir) |libc_runtimes_dir| libc_runtimes_dir.close(init.io);
1867 if (gdb_path_arg) |gdb_path| args.gdb_exe = cwd.openFile(init.io, gdb_path, .{}) catch |err| switch (err) {
1868 error.Canceled => |e| return e,
1869 else => |e| fatal("unable to open {q}: {t}", .{ gdb_path, e }),
1870 };
1871 defer if (args.gdb_exe) |gdb_exe| gdb_exe.close(init.io);
1872 if (lldb_path_arg) |lldb_path| args.lldb_exe = cwd.openFile(init.io, lldb_path, .{}) catch |err| switch (err) {
1873 error.Canceled => |e| return e,
1874 else => |e| fatal("unable to open {q}: {t}", .{ lldb_path, e }),
1875 };
1876 defer if (args.lldb_exe) |lldb_exe| lldb_exe.close(init.io);
1877
1878 const src_dir_path = "src_" ++ std.fmt.hex(rand_int: {
1879 var rand_int: u64 = undefined;
1880 init.io.random(@ptrCast(&rand_int));
1881 break :rand_int rand_int;
1882 });
1883 args.src_dir = cwd.createDirPathOpen(init.io, src_dir_path, .{}) catch |err| switch (err) {
1884 error.Canceled => |e| return e,
1885 else => |e| fatal("unable to create {q}: {t}", .{ src_dir_path, e }),
1886 };
1887 defer {
1888 args.src_dir.close(init.io);
1889 if (!args.keep_src) cwd.deleteTree(init.io, src_dir_path) catch |err| {
1890 std.log.warn("unable to delete tree {q}: {t}", .{ src_dir_path, err });
1891 };
1892 }
1893
1894 var inherit_dirs: std.ArrayList(std.Io.Dir) = .initBuffer(try arena.alloc(std.Io.Dir, 3));
1895 var inherit_files: std.ArrayList(std.Io.File) = .initBuffer(try arena.alloc(std.Io.File, 4));
1896 inherit_files.appendSliceAssumeCapacity(&.{ args.test_file, args.zig_exe });
1897 inherit_dirs.appendSliceAssumeCapacity(&.{ args.lib_dir, args.src_dir });
1898 if (args.libc_runtimes_dir) |libc_runtimes_dir| inherit_dirs.appendAssumeCapacity(libc_runtimes_dir);
1899 if (args.gdb_exe) |gdb_exe| inherit_files.appendAssumeCapacity(gdb_exe);
1900 if (args.lldb_exe) |lldb_exe| inherit_files.appendAssumeCapacity(lldb_exe);
1901 var child = std.process.spawn(init.io, .{
1902 .argv = &.{ self, "--listen=-" },
1903 .stdin = .pipe,
1904 .stdout = .pipe,
1905 .inherit_dirs = inherit_dirs.items,
1906 .inherit_files = inherit_files.items,
1907 }) catch |err| switch (err) {
1908 error.Canceled, error.OutOfMemory => |e| return e,
1909 else => |e| fatal("unable to spawn runner: {t}", .{e}),
1910 };
1911
1912 var child_reader_buffer: [512]u8 = undefined;
1913 var child_reader = child.stdout.?.readerStreaming(init.io, &child_reader_buffer);
1914 var child_writer_buffer: [512]u8 = undefined;
1915 var child_writer = child.stdin.?.writerStreaming(init.io, &child_writer_buffer);
1916 var client: std.zig.Client = .{
1917 .in = &child_reader.interface,
1918 .out = &child_writer.interface,
1919 };
1920 const success = runClient(init.gpa, arena, init.io, &client, &args) catch |err| switch (err) {
1921 error.OutOfMemory => |e| return e,
1922 error.ReadFailed => switch (child_reader.err.?) {
1923 error.Canceled => |e| return e,
1924 else => |e| fatal("unable to receive message: {t}", .{e}),
1925 },
1926 error.WriteFailed => switch (child_writer.err.?) {
1927 error.Canceled => |e| return e,
1928 else => |e| fatal("unable to send message: {t}", .{e}),
1929 },
1930 error.EndOfStream => fatal("no more messages", .{}),
1931 };
1932 _ = child.wait(init.io) catch |err| switch (err) {
1933 error.Canceled => |e| return e,
1934 else => |e| fatal("unable to wait for runner: {t}", .{e}),
1935 };
1936 return if (success) 0 else 1;
1937}
1938fn runClient(
1939 gpa: std.mem.Allocator,
1940 arena: std.mem.Allocator,
1941 io: std.Io,
1942 client: *std.zig.Client,
1943 args: *const ClientArgs,
1944) (std.mem.Allocator.Error || std.Io.Reader.Error || std.Io.Writer.Error)!bool {
1945 var stdout_buffer: [512]u8 = undefined;
1946 var stdout_fw: std.Io.File.Writer = .initStreaming(.stdout(), io, &stdout_buffer);
1947 const stdout = &stdout_fw.interface;
1948 var stderr_buffer: [512]u8 = undefined;
1949 var stderr_fw: std.Io.File.Writer = .initStreaming(.stderr(), io, &stderr_buffer);
1950 const stderr = &stderr_fw.interface;
1951
1952 var argv: std.ArrayList(u8) = .empty;
1953 defer argv.deinit(gpa);
1954 const Arg = std.zig.Client.Message.Arg;
1955
1956 try argv.append(gpa, @backingInt(@as(Arg, switch (args.test_kind) {
1957 else => unreachable,
1958 .file => .input_file,
1959 .directory => .input_dir,
1960 })));
1961 try argv.appendSlice(gpa, @ptrCast(&args.test_file.handle));
1962
1963 try argv.append(gpa, @backingInt(Arg.prefix));
1964 try argv.appendSlice(gpa, "--zig=");
1965 try argv.append(gpa, 0);
1966 try argv.append(gpa, @backingInt(Arg.input_file));
1967 try argv.appendSlice(gpa, @ptrCast(&args.zig_exe.handle));
1968
1969 try argv.append(gpa, @backingInt(Arg.prefix));
1970 try argv.appendSlice(gpa, "--lib=");
1971 try argv.append(gpa, 0);
1972 try argv.append(gpa, @backingInt(Arg.input_dir));
1973 try argv.appendSlice(gpa, @ptrCast(&args.lib_dir.handle));
1974
1975 try argv.append(gpa, @backingInt(Arg.prefix));
1976 try argv.appendSlice(gpa, "--src=");
1977 try argv.append(gpa, 0);
1978 try argv.append(gpa, @backingInt(Arg.output_dir));
1979 try argv.appendSlice(gpa, @ptrCast(&args.src_dir.handle));
1980
1981 for (args.targets.items) |target| {
1982 try argv.append(gpa, @backingInt(Arg.string));
1983 try argv.appendSlice(gpa, "--target");
1984 try argv.append(gpa, 0);
1985
1986 try argv.append(gpa, @backingInt(Arg.string));
1987 try argv.appendSlice(gpa, target);
1988 try argv.append(gpa, 0);
1989 }
1990
1991 if (args.libc_runtimes_dir) |libc_runtimes_dir| {
1992 try argv.append(gpa, @backingInt(Arg.prefix));
1993 try argv.appendSlice(gpa, "--libc-runtimes=");
1994 try argv.append(gpa, 0);
1995 try argv.append(gpa, @backingInt(Arg.input_dir));
1996 try argv.appendSlice(gpa, @ptrCast(&libc_runtimes_dir.handle));
1997 }
1998 if (args.enable_darling) {
1999 try argv.append(gpa, @backingInt(Arg.string));
2000 try argv.appendSlice(gpa, "-fdarling");
2001 try argv.append(gpa, 0);
2002 }
2003 if (args.enable_qemu) {
2004 try argv.append(gpa, @backingInt(Arg.string));
2005 try argv.appendSlice(gpa, "-fqemu");
2006 try argv.append(gpa, 0);
2007 }
2008 if (args.enable_rosetta) {
2009 try argv.append(gpa, @backingInt(Arg.string));
2010 try argv.appendSlice(gpa, "-frosetta");
2011 try argv.append(gpa, 0);
2012 }
2013 if (args.enable_wine) {
2014 try argv.append(gpa, @backingInt(Arg.string));
2015 try argv.appendSlice(gpa, "-fwine");
2016 try argv.append(gpa, 0);
2017 }
2018 if (args.enable_wasmtime) {
2019 try argv.append(gpa, @backingInt(Arg.string));
2020 try argv.appendSlice(gpa, "-fwasmtime");
2021 try argv.append(gpa, 0);
2022 }
2023
2024 if (args.gdb_exe) |gdb_exe| {
2025 try argv.append(gpa, @backingInt(Arg.prefix));
2026 try argv.appendSlice(gpa, "--gdb=");
2027 try argv.append(gpa, 0);
2028 try argv.append(gpa, @backingInt(Arg.input_file));
2029 try argv.appendSlice(gpa, @ptrCast(&gdb_exe.handle));
2030 }
2031 if (args.lldb_exe) |lldb_exe| {
2032 try argv.append(gpa, @backingInt(Arg.prefix));
2033 try argv.appendSlice(gpa, "--lldb=");
2034 try argv.append(gpa, 0);
2035 try argv.append(gpa, @backingInt(Arg.input_file));
2036 try argv.appendSlice(gpa, @ptrCast(&lldb_exe.handle));
2037 }
2038
2039 if (args.quiet) {
2040 try argv.append(gpa, @backingInt(Arg.string));
2041 try argv.appendSlice(gpa, "--quiet");
2042 try argv.append(gpa, 0);
2043 }
2044
2045 try client.serveMessageHeader(.{
2046 .tag = .args,
2047 .bytes_len = @intCast(argv.items.len),
2048 });
2049 try client.out.writeAll(argv.items);
2050
2051 var success = true;
2052 var metadata: struct {
2053 index: u32,
2054 len: u32,
2055 names: []u32,
2056 expected_panic_msgs: []u32,
2057 string_bytes: []u8,
2058
2059 fn name(m: *@This()) []const u8 {
2060 return std.mem.sliceTo(m.string_bytes[m.names[m.index - 1]..], 0);
2061 }
2062
2063 fn expectedPanicMsg(m: *@This()) ?[:0]const u8 {
2064 return switch (m.expected_panic_msgs[m.index - 1]) {
2065 0 => null,
2066 else => |offset| m.string_bytes[offset..std.mem.findScalarPos(
2067 u8,
2068 m.string_bytes,
2069 offset,
2070 0,
2071 ).? :0],
2072 };
2073 }
2074
2075 fn next(m: *@This()) ?u32 {
2076 if (m.len - m.index == 0) return null;
2077 defer m.index += 1;
2078 return m.index;
2079 }
2080 } = .{ .index = 0, .len = 0, .names = &.{}, .expected_panic_msgs = &.{}, .string_bytes = &.{} };
2081 try client.serveBodylessMessage(.query_test_metadata);
2082 while (true) {
2083 const hdr = try client.receiveMessage();
2084 switch (hdr.tag) {
2085 else => try client.in.discardAll(hdr.bytes_len),
2086 .zig_version => {
2087 const actual_version = try client.in.take(hdr.bytes_len);
2088 if (!std.mem.eql(u8, builtin.zig_version_string, actual_version)) {
2089 try stderr.print(
2090 "error: zig version mismatch compiler test runner vs compiler: {q} vs {q}\n",
2091 .{ builtin.zig_version_string, actual_version },
2092 );
2093 try stderr.flush();
2094 std.process.exit(1);
2095 }
2096 },
2097 .error_bundle => {
2098 const body = try arena.alloc(u8, hdr.bytes_len);
2099 try client.in.readSliceAll(body);
2100 const eb = std.zig.Server.allocErrorBundle(arena, body) catch |err| switch (err) {
2101 error.OutOfMemory => |e| return e,
2102 error.EndOfStream => {
2103 try stderr.writeAll("error bundle truncated\n");
2104 try stderr.flush();
2105 std.process.exit(1);
2106 },
2107 };
2108 success = false;
2109 eb.renderToStderr(io, .{}, .auto) catch {};
2110 },
2111 .test_metadata => {
2112 const tm_hdr =
2113 try client.in.takeStruct(std.zig.Server.Message.TestMetadata, .little);
2114 metadata = .{
2115 .index = 0,
2116 .len = tm_hdr.tests_len,
2117 .names = try arena.alloc(u32, tm_hdr.tests_len),
2118 .expected_panic_msgs = try arena.alloc(u32, tm_hdr.tests_len),
2119 .string_bytes = try arena.alloc(u8, tm_hdr.string_bytes_len),
2120 };
2121 try client.in.readSliceEndian(u32, metadata.names, .little);
2122 try client.in.readSliceEndian(u32, metadata.expected_panic_msgs, .little);
2123 try client.in.readSliceAll(metadata.string_bytes);
2124 try client.serveRunTest(metadata.next() orelse break);
2125 },
2126 .test_results => {
2127 const tr = try client.in.takeStruct(std.zig.Server.Message.TestResults, .little);
2128 switch (tr.flags.status) {
2129 .pass, .skip => {},
2130 .fail => success = false,
2131 }
2132 try stdout.print("[{t}] {s}\n", .{ tr.flags.status, metadata.name() });
2133 try stdout.flush();
2134 try client.serveRunTest(metadata.next() orelse break);
2135 },
2136 }
2137 }
2138 try client.serveBodylessMessage(.exit);
2139 return success;
2140}
test/tests.zig+27-183
...@@ -6,14 +6,12 @@ const OptimizeMode = std.builtin.Optimize;...@@ -6,14 +6,12 @@ const OptimizeMode = std.builtin.Optimize;
6const Step = std.Build.Step;6const Step = std.Build.Step;
77
8// Cases8// Cases
9const llvm_ir = @import("llvm_ir.zig");
10const libc = @import("libc.zig");9const libc = @import("libc.zig");
11const link = @import("link.zig");10const link = @import("link.zig");
1211
13// Implementations12// Implementations
14pub const ErrorTracesContext = @import("src/ErrorTrace.zig");13pub const ErrorTracesContext = @import("src/ErrorTrace.zig");
15pub const StackTracesContext = @import("src/StackTrace.zig");14pub const StackTracesContext = @import("src/StackTrace.zig");
16pub const LlvmIrContext = @import("src/LlvmIr.zig");
17pub const LibcContext = @import("src/Libc.zig");15pub const LibcContext = @import("src/Libc.zig");
18pub const LinkContext = @import("src/Link.zig");16pub const LinkContext = @import("src/Link.zig");
1917
...@@ -2188,150 +2186,6 @@ const link_targets = blk: {...@@ -2188,150 +2186,6 @@ const link_targets = blk: {
2188 };2186 };
2189};2187};
21902188
2191/// These are passed to `src/Runner.zig` as `<target>-<cache_mode>-<backend>-<linker>-<pic>` strings.
2192///
2193/// If only one specific test is failing on a target, instead of entirely disabling the target here, you
2194/// can skip the target for that specific test only by adding a line like this to top of the manifest:
2195/// #skip x86_64-linux-selfhosted
2196const RunnerTarget = struct {
2197 target: std.Target.Query,
2198 cache_mode: enum { whole, incremental },
2199 backend: enum { selfhosted, llvm, cbe },
2200 linker: enum { lld, old, new },
2201 pic: enum { nopic, pic, pie },
2202};
2203
2204pub const incremental_matrix: []const RunnerTarget = &.{
2205 // Avoid adding more CBE or LLVM targets without good reason: they're a lot slower than others
2206 // to run due to the output (C source code or LLVM IR) being built non-incrementally (by Clang
2207 // or LLVM). We just have a couple here to make sure that it works.
2208 .{
2209 .target = .{
2210 .cpu_arch = .x86_64,
2211 .os_tag = .linux,
2212 .abi = .musl,
2213 },
2214 .cache_mode = .incremental,
2215 .backend = .cbe,
2216 .linker = .old,
2217 .pic = .nopic,
2218 },
2219 .{
2220 .target = .{
2221 .cpu_arch = .x86_64,
2222 .os_tag = .linux,
2223 .abi = .none,
2224 },
2225 .cache_mode = .incremental,
2226 .backend = .llvm,
2227 .linker = .lld,
2228 .pic = .nopic,
2229 },
2230
2231 .{
2232 .target = .{
2233 .cpu_arch = .x86_64,
2234 .os_tag = .linux,
2235 .abi = .none,
2236 },
2237 .cache_mode = .incremental,
2238 .backend = .selfhosted,
2239 .linker = .new,
2240 .pic = .nopic,
2241 },
2242 .{
2243 .target = .{
2244 .cpu_arch = .x86_64,
2245 .os_tag = .windows,
2246 .abi = .none,
2247 },
2248 .cache_mode = .incremental,
2249 .backend = .selfhosted,
2250 .linker = .old,
2251 .pic = .pic,
2252 },
2253 .{
2254 .target = .{
2255 .cpu_arch = .wasm32,
2256 .os_tag = .wasi,
2257 .abi = .none,
2258 },
2259 .cache_mode = .incremental,
2260 .backend = .selfhosted,
2261 .linker = .old,
2262 .pic = .nopic,
2263 },
2264};
2265
2266pub const debugger_matrix: []const RunnerTarget = &.{
2267 .{
2268 .target = .{
2269 .cpu_arch = .x86_64,
2270 .os_tag = .linux,
2271 .abi = .none,
2272 },
2273 .cache_mode = .whole,
2274 .backend = .selfhosted,
2275 .linker = .old,
2276 .pic = .nopic,
2277 },
2278 .{
2279 .target = .{
2280 .cpu_arch = .x86_64,
2281 .os_tag = .linux,
2282 .abi = .none,
2283 },
2284 .cache_mode = .whole,
2285 .backend = .selfhosted,
2286 .linker = .old,
2287 .pic = .pic,
2288 },
2289 .{
2290 .target = .{
2291 .cpu_arch = .x86_64,
2292 .os_tag = .linux,
2293 .abi = .none,
2294 },
2295 .cache_mode = .whole,
2296 .backend = .selfhosted,
2297 .linker = .new,
2298 .pic = .nopic,
2299 },
2300 .{
2301 .target = .{
2302 .cpu_arch = .x86_64,
2303 .os_tag = .linux,
2304 .abi = .none,
2305 },
2306 .cache_mode = .whole,
2307 .backend = .selfhosted,
2308 .linker = .new,
2309 .pic = .pic,
2310 },
2311 .{
2312 .target = .{
2313 .cpu_arch = .x86_64,
2314 .os_tag = .linux,
2315 .abi = .none,
2316 },
2317 .cache_mode = .incremental,
2318 .backend = .selfhosted,
2319 .linker = .new,
2320 .pic = .nopic,
2321 },
2322 .{
2323 .target = .{
2324 .cpu_arch = .x86_64,
2325 .os_tag = .linux,
2326 .abi = .none,
2327 },
2328 .cache_mode = .incremental,
2329 .backend = .selfhosted,
2330 .linker = .new,
2331 .pic = .pic,
2332 },
2333};
2334
2335pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step {2189pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step {
2336 const step = b.step("test-stack-traces", "Run the stack trace tests");2190 const step = b.step("test-stack-traces", "Run the stack trace tests");
23372191
...@@ -3170,7 +3024,6 @@ pub fn addCases(...@@ -3170,7 +3024,6 @@ pub fn addCases(
3170 b: *std.Build,3024 b: *std.Build,
3171 parent_step: *Step,3025 parent_step: *Step,
3172 case_test_options: @import("src/Cases.zig").CaseTestOptions,3026 case_test_options: @import("src/Cases.zig").CaseTestOptions,
3173 build_options: @import("cases.zig").BuildOptions,
3174) !void {3027) !void {
3175 const arena = b.allocator;3028 const arena = b.allocator;
3176 const gpa = b.allocator;3029 const gpa = b.allocator;
...@@ -3184,7 +3037,7 @@ pub fn addCases(...@@ -3184,7 +3037,7 @@ pub fn addCases(
3184 defer dir.close(io);3037 defer dir.close(io);
31853038
3186 cases.addFromDir(dir, "test/cases", b);3039 cases.addFromDir(dir, "test/cases", b);
3187 try @import("cases.zig").addCases(&cases, build_options, b);3040 try @import("cases.zig").addCases(&cases, b);
31883041
3189 cases.lowerToBuildSteps(3042 cases.lowerToBuildSteps(
3190 b,3043 b,
...@@ -3193,6 +3046,7 @@ pub fn addCases(...@@ -3193,6 +3046,7 @@ pub fn addCases(
3193 );3046 );
3194}3047}
31953048
3049pub const RunnerTarget = @import("Runner.zig").Target;
3196pub const RunnerOptions = struct {3050pub const RunnerOptions = struct {
3197 test_filters: []const []const u8,3051 test_filters: []const []const u8,
3198 test_target_filters: []const []const u8,3052 test_target_filters: []const []const u8,
...@@ -3205,10 +3059,13 @@ pub const RunnerOptions = struct {...@@ -3205,10 +3059,13 @@ pub const RunnerOptions = struct {
3205 skip_darwin: bool,3059 skip_darwin: bool,
3206 skip_linux: bool,3060 skip_linux: bool,
3207 skip_llvm: bool,3061 skip_llvm: bool,
3062 llvm_has_m68k: bool,
3063 llvm_has_csky: bool,
3064 llvm_has_arc: bool,
3065 llvm_has_xtensa: bool,
3208 gdb: ?[]const u8,3066 gdb: ?[]const u8,
3209 lldb: ?[]const u8,3067 lldb: ?[]const u8,
3210};3068};
3211
3212pub fn addRunnerTests(3069pub fn addRunnerTests(
3213 b: *std.Build,3070 b: *std.Build,
3214 runner: *std.Build.Step.Compile,3071 runner: *std.Build.Step.Compile,
...@@ -3224,21 +3081,24 @@ pub fn addRunnerTests(...@@ -3224,21 +3081,24 @@ pub fn addRunnerTests(
3224 defer tests_dir.close(b.graph.io);3081 defer tests_dir.close(b.graph.io);
3225 var test_it = tests_dir.iterate();3082 var test_it = tests_dir.iterate();
3226 while (try test_it.next(b.graph.io)) |@"test"| {3083 while (try test_it.next(b.graph.io)) |@"test"| {
3227 for (options.test_filters) |filter| {
3228 if (std.mem.find(u8, @"test".name, filter) != null) break;
3229 } else if (options.test_filters.len > 0) continue;
3230
3231 const test_path = tests_path.path(b, @"test".name);
3232 switch (@"test".kind) {3084 switch (@"test".kind) {
3233 else => continue,3085 else => continue,
3234 .file => if (isEditorFileName(@"test".name)) continue,3086 .file => {
3087 if (std.mem.eql(u8, @"test".name, "matrix.zon")) continue;
3088 if (isEditorFileName(@"test".name)) continue;
3089 },
3235 .directory => {},3090 .directory => {},
3236 }3091 }
32373092
3093 for (options.test_filters) |filter| {
3094 if (std.mem.find(u8, @"test".name, filter) != null) break;
3095 } else if (options.test_filters.len > 0) continue;
3096
3238 const run = b.addRunArtifact(runner);3097 const run = b.addRunArtifact(runner);
3239 run.setName(@"test".name);3098 run.setName(@"test".name);
3240 run.enableProtocolMode();3099 run.enableProtocolMode();
32413100
3101 const test_path = tests_path.path(b, @"test".name);
3242 switch (@"test".kind) {3102 switch (@"test".kind) {
3243 else => continue,3103 else => continue,
3244 .file => run.addFileArg(test_path),3104 .file => run.addFileArg(test_path),
...@@ -3249,7 +3109,7 @@ pub fn addRunnerTests(...@@ -3249,7 +3109,7 @@ pub fn addRunnerTests(
3249 _ = run.addPrefixedOutputDirectoryArg("--src=", "src");3109 _ = run.addPrefixedOutputDirectoryArg("--src=", "src");
32503110
3251 for (matrix) |test_target| {3111 for (matrix) |test_target| {
3252 const resolved_target = b.resolveTargetQuery(test_target.target);3112 const resolved_target = b.resolveTargetQuery(test_target.toQuery());
32533113
3254 if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result))3114 if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result))
3255 continue;3115 continue;
...@@ -3265,15 +3125,18 @@ pub fn addRunnerTests(...@@ -3265,15 +3125,18 @@ pub fn addRunnerTests(
3265 if (options.skip_darwin and target.os.tag.isDarwin()) continue;3125 if (options.skip_darwin and target.os.tag.isDarwin()) continue;
3266 if (options.skip_linux and target.os.tag == .linux) continue;3126 if (options.skip_linux and target.os.tag == .linux) continue;
32673127
3268 if (options.skip_llvm and test_target.backend == .llvm) continue;3128 if (test_target.backend == .llvm) {
3129 if (options.skip_llvm) continue;
3130 switch (target.cpu.arch) {
3131 else => {},
3132 .m68k => if (!options.llvm_has_m68k) continue,
3133 .csky => if (!options.llvm_has_csky) continue,
3134 .arc => if (!options.llvm_has_arc) continue,
3135 .xtensa => if (!options.llvm_has_xtensa) continue,
3136 }
3137 }
32693138
3270 const target_str = b.fmt("{s}-{t}-{t}-{t}-{t}", .{3139 const target_str = b.fmt("{f}", .{test_target});
3271 resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"),
3272 test_target.cache_mode,
3273 test_target.backend,
3274 test_target.linker,
3275 test_target.pic,
3276 });
32773140
3278 for (options.test_target_filters) |filter| {3141 for (options.test_target_filters) |filter| {
3279 if (std.mem.find(u8, target_str, filter) != null) break;3142 if (std.mem.find(u8, target_str, filter) != null) break;
...@@ -3303,25 +3166,6 @@ fn isEditorFileName(name: []const u8) bool {...@@ -3303,25 +3166,6 @@ fn isEditorFileName(name: []const u8) bool {
3303 std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp");3166 std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp");
3304}3167}
33053168
3306pub fn addLlvmIrTests(b: *std.Build, options: LlvmIrContext.Options) ?*Step {
3307 const step = b.step("test-llvm-ir", "Run the LLVM IR tests");
3308
3309 if (!options.enable_llvm) {
3310 step.dependOn(&b.addFail("test-llvm-ir requires -Denable-llvm").step);
3311 return null;
3312 }
3313
3314 var context: LlvmIrContext = .{
3315 .b = b,
3316 .options = options,
3317 .root_step = step,
3318 };
3319
3320 llvm_ir.addCases(&context);
3321
3322 return step;
3323}
3324
3325const libc_test_nsz_targets: []const std.Target.Query = &.{3169const libc_test_nsz_targets: []const std.Target.Query = &.{
3326 .{3170 .{
3327 .cpu_arch = .arm,3171 .cpu_arch = .arm,