| author | |
| committer | |
| log | 465b2d51d1a54761b3517eef93ccffcf7df44233 |
| tree | 098598c0323c1244904e088cae984a1e5c0458b6 |
| parent | ed136f830665c38af3d0d4beb1177584cb6d40d7 |
| parent | 6148ec9f438e38c94ce95d5802103c7c078acff0 |
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 | 330 | src/Air/Legalize.zig |
| 331 | 331 | src/Air/Liveness.zig |
| 332 | 332 | src/Air/Liveness/Verify.zig |
| 333 | src/Air/print.zig | |
| 333 | src/Air/Print.zig | |
| 334 | 334 | src/Builtin.zig |
| 335 | 335 | src/Compilation.zig |
| 336 | 336 | src/Compilation/Config.zig |
bootstrap.c+1-1| ... | ... | @@ -179,7 +179,7 @@ int main(int argc, char **argv) { |
| 179 | 179 | "pub const version: [:0]const u8 = \"%s\";\n" |
| 180 | 180 | "pub const semver = @import(\"std\").SemanticVersion.parse(version) catch unreachable;\n" |
| 181 | 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 | 183 | "pub const enable_link_snapshots = false;\n" |
| 184 | 184 | "pub const enable_tracy = false;\n" |
| 185 | 185 | "pub const value_tracing = false;\n" |
build.zig+32-27| ... | ... | @@ -25,6 +25,10 @@ pub fn build(b: *std.Build) !void { |
| 25 | 25 | }, |
| 26 | 26 | }); |
| 27 | 27 | const optimize = b.standardOptimizeOption(.{}); |
| 28 | const is_debug = switch (optimize) { | |
| 29 | .debug => true, | |
| 30 | .safe, .fast, .small => false, | |
| 31 | }; | |
| 28 | 32 | |
| 29 | 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 | 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 | 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; |
| 206 | 210 | |
| 207 | 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); | |
| 209 | if (optimize != .debug) break :blk 0; | |
| 210 | break :blk 4; | |
| 212 | if (strip == true) break :blk 0; | |
| 213 | if (is_debug) break :blk 4; | |
| 214 | break :blk 0; | |
| 211 | 215 | }; |
| 212 | 216 | |
| 213 | 217 | const exe = addCompilerStep(b, .{ |
| ... | ... | @@ -255,9 +259,15 @@ pub fn build(b: *std.Build) !void { |
| 255 | 259 | exe.root_module.link_libc = true; |
| 256 | 260 | } |
| 257 | 261 | |
| 258 | const is_debug = optimize == .debug; | |
| 259 | 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 | }; | |
| 261 | 271 | |
| 262 | 272 | const opt_version_string = b.option([]const u8, "version-string", "Override Zig version string. Default is to find out with git."); |
| 263 | 273 | const version_slice = if (opt_version_string) |version| version else v: { |
| ... | ... | @@ -398,7 +408,7 @@ pub fn build(b: *std.Build) !void { |
| 398 | 408 | exe_options.addOption(std.SemanticVersion, "semver", semver); |
| 399 | 409 | |
| 400 | 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 | 412 | exe_options.addOption(bool, "enable_tracy", tracy != null); |
| 403 | 413 | exe_options.addOption(bool, "enable_tracy_callstack", tracy_callstack); |
| 404 | 414 | exe_options.addOption(bool, "enable_tracy_allocation", tracy_allocation); |
| ... | ... | @@ -494,12 +504,6 @@ pub fn build(b: *std.Build) !void { |
| 494 | 504 | .skip_linux = skip_linux, |
| 495 | 505 | .skip_llvm = skip_llvm, |
| 496 | 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 | 508 | test_step.dependOn(test_cases_step); |
| 505 | 509 | |
| ... | ... | @@ -702,11 +706,6 @@ pub fn build(b: *std.Build) !void { |
| 702 | 706 | .skip_libc = skip_libc, |
| 703 | 707 | })); |
| 704 | 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); | |
| 710 | 709 | |
| 711 | 710 | try addWasiUpdateStep(b, version); |
| 712 | 711 | |
| ... | ... | @@ -783,7 +782,7 @@ pub fn build(b: *std.Build) !void { |
| 783 | 782 | const runner = b.addExecutable(.{ |
| 784 | 783 | .name = "runner", |
| 785 | 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 | 786 | .target = b.graph.host, |
| 788 | 787 | }), |
| 789 | 788 | }); |
| ... | ... | @@ -799,21 +798,27 @@ pub fn build(b: *std.Build) !void { |
| 799 | 798 | .skip_darwin = skip_darwin, |
| 800 | 799 | .skip_linux = skip_linux, |
| 801 | 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 | 805 | .gdb = b.option([]const u8, "gdb", "path to gdb binary"), |
| 803 | 806 | .lldb = b.option([]const u8, "lldb", "path to lldb binary"), |
| 804 | 807 | }; |
| 805 | 808 | |
| 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 | 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 | 817 | test_step.dependOn(test_incremental_step); |
| 809 | 818 | |
| 810 | const test_debugger_step = b.step("test-debugger", "Run the debugger tests"); | |
| 811 | if (runner_opts.gdb == null and runner_opts.lldb == null) { | |
| 812 | test_debugger_step.dependOn(&b.addFail("test-debugger requires -Dgdb and/or -Dlldb").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 | } | |
| 819 | const test_llvm_step = b.step("test-llvm", "Run the LLVM IR tests"); | |
| 820 | try tests.addRunnerTests(b, runner, test_llvm_step, "test/llvm", @import("test/llvm/matrix.zon"), runner_opts); | |
| 821 | test_step.dependOn(test_llvm_step); | |
| 817 | 822 | } |
| 818 | 823 | |
| 819 | 824 | 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 | 842 | exe_options.addOption([:0]const u8, "version", version); |
| 838 | 843 | exe_options.addOption(std.SemanticVersion, "semver", semver); |
| 839 | 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 | 846 | exe_options.addOption(bool, "enable_tracy", false); |
| 842 | 847 | exe_options.addOption(bool, "enable_tracy_callstack", false); |
| 843 | 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 | 509 | } else if (mem.eql(u8, arg, "--libc-runtimes") or mem.eql(u8, arg, "--glibc-runtimes")) { |
| 510 | 510 | // --glibc-runtimes was the old name of the flag; kept for compatibility for now. |
| 511 | 511 | graph.libc_runtimes_dir = nextArgOrFatal(args, &arg_i); |
| 512 | } else if (mem.eql(u8, arg, "--verbose-air")) { | |
| 513 | graph.verbose_air = true; | |
| 514 | 512 | } else if (mem.eql(u8, arg, "--verbose-cc")) { |
| 515 | 513 | graph.verbose_cc = true; |
| 516 | 514 | } else if (mem.eql(u8, arg, "--verbose-link")) { |
| 517 | 515 | graph.verbose_link = true; |
| 518 | } else if (mem.eql(u8, arg, "--verbose-llvm-ir")) { | |
| 519 | graph.verbose_llvm_ir = true; | |
| 520 | 516 | } else if (mem.eql(u8, arg, "--watch")) { |
| 521 | 517 | watch_flag = true; |
| 522 | 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 | 32 | debug_incremental: bool = false, |
| 33 | 33 | fuzzing: bool = false, |
| 34 | 34 | verbose: bool = false, |
| 35 | verbose_air: bool = false, | |
| 36 | 35 | verbose_cc: bool = false, |
| 37 | 36 | verbose_link: bool = false, |
| 38 | verbose_llvm_cpu_features: bool = false, | |
| 39 | verbose_llvm_ir: bool = false, | |
| 40 | 37 | libc_file: ?[]const u8 = null, |
| 41 | 38 | /// What does this do? Nobody bothered to document it, and I think it's a |
| 42 | 39 | /// 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 | 494 | }; |
| 495 | 495 | switch (result) { |
| 496 | 496 | .success => {}, |
| 497 | .failure => |err| try p.appendStrLitError(err, token, bytes, offset), | |
| 498 | } | |
| 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 | }, | |
| 497 | .failure => |err| try p.appendErrorOff(token, @intCast(offset + err.offset()), "{f}", .{ | |
| 498 | err.fmt(bytes[offset..]), | |
| 499 | }), | |
| 586 | 500 | } |
| 587 | 501 | } |
| 588 | 502 |
lib/compiler/Maker/ScannedConfig.zig+2-6| ... | ... | @@ -351,6 +351,8 @@ const general_usage = |
| 351 | 351 | \\ preferred optimization mode: fast, safe, small |
| 352 | 352 | \\ |
| 353 | 353 | \\ --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 | 356 | \\ --color [auto|off|on] Enable or disable colored error messages |
| 355 | 357 | \\ --error-style [style] Control how build errors are printed |
| 356 | 358 | \\ verbose (Default) Report errors with full context |
| ... | ... | @@ -417,11 +419,5 @@ const general_usage = |
| 417 | 419 | \\ none (default) No build ID |
| 418 | 420 | \\ --debug-log [scope] Enable debugging the compiler |
| 419 | 421 | \\ --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 | 608 | |
| 609 | 609 | try addBool(gpa, zig_args, "--debug-compile-errors", graph.debug_compile_errors); |
| 610 | 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 | 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 | 613 | try addBool(gpa, zig_args, "--time-report", graph.time_report); |
| 617 | 614 | |
| 618 | 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 | 795 | multi_reader: *Io.File.MultiReader, |
| 796 | 796 | opt_metadata: *?TestMetadata, |
| 797 | 797 | results: *Step.TestResults, |
| 798 | eb_wip: *std.zig.ErrorBundle.Wip, | |
| 798 | 799 | ) !union(enum) { |
| 799 | 800 | write_failed: anyerror, |
| 800 | 801 | no_poll: struct { |
| ... | ... | @@ -885,7 +886,7 @@ fn waitZigTest( |
| 885 | 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 | 890 | .test_metadata => { |
| 890 | 891 | // `metadata` would only be populated if we'd already seen a `test_metadata`, but we |
| 891 | 892 | // only request it once (and importantly, we don't re-request it if we kill and |
| ... | ... | @@ -1573,6 +1574,9 @@ fn evalZigTest( |
| 1573 | 1574 | }; |
| 1574 | 1575 | var test_metadata: ?TestMetadata = null; |
| 1575 | 1576 | |
| 1577 | var eb_wip: std.zig.ErrorBundle.Wip = try .init(gpa); | |
| 1578 | defer eb_wip.deinit(); | |
| 1579 | ||
| 1576 | 1580 | while (true) { |
| 1577 | 1581 | var child = try process.spawn(io, spawn_options); |
| 1578 | 1582 | var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined; |
| ... | ... | @@ -1602,6 +1606,7 @@ fn evalZigTest( |
| 1602 | 1606 | &multi_reader, |
| 1603 | 1607 | &test_metadata, |
| 1604 | 1608 | &test_results, |
| 1609 | &eb_wip, | |
| 1605 | 1610 | )) { |
| 1606 | 1611 | .write_failed => |err| { |
| 1607 | 1612 | // The runner unexpectedly closed a stdio pipe, which means a crash. Make sure we've captured |
| ... | ... | @@ -1687,6 +1692,7 @@ fn evalZigTest( |
| 1687 | 1692 | } |
| 1688 | 1693 | } |
| 1689 | 1694 | } |
| 1695 | step.result_error_bundle = try eb_wip.toOwnedBundle(""); | |
| 1690 | 1696 | return; |
| 1691 | 1697 | }, |
| 1692 | 1698 | .timeout => |timeout| { |
lib/compiler/aro/aro/Driver.zig+1-1| ... | ... | @@ -927,7 +927,7 @@ pub fn parseArgs( |
| 927 | 927 | break :debug switch (d.comp.target.ofmt) { |
| 928 | 928 | .elf, .macho, .wasm => .{ .dwarf = .@"32" }, |
| 929 | 929 | .coff => .code_view, |
| 930 | .c => switch (d.comp.target.os.tag) { | |
| 930 | .c, .llvmbc, .llvmir => switch (d.comp.target.os.tag) { | |
| 931 | 931 | .windows, .uefi => .code_view, |
| 932 | 932 | else => .{ .dwarf = .@"32" }, |
| 933 | 933 | }, |
lib/lldb/pretty_printers.py+100-51| ... | ... | @@ -13,34 +13,73 @@ page_size = 1 << 12 |
| 13 | 13 | |
| 14 | 14 | def log2_int(i): return i.bit_length() - 1 |
| 15 | 15 | |
| 16 | def create_struct(parent, name, struct_type, inits): | |
| 17 | struct_bytes, struct_data = bytearray(struct_type.size), lldb.SBData() | |
| 18 | for field in struct_type.fields: | |
| 19 | field_size = field.type.size | |
| 20 | field_init = inits[field.name] | |
| 21 | if isinstance(field_init, int): | |
| 22 | match struct_data.byte_order: | |
| 23 | case lldb.eByteOrderLittle: | |
| 24 | byte_order = 'little' | |
| 25 | case lldb.eByteOrderBig: | |
| 26 | byte_order = 'big' | |
| 27 | field_bytes = field_init.to_bytes(field_size, byte_order, signed=field.type.GetTypeFlags() & lldb.eTypeIsSigned != 0) | |
| 28 | elif isinstance(field_init, lldb.SBValue): | |
| 29 | field_bytes = field_init.data.uint8 | |
| 30 | else: return | |
| 31 | match struct_data.byte_order: | |
| 16 | class ValueInit: | |
| 17 | def __init__(self, value: lldb.SBValue): self.value = value | |
| 18 | def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes: | |
| 19 | return self.value.data.uint8 | |
| 20 | def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue: | |
| 21 | return self.value.Clone(name) | |
| 22 | ||
| 23 | class FromBytes(ValueInit): | |
| 24 | def __init__(self, value_bytes: bytes): self.value_bytes = value_bytes | |
| 25 | def toBytes(self, parent: lldb.SBValue, value_type: lldb.SBType) -> bytes: return self.value_bytes | |
| 26 | def create(self, parent: lldb.SBValue, name: str, value_type: lldb.SBType) -> lldb.SBValue: | |
| 27 | data = lldb.SBData() | |
| 28 | error = lldb.SBError() | |
| 29 | value_bytes = self.toBytes(parent, value_type); | |
| 30 | target = parent.target | |
| 31 | data.SetData(error, value_bytes, target.byte_order, target.addr_size) | |
| 32 | return parent.CreateValueFromData(name, data, value_type) | |
| 33 | ||
| 34 | class 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 | 41 | case lldb.eByteOrderLittle: |
| 33 | field_bytes = field_bytes[:field_size] | |
| 34 | field_start = field.byte_offset | |
| 35 | struct_bytes[field_start:field_start + len(field_bytes)] = field_bytes | |
| 42 | byte_order = 'little' | |
| 36 | 43 | case lldb.eByteOrderBig: |
| 37 | field_bytes = field_bytes[-field_size:] | |
| 38 | field_end = field.byte_offset + field_size | |
| 39 | struct_bytes[field_end - len(field_bytes):field_end] = field_bytes | |
| 40 | struct_data.SetData(lldb.SBError(), struct_bytes, struct_data.byte_order, struct_data.GetAddressByteSize()) | |
| 41 | return parent.CreateValueFromData(name, struct_data, struct_type) | |
| 42 | ||
| 43 | # Define Zig Language | |
| 44 | byte_order = 'big' | |
| 45 | return self.int_value.to_bytes(int_type.size, byte_order, signed=int_is_signed) | |
| 46 | ||
| 47 | class FromBackingInt(FromBytes): | |
| 48 | def __init__(self, field_value: int): self.field_value = field_value | |
| 49 | def fieldValue(self, enum_type: lldb.SBType) -> int: return self.field_value | |
| 50 | 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 | ||
| 55 | class 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 | ||
| 63 | class 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 | ||
| 71 | class 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) | |
| 44 | 83 | |
| 45 | 84 | zig_keywords = { |
| 46 | 85 | 'addrspace', |
| ... | ... | @@ -204,7 +243,7 @@ class zig_TaggedUnion_SynthProvider: |
| 204 | 243 | except: return -1 |
| 205 | 244 | def get_child_at_index(self, index): return (self.tag, self.payload)[index] if index in range(2) else None |
| 206 | 245 | |
| 207 | # Define Zig Standard Library | |
| 246 | # Define Zig Standard Library (for programs compiled with the llvm backend) | |
| 208 | 247 | |
| 209 | 248 | class std_MultiArrayList_SynthProvider: |
| 210 | 249 | def __init__(self, value, _=None): self.value = value |
| ... | ... | @@ -331,7 +370,7 @@ class std_Entry_SynthProvider: |
| 331 | 370 | def get_child_index(self, name): return self.indices.get(name) |
| 332 | 371 | def get_child_at_index(self, index): return self.children[index].deref if index in range(len(self.children)) else None |
| 333 | 372 | |
| 334 | # Define Zig Compiler | |
| 373 | # Define Zig Compiler (compiled with the llvm backend) | |
| 335 | 374 | |
| 336 | 375 | class TagAndPayload_SynthProvider: |
| 337 | 376 | def __init__(self, value, _=None): self.value = value |
| ... | ... | @@ -435,8 +474,9 @@ class InternPool_Index_SynthProvider: |
| 435 | 474 | def __init__(self, value, _=None): self.value = value |
| 436 | 475 | def update(self): |
| 437 | 476 | try: |
| 477 | target = self.value.target | |
| 438 | 478 | 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 | 480 | ptr_self_type, ptr_tag_to_encoding_map_type = helper.function.type.GetFunctionArgumentTypes() |
| 441 | 481 | if ptr_self_type.GetPointeeType() == index_type: break |
| 442 | 482 | else: return |
| ... | ... | @@ -465,7 +505,7 @@ class InternPool_Index_SynthProvider: |
| 465 | 505 | for trailing_field in encoding_field.type.fields: |
| 466 | 506 | trailing_data.Append(extra.GetChildAtIndex(extra_index).address_of.data) |
| 467 | 507 | 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 | 509 | extra_index += trailing_len |
| 470 | 510 | self.trailing = self.data.CreateValueFromData('trailing', trailing_data, encoding_field.type) |
| 471 | 511 | else: |
| ... | ... | @@ -685,8 +725,18 @@ value_tag_handlers = { |
| 685 | 725 | class root_InternPool_Local_List_SynthProvider: |
| 686 | 726 | def __init__(self, value, _=None): self.value = value |
| 687 | 727 | def update(self): |
| 688 | capacity = self.value.EvaluateExpression('@as(*@This().Header, @alignCast(@ptrCast(@this().bytes - @This().bytes_offset))).capacity') | |
| 689 | self.view = create_struct(self.value, '.view', self.value.type.FindDirectNestedType('View'), { 'bytes': self.value.GetChildMemberWithName('bytes'), 'len': capacity, 'capacity': capacity }).GetNonSyntheticValue() | |
| 728 | capacity = IntLiteral(self.value.EvaluateExpression( | |
| 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 | 740 | def has_children(self): return True |
| 691 | 741 | def num_children(self): return 1 |
| 692 | 742 | def get_child_index(self, name): |
| ... | ... | @@ -719,7 +769,10 @@ class root_InternPool_Index_SynthProvider: |
| 719 | 769 | unwrapped_type = self.value.type.FindDirectNestedType('Unwrapped') |
| 720 | 770 | ip = self.value.CreateValueFromType(unwrapped_type).GetChildMemberWithName('debug_state').GetChildMemberWithName('intern_pool').GetNonSyntheticValue().GetChildMemberWithName('?') |
| 721 | 771 | 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 | 776 | def has_children(self): return True |
| 724 | 777 | def num_children(self): return 0 |
| 725 | 778 | def get_child_index(self, name): |
| ... | ... | @@ -732,6 +785,7 @@ class root_InternPool_Index_SynthProvider: |
| 732 | 785 | class root_InternPool_Index_Unwrapped_SynthProvider: |
| 733 | 786 | def __init__(self, value, _=None): self.value = value |
| 734 | 787 | def update(self): |
| 788 | target = self.value.target | |
| 735 | 789 | self.tag, self.index, self.data, self.payload, self.trailing = None, None, None, None, None |
| 736 | 790 | index = self.value.GetChildMemberWithName('index') |
| 737 | 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 | 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 | 797 | if encoding_index: |
| 744 | 798 | index_type = encoding_index.GetValueAsType() |
| 745 | index_bytes, index_data = index.data.uint8, lldb.SBData() | |
| 746 | match index_data.byte_order: | |
| 799 | index_bytes = index.data.uint8 | |
| 800 | match target.byte_order: | |
| 747 | 801 | case lldb.eByteOrderLittle: |
| 748 | 802 | index_bytes = bytes(index_bytes[:index_type.size]) |
| 749 | 803 | case lldb.eByteOrderBig: |
| 750 | 804 | index_bytes = bytes(index_bytes[-index_type.size:]) |
| 751 | index_data.SetData(lldb.SBError(), index_bytes, index_data.byte_order, index_data.GetAddressByteSize()) | |
| 752 | self.index = self.value.CreateValueFromData('.index', index_data, index_type) | |
| 805 | self.index = FromBytes(index_bytes).create(self.value, '.index', index_type) | |
| 753 | 806 | elif encoding_data: |
| 754 | 807 | data_type = encoding_data.GetValueAsType() |
| 755 | data_bytes, data_data = item_data.data.uint8, lldb.SBData() | |
| 756 | match data_data.byte_order: | |
| 808 | data_bytes = item_data.data.uint8 | |
| 809 | match target.byte_order: | |
| 757 | 810 | case lldb.eByteOrderLittle: |
| 758 | 811 | data_bytes = bytes(data_bytes[:data_type.size]) |
| 759 | 812 | case lldb.eByteOrderBig: |
| 760 | 813 | data_bytes = bytes(data_bytes[-data_type.size:]) |
| 761 | data_data.SetData(lldb.SBError(), data_bytes, data_data.byte_order, data_data.GetAddressByteSize()) | |
| 762 | self.data = self.value.CreateValueFromData('.data', data_data, data_type) | |
| 814 | self.data = FromBytes(data_bytes).create(self.value, '.data', data_type) | |
| 763 | 815 | elif encoding_payload: |
| 764 | 816 | extra = shared.GetChildMemberWithName('extra').GetChildMemberWithName('view').GetChildMemberWithName('0') |
| 765 | 817 | extra_index = item_data.unsigned |
| 766 | 818 | payload_type = encoding_payload.GetValueAsType() |
| 767 | 819 | payload_fields = dict() |
| 768 | 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 | 822 | 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 | 824 | if encoding_trailing and encoding_config: |
| 773 | 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 | 827 | def eval_config(config_name): |
| 776 | 828 | expr = encoding_config.GetChildMemberWithName(config_name).value.removeprefix('.').removeprefix('@"').removesuffix('"').replace(r'\"', '"') |
| 777 | 829 | if 'payload.' in expr: |
| ... | ... | @@ -780,13 +832,11 @@ class root_InternPool_Index_Unwrapped_SynthProvider: |
| 780 | 832 | field_type, field_byte_offset = trailing_type, 0 |
| 781 | 833 | expr_parts = expr.split('.') |
| 782 | 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 | 836 | field_type = field.type |
| 785 | 837 | field_byte_offset += field.byte_offset |
| 786 | field_data = lldb.SBData() | |
| 787 | 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()) | |
| 789 | return self.value.CreateValueFromData('.%s' % expr_parts[-1], field_data, field_type) | |
| 839 | return FromBytes(field_bytes).create(self.value, '.%s' % expr_parts[-1], field_type) | |
| 790 | 840 | else: |
| 791 | 841 | return self.value.frame.EvaluateExpression(expr) |
| 792 | 842 | for trailing_field in trailing_type.fields: |
| ... | ... | @@ -812,7 +862,7 @@ class root_InternPool_Index_Unwrapped_SynthProvider: |
| 812 | 862 | trailing_bytes[ptr_field_byte_offset:ptr_field_byte_offset + ptr_field.type.size] = extra.child[extra_index].address_of.data.uint8 |
| 813 | 863 | len_field_value = eval_config('%s.len' % trailing_field_name) |
| 814 | 864 | len_field_size = len_field.type.size |
| 815 | match trailing_data.byte_order: | |
| 865 | match target.byte_order: | |
| 816 | 866 | case lldb.eByteOrderLittle: |
| 817 | 867 | len_field_bytes = len_field_value.data.uint8[:len_field_size] |
| 818 | 868 | 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 | 877 | trailing_bytes[trailing_field_byte_offset + offset:trailing_field_byte_offset + offset + 4] = extra.child[extra_index].data.uint8 |
| 828 | 878 | extra_index += 1 |
| 829 | 879 | break |
| 830 | trailing_data.SetData(lldb.SBError(), trailing_bytes, trailing_data.byte_order, trailing_data.GetAddressByteSize()) | |
| 831 | self.trailing = self.value.CreateValueFromData('.trailing', trailing_data, trailing_type) | |
| 880 | self.trailing = FromBytes(trailing_bytes).create(self.value, '.trailing', trailing_type) | |
| 832 | 881 | def has_children(self): return True |
| 833 | 882 | def num_children(self): return 1 + ((self.index or self.data or self.payload) is not None) + (self.trailing is not None) |
| 834 | 883 | def get_child_index(self, name): |
lib/std/Build/Configuration.zig+2| ... | ... | @@ -2519,6 +2519,8 @@ pub const TargetQuery = struct { |
| 2519 | 2519 | coff, |
| 2520 | 2520 | elf, |
| 2521 | 2521 | hex, |
| 2522 | llvmbc, | |
| 2523 | llvmir, | |
| 2522 | 2524 | macho, |
| 2523 | 2525 | plan9, |
| 2524 | 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 | 7191 | return n; |
| 7192 | 7192 | }, |
| 7193 | 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 | 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 | 7197 | const syscall: Syscall = try .start(); |
| 7198 | 7198 | while (true) { |
| 7199 | 7199 | const rc = posix.system.readlink(proc_path, out_buffer.ptr, out_buffer.len); |
| ... | ... | @@ -7266,27 +7266,32 @@ fn fileHardLink( |
| 7266 | 7266 | new_sub_path: []const u8, |
| 7267 | 7267 | options: File.HardLinkOptions, |
| 7268 | 7268 | ) File.HardLinkError!void { |
| 7269 | _ = userdata; | |
| 7270 | if (native_os != .linux) return error.OperationUnsupported; | |
| 7269 | const t: *Threaded = @ptrCast(@alignCast(userdata)); | |
| 7270 | _ = t; | |
| 7271 | 7271 | |
| 7272 | 7272 | var new_path_buffer: [posix.PATH_MAX]u8 = undefined; |
| 7273 | 7273 | const new_sub_path_posix = try pathToPosix(new_sub_path, &new_path_buffer); |
| 7274 | 7274 | |
| 7275 | const flags: u32 = if (options.follow_symlinks) | |
| 7276 | posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH | |
| 7277 | else | |
| 7278 | posix.AT.EMPTY_PATH; | |
| 7275 | switch (native_os) { | |
| 7276 | else => return error.OperationUnsupported, | |
| 7277 | .freebsd, .linux => { | |
| 7278 | const flags: u32 = if (options.follow_symlinks) | |
| 7279 | posix.AT.SYMLINK_FOLLOW | posix.AT.EMPTY_PATH | |
| 7280 | else | |
| 7281 | posix.AT.EMPTY_PATH; | |
| 7279 | 7282 | |
| 7280 | return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) { | |
| 7281 | error.FileNotFound => { | |
| 7282 | if (options.follow_symlinks) return error.FileNotFound; | |
| 7283 | var proc_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; | |
| 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); | |
| 7283 | return linkat(file.handle, "", new_dir.handle, new_sub_path_posix, flags) catch |err| switch (err) { | |
| 7284 | error.FileNotFound => {}, | |
| 7285 | else => |e| return e, | |
| 7286 | }; | |
| 7287 | 7287 | }, |
| 7288 | else => |e| return e, | |
| 7289 | }; | |
| 7288 | .netbsd, .openbsd => {}, | |
| 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 | } |
| 7291 | 7296 | |
| 7292 | 7297 | fn linkat( |
| ... | ... | @@ -8732,12 +8737,12 @@ fn fchmodatFallback( |
| 8732 | 8737 | ) Dir.SetFilePermissionsError!void { |
| 8733 | 8738 | comptime assert(native_os == .linux); |
| 8734 | 8739 | |
| 8735 | // Fallback to changing permissions using procfs: | |
| 8740 | // Fallback to changing permissions using devfs: | |
| 8736 | 8741 | // |
| 8737 | 8742 | // 1. Open `path` as a `PATH` descriptor. |
| 8738 | 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}`. | |
| 8740 | // 4. Pass the procfs path to `chmod` with the `mode`. | |
| 8744 | // 3. Generate the devfs reference to the fd via `/dev/fd/{fd}`. | |
| 8745 | // 4. Pass the devfs path to `chmod` with the `mode`. | |
| 8741 | 8746 | const path_fd: posix.fd_t = fd: { |
| 8742 | 8747 | const syscall: Syscall = try .start(); |
| 8743 | 8748 | while (true) { |
| ... | ... | @@ -8808,11 +8813,11 @@ fn fchmodatFallback( |
| 8808 | 8813 | if ((path_mode & posix.S.IFMT) == posix.S.IFLNK) |
| 8809 | 8814 | return error.OperationUnsupported; |
| 8810 | 8815 | |
| 8811 | var procfs_buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined; | |
| 8812 | const proc_path = std.mem.printSentinel(&procfs_buf, "/proc/self/fd/{d}", .{path_fd}, 0) catch unreachable; | |
| 8816 | var dev_buf: [std.fmt.count("/dev/fd/{d}\x00", .{std.math.minInt(posix.fd_t)})]u8 = undefined; | |
| 8817 | const dev_path = std.mem.printSentinel(&dev_buf, "/dev/fd/{d}", .{path_fd}, 0) catch unreachable; | |
| 8813 | 8818 | const syscall: Syscall = try .start(); |
| 8814 | 8819 | while (true) { |
| 8815 | switch (posix.errno(posix.system.chmod(proc_path, mode))) { | |
| 8820 | switch (posix.errno(posix.system.chmod(dev_path, mode))) { | |
| 8816 | 8821 | .SUCCESS => return syscall.finish(), |
| 8817 | 8822 | .INTR => { |
| 8818 | 8823 | try syscall.checkCancel(); |
| ... | ... | @@ -8821,7 +8826,7 @@ fn fchmodatFallback( |
| 8821 | 8826 | else => |e| { |
| 8822 | 8827 | syscall.finish(); |
| 8823 | 8828 | switch (e) { |
| 8824 | .NOENT => return error.OperationUnsupported, // procfs not mounted. | |
| 8829 | .NOENT => return error.OperationUnsupported, // devfs not mounted. | |
| 8825 | 8830 | .BADF => |err| return errnoBug(err), |
| 8826 | 8831 | .FAULT => |err| return errnoBug(err), |
| 8827 | 8832 | .INVAL => |err| return errnoBug(err), |
| ... | ... | @@ -17446,9 +17451,6 @@ pub fn posixExecveat( |
| 17446 | 17451 | ) process.ReplaceError { |
| 17447 | 17452 | try Thread.checkCancel(); |
| 17448 | 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 | 17454 | if (comptime native_os == .linux and (!builtin.link_libc or |
| 17453 | 17455 | (builtin.target.isGnuLibC() and builtin.target.os.version_range.linux.glibc.order( |
| 17454 | 17456 | .{ .major = 2, .minor = 34, .patch = 0 }, |
| ... | ... | @@ -17462,34 +17464,57 @@ pub fn posixExecveat( |
| 17462 | 17464 | .NOSYS => {}, |
| 17463 | 17465 | } |
| 17464 | 17466 | } |
| 17465 | var path_buffer: [posix.PATH_MAX]u8 = undefined; | |
| 17466 | var path_len = realPathPosix(dir, &path_buffer) catch |err| switch (err) { | |
| 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, | |
| 17467 | if (path) |p| if (dir == posix.AT.FDCWD or Dir.path.isAbsoluteZ(p)) { | |
| 17468 | break :err posix.errno(posix.system.execve(p, argv, env_block.slice.ptr)); | |
| 17481 | 17469 | }; |
| 17482 | if (path) |p| { | |
| 17483 | const path_slice = std.mem.span(p); | |
| 17484 | path_buffer[path_len] = Dir.path.sep; | |
| 17485 | path_len += 1; | |
| 17486 | @memcpy(path_buffer[path_len..][0..path_slice.len], path_slice); | |
| 17487 | path_len += path_slice.len; | |
| 17488 | } | |
| 17489 | path_buffer[path_len] = 0; | |
| 17490 | break :err posix.errno( | |
| 17491 | posix.system.execve(path_buffer[0..path_len :0], argv, env_block.slice.ptr), | |
| 17492 | ); | |
| 17470 | const exe: posix.fd_t = if (path) |p| exe: { | |
| 17471 | var flags: posix.O = .{}; | |
| 17472 | if (@hasField(posix.O, "CLOEXEC")) flags.CLOEXEC = true; | |
| 17473 | if (@hasField(posix.O, "LARGEFILE")) flags.LARGEFILE = true; | |
| 17474 | if (@hasField(posix.O, "NOCTTY")) flags.NOCTTY = true; | |
| 17475 | if (@hasField(posix.O, "PATH")) flags.PATH = true; | |
| 17476 | if (@hasField(posix.O, "EXEC")) flags.EXEC = true; | |
| 17477 | const rc = openat_sym(dir, p, flags, @as(posix.mode_t, 0)); | |
| 17478 | while (true) switch (posix.errno(rc)) { | |
| 17479 | .SUCCESS => break :exe @intCast(rc), | |
| 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 | 17519 | .FAULT => |err| return errnoBug(err), // Bad pointer parameter. |
| 17495 | 17520 | .@"2BIG" => return error.SystemResources, |
lib/std/Target.zig+6| ... | ... | @@ -1043,6 +1043,10 @@ pub const ObjectFormat = enum { |
| 1043 | 1043 | elf, |
| 1044 | 1044 | /// The Intel HEX format for storing binary code in ASCII text. |
| 1045 | 1045 | hex, |
| 1046 | /// LLVM binary intermediate representation. | |
| 1047 | llvmbc, | |
| 1048 | /// LLVM text intermediate representation. | |
| 1049 | llvmir, | |
| 1046 | 1050 | /// The Mach object format used by macOS and other Apple platforms. |
| 1047 | 1051 | macho, |
| 1048 | 1052 | /// The a.out format used by Plan 9 from Bell Labs. |
| ... | ... | @@ -1060,6 +1064,8 @@ pub const ObjectFormat = enum { |
| 1060 | 1064 | .coff => ".obj", |
| 1061 | 1065 | .elf, .macho, .wasm => ".o", |
| 1062 | 1066 | .hex => ".ihex", |
| 1067 | .llvmbc => ".bc", | |
| 1068 | .llvmir => ".ll", | |
| 1063 | 1069 | .plan9 => arch.plan9Ext(), |
| 1064 | 1070 | .raw => ".bin", |
| 1065 | 1071 | .spirv => ".spv", |
lib/std/Target/Query.zig+61-97| ... | ... | @@ -261,13 +261,11 @@ pub fn parse(args: ParseOptions) !Query { |
| 261 | 261 | if (abi_it.next() != null) { |
| 262 | 262 | if (abi.isGnu()) { |
| 263 | 263 | result.glibc_version = parseVersion(abi_ver_text) catch |err| switch (err) { |
| 264 | error.Overflow => return error.InvalidAbiVersion, | |
| 265 | error.InvalidVersion => return error.InvalidAbiVersion, | |
| 264 | error.Overflow, error.InvalidVersion => return error.InvalidAbiVersion, | |
| 266 | 265 | }; |
| 267 | 266 | } else if (abi.isAndroid()) { |
| 268 | 267 | result.android_api_level = std.fmt.parseUnsigned(u32, abi_ver_text, 10) catch |err| switch (err) { |
| 269 | error.InvalidCharacter => return error.InvalidVersion, | |
| 270 | error.Overflow => |e| return e, | |
| 268 | error.InvalidCharacter, error.Overflow => return error.InvalidAbiVersion, | |
| 271 | 269 | }; |
| 272 | 270 | } else { |
| 273 | 271 | return error.InvalidAbiVersion; |
| ... | ... | @@ -428,139 +426,105 @@ pub fn canDetectLibC(self: Query) bool { |
| 428 | 426 | return false; |
| 429 | 427 | } |
| 430 | 428 | |
| 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 | 430 | /// unlike SemanticVersion.format which formats all its version components regardless. |
| 433 | fn formatVersion(version: SemanticVersion, gpa: Allocator, list: *ArrayList(u8)) !void { | |
| 434 | if (version.patch == 0) { | |
| 435 | try list.print(gpa, "{d}.{d}", .{ version.major, version.minor }); | |
| 436 | } else { | |
| 437 | try list.print(gpa, "{d}.{d}.{d}", .{ version.major, version.minor, version.patch }); | |
| 431 | pub const PrintVersion = struct { | |
| 432 | version: SemanticVersion, | |
| 433 | pub fn format(print: PrintVersion, w: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 434 | try w.print("{d}.{d}", .{ print.version.major, print.version.minor }); | |
| 435 | switch (print.version.patch) { | |
| 436 | 0 => {}, | |
| 437 | else => |patch| try w.print(".{d}", .{patch}), | |
| 438 | } | |
| 438 | 439 | } |
| 439 | } | |
| 440 | ||
| 441 | pub 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"; | |
| 440 | }; | |
| 446 | 441 | |
| 447 | var result: ArrayList(u8) = .empty; | |
| 448 | defer result.deinit(gpa); | |
| 442 | pub fn printZigTriple(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 443 | if (query.isNativeTriple()) return w.writeAll("native"); | |
| 449 | 444 | |
| 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 | }); | |
| 451 | 449 | |
| 452 | 450 | // The zig target syntax does not allow specifying a max os version with no min, so |
| 453 | 451 | // if either are present, we need the min. |
| 454 | if (self.os_version_min) |min| { | |
| 452 | if (query.os_version_min) |min| { | |
| 455 | 453 | switch (min) { |
| 456 | 454 | .none => {}, |
| 457 | .semver => |v| { | |
| 458 | try result.appendSlice(gpa, "."); | |
| 459 | try formatVersion(v, gpa, &result); | |
| 460 | }, | |
| 461 | .windows => |v| { | |
| 462 | try result.print(gpa, "{f}", .{v}); | |
| 463 | }, | |
| 455 | .semver => |v| try w.print(".{f}", .{PrintVersion{ .version = v }}), | |
| 456 | .windows => |v| try w.print("{f}", .{v}), | |
| 464 | 457 | } |
| 465 | 458 | } |
| 466 | if (self.os_version_max) |max| { | |
| 459 | if (query.os_version_max) |max| { | |
| 467 | 460 | switch (max) { |
| 468 | 461 | .none => {}, |
| 469 | .semver => |v| { | |
| 470 | try result.appendSlice(gpa, "..."); | |
| 471 | try formatVersion(v, gpa, &result); | |
| 472 | }, | |
| 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 | }, | |
| 462 | .semver => |v| try w.print("...{f}", .{PrintVersion{ .version = v }}), | |
| 463 | // This is counting on a custom format() function defined on `WindowsVersion` | |
| 464 | // to add a prefix '.' and make there be a total of three dots. | |
| 465 | .windows => |v| try w.print("..{f}", .{v}), | |
| 478 | 466 | } |
| 479 | 467 | } |
| 480 | 468 | |
| 481 | if (self.glibc_version) |v| { | |
| 482 | const name = @tagName(self.abi.?); | |
| 483 | try result.ensureUnusedCapacity(gpa, name.len + 2); | |
| 484 | result.appendAssumeCapacity('-'); | |
| 485 | result.appendSliceAssumeCapacity(name); | |
| 486 | result.appendAssumeCapacity('.'); | |
| 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); | |
| 469 | if (query.glibc_version) |v| { | |
| 470 | try w.print("-{t}.{f}", .{ query.abi.?, PrintVersion{ .version = v } }); | |
| 471 | } else if (query.android_api_level) |lvl| { | |
| 472 | try w.print("-{t}.{d}", .{ query.abi.?, lvl }); | |
| 473 | } else if (query.abi) |abi| { | |
| 474 | try w.print("-{t}", .{abi}); | |
| 500 | 475 | } |
| 501 | ||
| 502 | return result.toOwnedSlice(gpa); | |
| 503 | 476 | } |
| 504 | 477 | |
| 505 | /// Renders the query into a textual representation that can be parsed via the | |
| 478 | /// Prints the query into a textual representation that can be parsed via the | |
| 506 | 479 | /// `-mcpu` flag passed to the Zig compiler. |
| 507 | /// Appends the result to `buffer`. | |
| 508 | pub fn serializeCpu(q: Query, buffer: *std.array_list.Managed(u8)) Allocator.Error!void { | |
| 509 | try buffer.ensureUnusedCapacity(8); | |
| 510 | switch (q.cpu_model) { | |
| 511 | .native => { | |
| 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 | }, | |
| 480 | pub fn printCpu(query: *const Query, w: *std.Io.Writer) std.Io.Writer.Error!void { | |
| 481 | cpu_model: switch (query.cpu_model) { | |
| 482 | .native, .baseline => |_, cpu_model| try w.print("{t}", .{cpu_model}), | |
| 483 | .determined_by_arch_os => continue :cpu_model if (query.cpu_arch) |_| .baseline else .native, | |
| 484 | .explicit => |model| try w.writeAll(model.name), | |
| 527 | 485 | } |
| 528 | 486 | |
| 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 | 488 | // The CPU name alone is sufficient. |
| 531 | 489 | return; |
| 532 | 490 | } |
| 533 | 491 | |
| 534 | const cpu_arch = q.cpu_arch orelse builtin.cpu.arch; | |
| 492 | const cpu_arch = query.cpu_arch orelse builtin.cpu.arch; | |
| 535 | 493 | const all_features = cpu_arch.allFeaturesList(); |
| 536 | 494 | |
| 537 | 495 | for (all_features, 0..) |feature, i_usize| { |
| 538 | 496 | const i: Target.Cpu.Feature.Set.Index = @intCast(i_usize); |
| 539 | try buffer.ensureUnusedCapacity(feature.name.len + 1); | |
| 540 | if (q.cpu_features_sub.isEnabled(i)) { | |
| 541 | buffer.appendAssumeCapacity('-'); | |
| 542 | buffer.appendSliceAssumeCapacity(feature.name); | |
| 543 | } else if (q.cpu_features_add.isEnabled(i)) { | |
| 544 | buffer.appendAssumeCapacity('+'); | |
| 545 | buffer.appendSliceAssumeCapacity(feature.name); | |
| 497 | if (query.cpu_features_sub.isEnabled(i)) { | |
| 498 | try w.print("-{s}", .{feature.name}); | |
| 499 | } else if (query.cpu_features_add.isEnabled(i)) { | |
| 500 | try w.print("+{s}", .{feature.name}); | |
| 546 | 501 | } |
| 547 | 502 | } |
| 548 | 503 | } |
| 549 | 504 | |
| 550 | pub fn serializeCpuAlloc(q: Query, ally: Allocator) Allocator.Error![]u8 { | |
| 551 | var buffer = std.array_list.Managed(u8).init(ally); | |
| 552 | try serializeCpu(q, &buffer); | |
| 553 | return buffer.toOwnedSlice(); | |
| 505 | /// Deprecated; use `printZigTriple` instead. Will be removed in 0.19.0. | |
| 506 | pub fn zigTriple(query: Query, gpa: Allocator) Allocator.Error![]u8 { | |
| 507 | return gpa.print("{f}", .{std.fmt.alt(&query, .printZigTriple)}); | |
| 508 | } | |
| 509 | ||
| 510 | /// Deprecated; use `printCpu` instead. Will be removed in 0.19.0. | |
| 511 | pub 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. | |
| 516 | pub fn serializeCpuAlloc(query: Query, gpa: Allocator) Allocator.Error![]u8 { | |
| 517 | return gpa.print("{f}", .{std.fmt.alt(&query, .printCpu)}); | |
| 554 | 518 | } |
| 555 | 519 | |
| 556 | 520 | /// Deprecated; use `zigTriple` instead. Will be removed in 0.18.0. |
| 557 | pub fn allocDescription(self: Query, allocator: Allocator) ![]u8 { | |
| 558 | return self.zigTriple(allocator); | |
| 521 | pub fn allocDescription(query: Query, allocator: Allocator) ![]u8 { | |
| 522 | return query.zigTriple(allocator); | |
| 559 | 523 | } |
| 560 | 524 | |
| 561 | 525 | /// Deprecated; set `glibc_version` directly. Will be removed in 0.18.0. |
| 562 | pub fn setGnuLibCVersion(self: *Query, major: u32, minor: u32, patch: u32) void { | |
| 563 | self.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; | |
| 526 | pub fn setGnuLibCVersion(query: *Query, major: u32, minor: u32, patch: u32) void { | |
| 527 | query.glibc_version = SemanticVersion{ .major = major, .minor = minor, .patch = patch }; | |
| 564 | 528 | } |
| 565 | 529 | |
| 566 | 530 | fn 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 | 8387 | /// to determine the target of relative file paths in the openat() and |
| 8388 | 8388 | /// similar syscalls. |
| 8389 | 8389 | pub const FDCWD = -100; |
| 8390 | /// Fail rename if target exists | |
| 8391 | pub const RENAME_NOREPLACE = 0x0001; | |
| 8390 | 8392 | /// Check access using effective user and group ID |
| 8391 | 8393 | pub const EACCESS = 0x0100; |
| 8392 | 8394 | /// Do not follow symbolic links |
| ... | ... | @@ -8397,6 +8399,10 @@ pub const AT = switch (native_os) { |
| 8397 | 8399 | pub const REMOVEDIR = 0x0800; |
| 8398 | 8400 | /// Fail if not under dirfd |
| 8399 | 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 | 8407 | .netbsd => struct { |
| 8402 | 8408 | /// Magic value that specify the use of the current working directory |
| ... | ... | @@ -8552,7 +8558,11 @@ pub const O = switch (native_os) { |
| 8552 | 8558 | DIRECTORY: bool = false, |
| 8553 | 8559 | CLOEXEC: bool = false, |
| 8554 | 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 | 8567 | .openbsd => packed struct(u32) { |
| 8558 | 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 | 10947 | pub extern "c" fn symlink(existing: [*:0]const u8, new: [*:0]const u8) c_int; |
| 10938 | 10948 | pub extern "c" fn symlinkat(oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int; |
| 10939 | 10949 | pub extern "c" fn rename(old: [*:0]const u8, new: [*:0]const u8) c_int; |
| 10940 | pub extern "c" fn renameat(olddirfd: fd_t, old: [*:0]const u8, newdirfd: fd_t, new: [*:0]const u8) c_int; | |
| 10950 | pub extern "c" fn renameat(olddirfd: fd_t, oldpath: [*:0]const u8, newdirfd: fd_t, newpath: [*:0]const u8) c_int; | |
| 10941 | 10951 | pub extern "c" fn chdir(path: [*:0]const u8) c_int; |
| 10942 | 10952 | pub extern "c" fn fchdir(fd: fd_t) c_int; |
| 10953 | pub const fexecve = switch (native_os) { | |
| 10954 | else => {}, | |
| 10955 | .freebsd, .linux, .netbsd => private.fexecve, | |
| 10956 | }; | |
| 10943 | 10957 | pub extern "c" fn execve(path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8) c_int; |
| 10944 | 10958 | pub extern "c" fn execveat(dirfd: fd_t, path: [*:0]const u8, argv: [*:null]const ?[*:0]const u8, envp: [*:null]const ?[*:0]const u8, flags: EXECVEAT) c_int; |
| 10945 | 10959 | pub extern "c" fn dup(fd: fd_t) c_int; |
| ... | ... | @@ -11791,34 +11805,35 @@ pub const setkeymap = serenity.setkeymap; |
| 11791 | 11805 | |
| 11792 | 11806 | /// External definitions shared by two or more operating systems. |
| 11793 | 11807 | const private = struct { |
| 11794 | pub 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; | |
| 11796 | pub 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; | |
| 11808 | 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; | |
| 11810 | 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; | |
| 11798 | 11812 | |
| 11799 | pub 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; | |
| 11813 | 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; | |
| 11801 | 11815 | |
| 11802 | extern "c" fn close(fd: fd_t) c_int; | |
| 11803 | 11816 | extern "c" fn clock_getres(clk_id: clockid_t, tp: *timespec) c_int; |
| 11804 | 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 | 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 | 11822 | extern "c" fn flock(fd: fd_t, operation: c_int) c_int; |
| 11807 | 11823 | extern "c" fn fork() c_int; |
| 11808 | 11824 | extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; |
| 11809 | 11825 | extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, buf: *Stat, flag: u32) c_int; |
| 11810 | 11826 | extern "c" fn getdirentries(fd: fd_t, buf_ptr: [*]u8, nbytes: usize, basep: *i64) isize; |
| 11811 | 11827 | extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) switch (native_os) { |
| 11828 | else => c_int, | |
| 11812 | 11829 | .freebsd => isize, |
| 11813 | 11830 | .illumos => usize, |
| 11814 | else => c_int, | |
| 11815 | 11831 | }; |
| 11816 | 11832 | extern "c" fn getrusage(who: c_int, usage: *rusage) c_int; |
| 11817 | 11833 | extern "c" fn gettimeofday(noalias tv: ?*timeval, noalias tz: ?*timezone) c_int; |
| 11818 | 11834 | extern "c" fn ioctl(fd: fd_t, request: c_int, ...) c_int; |
| 11819 | 11835 | extern "c" fn msync(addr: *align(page_size) const anyopaque, len: usize, flags: c_int) c_int; |
| 11820 | 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 | 11837 | extern "c" fn pipe2(fds: *[2]fd_t, flags: O) c_int; |
| 11823 | 11838 | extern "c" fn readdir(dir: *DIR) ?*dirent; |
| 11824 | 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 | 76 | }, |
| 77 | 77 | .macho => @import("debug/SelfInfo/MachO.zig"), |
| 78 | 78 | .plan9, .spirv, .wasm, .raw, .hex => void, |
| 79 | .c => unreachable, | |
| 79 | .c, .llvmbc, .llvmir => unreachable, | |
| 80 | 80 | }; |
| 81 | 81 | } |
| 82 | 82 |
lib/std/fmt.zig+7-1| ... | ... | @@ -285,7 +285,13 @@ pub fn Alt( |
| 285 | 285 | pub fn alt( |
| 286 | 286 | context: anytype, |
| 287 | 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 | 295 | return .{ .data = context }; |
| 290 | 296 | } |
| 291 | 297 |
lib/std/posix.zig+1-1| ... | ... | @@ -797,7 +797,7 @@ pub fn dl_iterate_phdr( |
| 797 | 797 | const dl = @import("dynamic_library.zig"); |
| 798 | 798 | |
| 799 | 799 | switch (builtin.object_format) { |
| 800 | .elf, .c => {}, | |
| 800 | .c, .elf, .llvmbc, .llvmir => {}, | |
| 801 | 801 | else => @compileError("dl_iterate_phdr is not available for this target"), |
| 802 | 802 | } |
| 803 | 803 |
lib/std/zig.zig+2| ... | ... | @@ -218,6 +218,8 @@ pub fn binNameAlloc(allocator: Allocator, options: BinNameOptions) error{OutOfMe |
| 218 | 218 | }, |
| 219 | 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 | 223 | .macho => switch (options.output_mode) { |
| 222 | 224 | .Exe => return allocator.dupe(u8, root_name), |
| 223 | 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 | 10855 | b.alignment_forward_references.items[index] = value; |
| 10856 | 10856 | } |
| 10857 | 10857 | |
| 10858 | pub fn dump(b: *Builder, io: Io) void { | |
| 10859 | var buffer: [4000]u8 = undefined; | |
| 10860 | const stderr: Io.File = .stderr(); | |
| 10861 | b.printToFile(io, stderr, &buffer) catch {}; | |
| 10862 | } | |
| 10858 | pub const Print = struct { | |
| 10859 | name: []const u8, | |
| 10860 | builder: *Builder, | |
| 10861 | err: ?Allocator.Error, | |
| 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 | }; | |
| 10863 | 10874 | |
| 10864 | 10875 | pub fn printToFilePath(b: *Builder, io: Io, dir: Io.Dir, path: []const u8) !void { |
| 10865 | 10876 | var buffer: [4000]u8 = undefined; |
lib/std/zig/string_literal.zig+17-1| ... | ... | @@ -38,6 +38,11 @@ pub const Error = union(enum) { |
| 38 | 38 | invalid_character: usize, |
| 39 | 39 | /// `''`. Not returned for string literals. |
| 40 | 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, | |
| 41 | 46 | |
| 42 | 47 | const FormatMessage = struct { |
| 43 | 48 | err: Error, |
| ... | ... | @@ -83,6 +88,12 @@ pub const Error = union(enum) { |
| 83 | 88 | .empty_char_literal => try writer.writeAll( |
| 84 | 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 | } |
| 88 | 99 | |
| ... | ... | @@ -104,6 +115,8 @@ pub const Error = union(enum) { |
| 104 | 115 | .expected_rbrace, |
| 105 | 116 | .expected_single_quote, |
| 106 | 117 | .invalid_character, |
| 118 | .end_of_input, | |
| 119 | .end_of_literal, | |
| 107 | 120 | => |n| n, |
| 108 | 121 | .empty_char_literal => 0, |
| 109 | 122 | }; |
| ... | ... | @@ -339,13 +352,16 @@ pub fn parseWrite(writer: *Writer, bytes: []const u8) Writer.Error!Result { |
| 339 | 352 | try writer.writeAll(buf[0..len]); |
| 340 | 353 | } else { |
| 341 | 354 | try writer.writeByte(@as(u8, @intCast(codepoint))); |
| 355 | if (index == bytes.len) return .{ .failure = .{ .end_of_input = index } }; | |
| 342 | 356 | } |
| 343 | 357 | }, |
| 344 | 358 | .failure => |err| return .{ .failure = err }, |
| 345 | 359 | } |
| 346 | 360 | }, |
| 347 | 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 | 365 | else => { |
| 350 | 366 | try writer.writeByte(b); |
| 351 | 367 | index += 1; |
src/Air.zig+5-5| ... | ... | @@ -13,10 +13,10 @@ const InternPool = @import("InternPool.zig"); |
| 13 | 13 | const Type = @import("Type.zig"); |
| 14 | 14 | const Value = @import("Value.zig"); |
| 15 | 15 | const Zcu = @import("Zcu.zig"); |
| 16 | const print = @import("Air/print.zig"); | |
| 17 | 16 | |
| 18 | 17 | pub const Legalize = @import("Air/Legalize.zig"); |
| 19 | 18 | pub const Liveness = @import("Air/Liveness.zig"); |
| 19 | pub const Print = @import("Air/Print.zig"); | |
| 20 | 20 | pub const Verify = @import("Air/Verify.zig"); |
| 21 | 21 | |
| 22 | 22 | instructions: std.MultiArrayList(Inst).Slice, |
| ... | ... | @@ -2517,10 +2517,10 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index |
| 2517 | 2517 | } |
| 2518 | 2518 | |
| 2519 | 2519 | pub const legalize = Legalize.legalize; |
| 2520 | pub const write = print.write; | |
| 2521 | pub const writeInst = print.writeInst; | |
| 2522 | pub const dump = print.dump; | |
| 2523 | pub const dumpInst = print.dumpInst; | |
| 2520 | pub const write = Print.write; | |
| 2521 | pub const writeInst = Print.writeInst; | |
| 2522 | pub const dump = Print.dump; | |
| 2523 | pub const dumpInst = Print.dumpInst; | |
| 2524 | 2524 | |
| 2525 | 2525 | pub const CoveragePoint = enum(u1) { |
| 2526 | 2526 | /// Indicates the block is not a place of interest corresponding to |
src/Air/Print.zig created+1059| ... | ... | @@ -0,0 +1,1059 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Allocator = std.mem.Allocator; | |
| 3 | const assert = std.debug.assert; | |
| 4 | ||
| 5 | const build_options = @import("build_options"); | |
| 6 | const Zcu = @import("../Zcu.zig"); | |
| 7 | const Value = @import("../Value.zig"); | |
| 8 | const Type = @import("../Type.zig"); | |
| 9 | const Air = @import("../Air.zig"); | |
| 10 | const InternPool = @import("../InternPool.zig"); | |
| 11 | const Printer = @This(); | |
| 12 | ||
| 13 | zcu: *Zcu, | |
| 14 | fqn: InternPool.NullTerminatedString, | |
| 15 | air: *const Air, | |
| 16 | liveness: *const ?Air.Liveness, | |
| 17 | ||
| 18 | pub 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 | ||
| 23 | pub 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 | ||
| 67 | pub 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 | ||
| 86 | pub 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 | ||
| 94 | pub 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 | ||
| 102 | const 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Allocator = std.mem.Allocator; | |
| 3 | const assert = std.debug.assert; | |
| 4 | ||
| 5 | const build_options = @import("build_options"); | |
| 6 | const Zcu = @import("../Zcu.zig"); | |
| 7 | const Value = @import("../Value.zig"); | |
| 8 | const Type = @import("../Type.zig"); | |
| 9 | const Air = @import("../Air.zig"); | |
| 10 | const InternPool = @import("../InternPool.zig"); | |
| 11 | ||
| 12 | pub 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 | ||
| 56 | pub 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 | ||
| 75 | pub 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 | ||
| 83 | pub 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 | ||
| 91 | const 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 | 147 | pub fn values(_: @This()) [0]void { |
| 148 | 148 | return .{}; |
| 149 | 149 | } |
| 150 | pub fn clearRetainingCapacity(_: @This()) void {} | |
| 150 | 151 | pub fn deinit(_: @This(), _: Allocator) void {} |
| 151 | 152 | } = .{}, |
| 152 | 153 | |
| ... | ... | @@ -161,12 +162,6 @@ clang_passthrough_mode: bool, |
| 161 | 162 | clang_preprocessor_mode: ClangPreprocessorMode, |
| 162 | 163 | /// Whether to print clang argvs to stdout. |
| 163 | 164 | verbose_cc: bool, |
| 164 | verbose_air: bool, | |
| 165 | verbose_intern_pool: bool, | |
| 166 | verbose_generic_instances: bool, | |
| 167 | verbose_llvm_ir: ?[]const u8, | |
| 168 | verbose_llvm_bc: ?[]const u8, | |
| 169 | verbose_llvm_cpu_features: bool, | |
| 170 | 165 | verbose_link: bool, |
| 171 | 166 | link_depfile: ?[]const u8, |
| 172 | 167 | disable_c_depfile: bool, |
| ... | ... | @@ -243,8 +238,6 @@ reference_trace: ?u32 = null, |
| 243 | 238 | /// This mutex guards all `Compilation` mutable state. |
| 244 | 239 | mutex: std.Io.Mutex = .init, |
| 245 | 240 | |
| 246 | test_filters: []const []const u8, | |
| 247 | ||
| 248 | 241 | link_prog_node: std.Progress.Node = .none, |
| 249 | 242 | |
| 250 | 243 | llvm_opt_bisect_limit: c_int, |
| ... | ... | @@ -1544,13 +1537,7 @@ pub const CreateOptions = struct { |
| 1544 | 1537 | clang_passthrough_mode: bool = false, |
| 1545 | 1538 | verbose_cc: bool = false, |
| 1546 | 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 | 1540 | link_depfile: ?[]const u8 = null, |
| 1553 | verbose_llvm_cpu_features: bool = false, | |
| 1554 | 1541 | debug_compiler_runtime_libs: ?std.lang.Optimize = null, |
| 1555 | 1542 | debug_compile_errors: bool = false, |
| 1556 | 1543 | debug_incremental: bool = false, |
| ... | ... | @@ -1646,28 +1633,11 @@ pub const CreateOptions = struct { |
| 1646 | 1633 | }; |
| 1647 | 1634 | }; |
| 1648 | 1635 | |
| 1649 | fn 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 | ||
| 1665 | 1636 | const RtStrat = enum { none, lib, obj, zcu }; |
| 1666 | 1637 | |
| 1667 | 1638 | pub const CreateDiagnostic = union(enum) { |
| 1668 | 1639 | export_table_import_table_conflict, |
| 1669 | 1640 | emit_h_without_zcu, |
| 1670 | illegal_zig_import, | |
| 1671 | 1641 | cross_libc_unavailable, |
| 1672 | 1642 | find_native_libc: std.zig.LibCInstallation.FindError, |
| 1673 | 1643 | libc_installation_missing_cc_dir, |
| ... | ... | @@ -1683,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) { |
| 1683 | 1653 | switch (diag) { |
| 1684 | 1654 | .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"), |
| 1685 | 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 | 1656 | .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"), |
| 1688 | 1657 | .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}), |
| 1689 | 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 | 1700 | const use_llvm = options.config.use_llvm; |
| 1732 | 1701 | const target = &options.root_mod.resolved_target.result; |
| 1733 | 1702 | |
| 1734 | const comp: *Compilation = comp: { | |
| 1703 | const comp = comp: { | |
| 1735 | 1704 | // We put the `Compilation` itself in the arena. Freeing the arena will free the module. |
| 1736 | 1705 | // It's initialized later after we prepare the initialization options. |
| 1737 | 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 | 1901 | try options.root_mod.deps.putNoClobber(arena, "zigc", zigc_mod); |
| 1933 | 1902 | } |
| 1934 | 1903 | |
| 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 | 1904 | const error_limit = options.error_limit orelse (std.math.maxInt(u16) - 1); |
| 1951 | 1905 | const main_mod = options.main_mod orelse options.root_mod; |
| 1952 | 1906 | |
| ... | ... | @@ -2014,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2014 | 1968 | // TODO audit this and make sure everything is in it |
| 2015 | 1969 | |
| 2016 | 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 | 1972 | // Pre-open the directory handles for cached ZIR code so that it does not need |
| 2019 | 1973 | // to redundantly happen for each AstGen operation. |
| 2020 | 1974 | const zir_sub_dir = "z"; |
| ... | ... | @@ -2067,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2067 | 2021 | zcu.* = .{ |
| 2068 | 2022 | .gpa = gpa, |
| 2069 | 2023 | .comp = comp, |
| 2070 | .main_mod = main_mod, | |
| 2024 | .llvm_object = null, | |
| 2025 | ||
| 2071 | 2026 | .root_mod = options.root_mod, |
| 2027 | .main_mod = main_mod, | |
| 2072 | 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 | 2035 | .global_zir_cache = global_zir_cache, |
| 2074 | 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 | 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 | 2081 | .analysis_roots_buffer = undefined, |
| 2078 | 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 | 2107 | .codegen_task_pool = try .init(arena), |
| 2108 | ||
| 2109 | .generation = 0, | |
| 2110 | ||
| 2080 | 2111 | .anon_name_counter = 0, |
| 2081 | 2112 | }; |
| 2082 | try zcu.init(gpa, io, options.thread_limit); | |
| 2083 | 2113 | break :blk zcu; |
| 2084 | 2114 | } else blk: { |
| 2085 | 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 | 2141 | .clang_passthrough_mode = options.clang_passthrough_mode, |
| 2112 | 2142 | .clang_preprocessor_mode = options.clang_preprocessor_mode, |
| 2113 | 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 | 2144 | .verbose_link = options.verbose_link, |
| 2145 | .link_depfile = options.link_depfile, | |
| 2122 | 2146 | .disable_c_depfile = options.disable_c_depfile, |
| 2123 | 2147 | .reference_trace = options.reference_trace, |
| 2124 | 2148 | .time_report = if (options.time_report) .init else null, |
| 2125 | 2149 | .stack_report = options.stack_report, |
| 2126 | .test_filters = options.test_filters, | |
| 2127 | 2150 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 2128 | 2151 | .debug_compile_errors = options.debug_compile_errors, |
| 2129 | 2152 | .debug_incremental = options.debug_incremental, |
| ... | ... | @@ -2175,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2175 | 2198 | comp.config.any_sanitize_c = any_sanitize_c; |
| 2176 | 2199 | comp.config.any_fuzz = any_fuzz; |
| 2177 | 2200 | |
| 2178 | if (opt_zcu) |zcu| { | |
| 2179 | // Finish initializing the `zcu` after the fields on `comp` have been initialized. | |
| 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 | } | |
| 2201 | // Initialize the `zcu` after the fields on `comp` have been initialized. | |
| 2202 | if (opt_zcu) |zcu| zcu.init(); | |
| 2190 | 2203 | |
| 2191 | 2204 | const lf_open_opts: link.File.OpenOptions = .{ |
| 2192 | 2205 | .linker_script = options.linker_script, |
| ... | ... | @@ -2282,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2282 | 2295 | hash.add(options.config.is_test); |
| 2283 | 2296 | hash.addListOfBytes(options.test_filters); |
| 2284 | 2297 | hash.add(options.skip_linker_dependencies); |
| 2285 | hash.add(options.emit_h != .no); | |
| 2298 | //hash.add(options.emit_h != .no); | |
| 2286 | 2299 | hash.add(error_limit); |
| 2287 | 2300 | |
| 2288 | // Here we put the root source file path name, but *not* with addFile. | |
| 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 | } | |
| 2301 | try comp.addModuleTableToCacheHash(&hash); | |
| 2299 | 2302 | |
| 2300 | 2303 | // In the case of incremental cache mode, this `artifact_directory` |
| 2301 | 2304 | // 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 | 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 | 2353 | break :comp comp; |
| 2366 | 2354 | }; |
| 2367 | 2355 | errdefer comp.destroy(); |
| ... | ... | @@ -2566,19 +2554,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic, |
| 2566 | 2554 | return comp; |
| 2567 | 2555 | } |
| 2568 | 2556 | |
| 2569 | fn 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 | ||
| 2582 | 2557 | pub fn destroy(comp: *Compilation) void { |
| 2583 | 2558 | const gpa = comp.gpa; |
| 2584 | 2559 | const io = comp.io; |
| ... | ... | @@ -2643,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void { |
| 2643 | 2618 | } |
| 2644 | 2619 | comp.win32_resources.deinit(gpa); |
| 2645 | 2620 | |
| 2646 | for (comp.failed_win32_resources.values()) |*value| { | |
| 2647 | value.deinit(gpa); | |
| 2621 | for (comp.failed_win32_resources.values()) |*bundle| { | |
| 2622 | bundle.deinit(gpa); | |
| 2648 | 2623 | } |
| 2649 | 2624 | comp.failed_win32_resources.deinit(gpa); |
| 2650 | 2625 | |
| ... | ... | @@ -2668,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void { |
| 2668 | 2643 | comp.misc_failures = .{}; |
| 2669 | 2644 | } |
| 2670 | 2645 | |
| 2671 | pub fn getTarget(self: *const Compilation) *const Target { | |
| 2672 | return &self.root_mod.resolved_target.result; | |
| 2646 | pub fn getTarget(comp: *const Compilation) *const Target { | |
| 2647 | return &comp.root_mod.resolved_target.result; | |
| 2673 | 2648 | } |
| 2674 | 2649 | |
| 2675 | 2650 | /// Only legal to call when cache mode is incremental and a link file is present. |
| ... | ... | @@ -2688,6 +2663,18 @@ pub fn hotCodeSwap( |
| 2688 | 2663 | fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2689 | 2664 | const io = comp.io; |
| 2690 | 2665 | |
| 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 | 2678 | switch (comp.cache_use) { |
| 2692 | 2679 | .none => |none| { |
| 2693 | 2680 | if (none.tmp_artifact_directory) |*tmp_dir| { |
| ... | ... | @@ -2704,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2704 | 2691 | // replicated in the output binary (the output instead contains a reference to that |
| 2705 | 2692 | // file which debug tooling can look through). So, in that particular case, we need |
| 2706 | 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) { | |
| 2708 | // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU | |
| 2709 | // object file must remain on-disk for its debug info. | |
| 2710 | return; | |
| 2694 | if (comp.bin_file == null or comp.getTarget().ofmt != .macho or comp.config.debug_format == .strip) { | |
| 2695 | const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int); | |
| 2696 | comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| { | |
| 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 | 2704 | .incremental => return, |
| ... | ... | @@ -2723,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void { |
| 2723 | 2707 | man.deinit(); |
| 2724 | 2708 | whole.cache_manifest = null; |
| 2725 | 2709 | } |
| 2726 | if (comp.bin_file) |lf| { | |
| 2727 | lf.destroy(); | |
| 2728 | comp.bin_file = null; | |
| 2729 | } | |
| 2730 | 2710 | if (whole.tmp_artifact_directory) |*tmp_dir| { |
| 2731 | 2711 | tmp_dir.handle.close(io); |
| 2732 | 2712 | whole.tmp_artifact_directory = null; |
| ... | ... | @@ -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 | } |
| 2743 | 2730 | |
| 2744 | 2731 | pub const UpdateError = error{ |
| ... | ... | @@ -2760,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2760 | 2747 | defer arena_allocator.deinit(); |
| 2761 | 2748 | const arena = arena_allocator.allocator(); |
| 2762 | 2749 | |
| 2763 | comp.clearMiscFailures(); | |
| 2764 | comp.last_update_was_cache_hit = false; | |
| 2765 | if (comp.time_report) |*tr| { | |
| 2766 | tr.deinit(gpa); // this is information about an old update | |
| 2767 | tr.* = .init; | |
| 2750 | reset: { | |
| 2751 | comp.clearMiscFailures(); | |
| 2752 | comp.last_update_was_cache_hit = false; | |
| 2753 | if (comp.time_report) |*tr| { | |
| 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 | } |
| 2769 | 2769 | |
| 2770 | 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 | 2909 | if (comp.zcu) |zcu| { |
| 2910 | 2910 | assert(zcu.cur_analysis_timer == null); |
| 2911 | 2911 | |
| 2912 | zcu.skip_analysis_this_update = false; | |
| 2913 | ||
| 2914 | 2912 | // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate! |
| 2915 | 2913 | for (zcu.embed_table.keys()) |embed_file| { |
| 2916 | 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 | } |
| 2946 | 2917 | |
| 2947 | 2918 | // 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 | 2934 | comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total); |
| 2964 | 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 | }; | |
| 2971 | 2937 | |
| 2972 | 2938 | try comp.performAllTheWork(main_progress_node, arena); |
| 2973 | 2939 | |
| ... | ... | @@ -2991,14 +2957,19 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 2991 | 2957 | try pt.processExports(); |
| 2992 | 2958 | } |
| 2993 | 2959 | |
| 2994 | if (build_options.enable_debug_extensions and comp.verbose_intern_pool) { | |
| 2995 | std.debug.print("intern pool stats for {q}:\n", .{comp.root_name}); | |
| 2996 | zcu.intern_pool.dump(); | |
| 2997 | } | |
| 2998 | ||
| 2999 | if (build_options.enable_debug_extensions and comp.verbose_generic_instances) { | |
| 3000 | std.debug.print("generic instances for '{s}:0x{x}':\n", .{ comp.root_name, @intFromPtr(zcu) }); | |
| 3001 | zcu.intern_pool.dumpGenericInstances(gpa); | |
| 2960 | { | |
| 2961 | var d: InternPool.Dump = .{ | |
| 2962 | .name = comp.root_name, | |
| 2963 | .arena = arena, | |
| 2964 | .ip = &zcu.intern_pool, | |
| 2965 | .err = null, | |
| 2966 | }; | |
| 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 | } |
| 3004 | 2975 | |
| ... | ... | @@ -3008,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3008 | 2979 | comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err}); |
| 3009 | 2980 | }; |
| 3010 | 2981 | |
| 3011 | if (anyErrors(comp)) { | |
| 2982 | if (comp.anyErrors()) { | |
| 3012 | 2983 | // Skip flushing and keep source files loaded for error reporting. |
| 3013 | 2984 | return; |
| 3014 | 2985 | } |
| ... | ... | @@ -3022,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3022 | 2993 | } |
| 3023 | 2994 | |
| 3024 | 2995 | switch (comp.cache_use) { |
| 3025 | .none, .incremental => try flush(comp, arena), | |
| 2996 | .none, .incremental => try comp.flush(arena), | |
| 3026 | 2997 | .whole => |whole| { |
| 3027 | 2998 | if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); |
| 3028 | 2999 | if (comp.parent_whole_cache) |pwc| { |
| ... | ... | @@ -3103,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE |
| 3103 | 3074 | }; |
| 3104 | 3075 | } |
| 3105 | 3076 | |
| 3106 | try flush(comp, arena); | |
| 3077 | try comp.flush(arena); | |
| 3107 | 3078 | |
| 3108 | 3079 | // Calling `flush` may have produced errors, in which case the |
| 3109 | 3080 | // cache manifest must not be written. |
| 3110 | if (anyErrors(comp)) return; | |
| 3081 | if (comp.anyErrors()) return; | |
| 3111 | 3082 | |
| 3112 | 3083 | // Release the lock and close the file before writing the manifest. |
| 3113 | 3084 | // 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 | 3178 | defer tid.release(io); |
| 3208 | 3179 | if (comp.zcu) |zcu| { |
| 3209 | 3180 | if (zcu.llvm_object) |llvm_object| { |
| 3210 | ||
| 3211 | 3181 | // Emit the ZCU object from LLVM now; it's required to flush the output file. |
| 3212 | 3182 | // If there's an output file, it wants to decide where the LLVM object goes! |
| 3213 | 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 | 3190 | comp.time_report.?.stats.real_ns_llvm_emit = ns; |
| 3221 | 3191 | }; |
| 3222 | 3192 | |
| 3223 | const zcu_obj_path: ?Cache.Path = if (comp.bin_file != null) p: { | |
| 3224 | break :p try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename); | |
| 3225 | } else null; | |
| 3193 | const zcu_obj_path: ?Cache.Path = switch (comp.getTarget().ofmt) { | |
| 3194 | .llvmbc, .llvmir => null, | |
| 3195 | else => if (comp.bin_file != null) | |
| 3196 | try comp.resolveEmitPathFlush(arena, .temp, llvm_object.out_bin_basename) | |
| 3197 | else | |
| 3198 | null, | |
| 3199 | }; | |
| 3226 | 3200 | |
| 3227 | 3201 | const active = zcu.activate(tid); |
| 3228 | 3202 | defer active.deactivate(); |
| 3229 | 3203 | llvm_object.emit(active.pt, .{ |
| 3230 | .pre_ir_path = comp.verbose_llvm_ir, | |
| 3231 | .pre_bc_path = comp.verbose_llvm_bc, | |
| 3232 | ||
| 3233 | 3204 | .bin_path = if (zcu_obj_path) |p| try p.toStringZ(arena) else null, |
| 3234 | 3205 | .asm_path = p: { |
| 3235 | 3206 | const raw = comp.emit_asm orelse break :p null; |
| 3236 | 3207 | const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); |
| 3237 | 3208 | break :p try p.toStringZ(arena); |
| 3238 | 3209 | }, |
| 3239 | .post_ir_path = p: { | |
| 3210 | .opt_ir_path = p: { | |
| 3240 | 3211 | const raw = comp.emit_llvm_ir orelse break :p null; |
| 3241 | 3212 | const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); |
| 3242 | 3213 | break :p try p.toStringZ(arena); |
| 3243 | 3214 | }, |
| 3244 | .post_bc_path = p: { | |
| 3215 | .opt_bc_path = p: { | |
| 3245 | 3216 | const raw = comp.emit_llvm_bc orelse break :p null; |
| 3246 | 3217 | const p = try comp.resolveEmitPathFlush(arena, .artifact, raw); |
| 3247 | 3218 | break :p try p.toStringZ(arena); |
| ... | ... | @@ -3267,7 +3238,7 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error |
| 3267 | 3238 | error.Canceled, error.OutOfMemory => |e| return e, |
| 3268 | 3239 | error.AlreadyReported => return, |
| 3269 | 3240 | }; |
| 3270 | } | |
| 3241 | } else return; | |
| 3271 | 3242 | } |
| 3272 | 3243 | } |
| 3273 | 3244 | if (comp.bin_file) |lf| { |
| ... | ... | @@ -3341,23 +3312,42 @@ fn renameTmpIntoCache( |
| 3341 | 3312 | /// anything from the link cache manifest. |
| 3342 | 3313 | pub const link_hash_implementation_version = 14; |
| 3343 | 3314 | |
| 3344 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | |
| 3345 | comptime assert(link_hash_implementation_version == 14); | |
| 3315 | fn addModuleTableToCacheHash(comp: *Compilation, hash: *Cache.HashHelper) Allocator.Error!void { | |
| 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]; | |
| 3346 | 3326 | |
| 3347 | if (comp.zcu) |zcu| { | |
| 3348 | 3327 | // No need to hash the actual file contents here because it is |
| 3349 | 3328 | // redundant with the logic in `PerThread.update` which iterates over |
| 3350 | 3329 | // `zcu.alive_files` and adds those files discovered via `@import` to |
| 3351 | 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 | ||
| 3341 | fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { | |
| 3342 | comptime assert(link_hash_implementation_version == 14); | |
| 3343 | ||
| 3344 | try comp.addModuleTableToCacheHash(&man.hash); | |
| 3353 | 3345 | |
| 3346 | if (comp.zcu) |zcu| { | |
| 3354 | 3347 | // Synchronize with other matching comments: ZigOnlyHashStuff |
| 3355 | man.hash.addListOfBytes(comp.test_filters); | |
| 3356 | man.hash.add(comp.skip_linker_dependencies); | |
| 3348 | man.hash.addListOfBytes(zcu.test_filters); | |
| 3357 | 3349 | //man.hash.add(zcu.emit_h != .no); |
| 3358 | 3350 | man.hash.add(zcu.error_limit); |
| 3359 | } else { | |
| 3360 | cache_helpers.addModule(&man.hash, comp.root_mod); | |
| 3361 | 3351 | } |
| 3362 | 3352 | |
| 3363 | 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 | 3816 | } |
| 3827 | 3817 | |
| 3828 | 3818 | /// This function is temporally single-threaded. |
| 3829 | pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { | |
| 3819 | pub fn getAllErrorsAlloc(comp: *Compilation) Allocator.Error!ErrorBundle { | |
| 3830 | 3820 | const gpa = comp.gpa; |
| 3831 | 3821 | const io = comp.io; |
| 3832 | 3822 | |
| ... | ... | @@ -3869,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle { |
| 3869 | 3859 | } |
| 3870 | 3860 | |
| 3871 | 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 | 3871 | if (zcu.multi_module_err != null) { |
| 3873 | 3872 | try zcu.addFileInMultipleModulesError(&bundle); |
| 3874 | 3873 | break :zcu_errors; |
| ... | ... | @@ -4397,7 +4396,9 @@ fn performAllTheWork( |
| 4397 | 4396 | defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu); |
| 4398 | 4397 | if (comp.zcu) |zcu| { |
| 4399 | 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 | 4402 | const active = zcu.acquire(); |
| 4402 | 4403 | defer active.release(); |
| 4403 | 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 | 4904 | .emit_bin = .yes_cache, |
| 4904 | 4905 | .verbose_cc = comp.verbose_cc, |
| 4905 | 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 | 4907 | .environ_map = comp.environ_map, |
| 4913 | 4908 | }) catch |err| switch (err) { |
| 4914 | 4909 | error.CreateFail => { |
| ... | ... | @@ -7415,12 +7410,6 @@ fn buildOutputFromZig( |
| 7415 | 7410 | .data_sections = true, |
| 7416 | 7411 | .verbose_cc = comp.verbose_cc, |
| 7417 | 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 | 7413 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 7425 | 7414 | .skip_linker_dependencies = true, |
| 7426 | 7415 | .environ_map = comp.environ_map, |
| ... | ... | @@ -7552,12 +7541,6 @@ pub fn build_crt_file( |
| 7552 | 7541 | .c_source_files = c_source_files, |
| 7553 | 7542 | .verbose_cc = comp.verbose_cc, |
| 7554 | 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 | 7544 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 7562 | 7545 | .skip_linker_dependencies = true, |
| 7563 | 7546 | .environ_map = comp.environ_map, |
src/Compilation/Config.zig+4-4| ... | ... | @@ -190,7 +190,7 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 190 | 190 | // *If* the LLVM backend were to be selected, should Zig use the LLVM |
| 191 | 191 | // library to build the LLVM module? |
| 192 | 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 | 194 | if (options.use_lib_llvm == true) return error.LlvmLibraryUnavailable; |
| 195 | 195 | break :b false; |
| 196 | 196 | } |
| ... | ... | @@ -324,7 +324,7 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 324 | 324 | if (!options.have_zcu) break :b false; |
| 325 | 325 | |
| 326 | 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 | 328 | if (options.use_llvm == false) |
| 329 | 329 | return error.EmittingLlvmModuleRequiresLlvmBackend; |
| 330 | 330 | if (!target_util.hasLlvmSupport(target, target.ofmt)) |
| ... | ... | @@ -379,7 +379,7 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 379 | 379 | const backend = target_util.zigBackend(target, use_llvm); |
| 380 | 380 | |
| 381 | 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 | 383 | // Explicit request to use LLVM to produce an object file, but without |
| 384 | 384 | // using LLVM libraries. Impossible. |
| 385 | 385 | return error.EmittingBinaryRequiresLlvmLibrary; |
| ... | ... | @@ -513,7 +513,7 @@ pub fn resolve(options: Options) ResolveError!Config { |
| 513 | 513 | break :b switch (target.ofmt) { |
| 514 | 514 | .elf, .macho, .wasm => .{ .dwarf = .@"32" }, |
| 515 | 515 | .coff => .code_view, |
| 516 | .c => switch (target.os.tag) { | |
| 516 | .c, .llvmbc, .llvmir => switch (target.os.tag) { | |
| 517 | 517 | .windows, .uefi => .code_view, |
| 518 | 518 | else => .{ .dwarf = .@"32" }, |
| 519 | 519 | }, |
src/InternPool.zig+36-25| ... | ... | @@ -5255,6 +5255,7 @@ pub const Tag = enum(u8) { |
| 5255 | 5255 | type_hash: ?u64, |
| 5256 | 5256 | captures_len: ?u32, |
| 5257 | 5257 | captures: ?[]CaptureValue, |
| 5258 | reified_field_name: ?[]NullTerminatedString, | |
| 5258 | 5259 | field_types: []Index, |
| 5259 | 5260 | field_aligns: ?[]Alignment, |
| 5260 | 5261 | }, |
| ... | ... | @@ -5263,6 +5264,8 @@ pub const Tag = enum(u8) { |
| 5263 | 5264 | .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true", |
| 5264 | 5265 | .@"trailing.captures.?" = .@"payload.flags.any_captures == .true", |
| 5265 | 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 | 5269 | .@"trailing.field_types.len" = .@"payload.fields_len", |
| 5267 | 5270 | .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns", |
| 5268 | 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 | 10591 | return ip.indexToKey(ty).error_union_type.payload_type; |
| 10589 | 10592 | } |
| 10590 | 10593 | |
| 10591 | pub fn dump(ip: *const InternPool) void { | |
| 10592 | var buffer: [4096]u8 = undefined; | |
| 10593 | const stderr = std.debug.lockStderr(&buffer); | |
| 10594 | defer std.debug.unlockStderr(); | |
| 10595 | const w = &stderr.file_writer.interface; | |
| 10596 | dumpDependencyStatsFallible(ip, w) catch return; | |
| 10597 | dumpStatsFallible(ip, w, std.heap.page_allocator) catch return; | |
| 10598 | dumpAllFallible(ip, w) catch return; | |
| 10599 | } | |
| 10594 | pub const Dump = struct { | |
| 10595 | name: []const u8, | |
| 10596 | arena: std.mem.Allocator, | |
| 10597 | ip: *const InternPool, | |
| 10598 | err: ?Allocator.Error, | |
| 10599 | ||
| 10600 | pub fn format(d: *Dump, w: *Io.Writer) Io.Writer.Error!void { | |
| 10601 | try w.print("{q}:\n", .{d.name}); | |
| 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 | } | |
| 10600 | 10616 | |
| 10601 | fn 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 | ||
| 10623 | fn dumpDependencyStatsFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void { | |
| 10602 | 10624 | const dep_entries_len = ip.dep_entries.items.len - ip.free_dep_entries.items.len; |
| 10603 | 10625 | const src_hash_deps_len = ip.src_hash_deps.count(); |
| 10604 | 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 | 10687 | }); |
| 10666 | 10688 | } |
| 10667 | 10689 | |
| 10668 | fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !void { | |
| 10690 | fn dumpStatsFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) (Allocator.Error || Io.Writer.Error)!void { | |
| 10669 | 10691 | var items_len: usize = 0; |
| 10670 | 10692 | var extra_len: usize = 0; |
| 10671 | 10693 | var limbs_len: usize = 0; |
| ... | ... | @@ -10965,7 +10987,7 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo |
| 10965 | 10987 | } |
| 10966 | 10988 | } |
| 10967 | 10989 | |
| 10968 | fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { | |
| 10990 | fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) Io.Writer.Error!void { | |
| 10969 | 10991 | for (ip.locals, 0..) |*local, tid| { |
| 10970 | 10992 | // Early check for length 0, because `view()` is invalid if capacity is 0 |
| 10971 | 10993 | if (local.mutate.items.len == 0) continue; |
| ... | ... | @@ -11068,21 +11090,10 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void { |
| 11068 | 11090 | } |
| 11069 | 11091 | } |
| 11070 | 11092 | |
| 11071 | pub fn dumpGenericInstances(ip: *const InternPool, allocator: Allocator) 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 | ||
| 11079 | pub 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 | ||
| 11093 | pub fn dumpGenericInstancesFallible(ip: *const InternPool, arena: Allocator, w: *Io.Writer) !void { | |
| 11084 | 11094 | var instances: std.array_hash_map.Auto(Index, std.ArrayList(Index)) = .empty; |
| 11085 | 11095 | for (ip.locals, 0..) |*local, tid| { |
| 11096 | if (local.mutate.items.len == 0) continue; | |
| 11086 | 11097 | const items = local.shared.items.view().slice(); |
| 11087 | 11098 | const extra_list = local.shared.extra; |
| 11088 | 11099 | for ( |
src/Module.zig+8-11| ... | ... | @@ -26,6 +26,7 @@ fully_qualified_name: []const u8, |
| 26 | 26 | deps: Deps = .{}, |
| 27 | 27 | |
| 28 | 28 | resolved_target: ResolvedTarget, |
| 29 | llvm_cpu_features: ?[:0]const u8, | |
| 29 | 30 | optimize_mode: std.lang.Optimize, |
| 30 | 31 | code_model: std.lang.CodeModel, |
| 31 | 32 | single_threaded: bool, |
| ... | ... | @@ -94,7 +95,6 @@ pub const ResolvedTarget = struct { |
| 94 | 95 | is_native_os: bool, |
| 95 | 96 | is_native_abi: bool, |
| 96 | 97 | is_explicit_dynamic_linker: bool, |
| 97 | llvm_cpu_features: ?[*:0]const u8 = null, | |
| 98 | 98 | }; |
| 99 | 99 | |
| 100 | 100 | pub const CreateError = error{ |
| ... | ... | @@ -362,15 +362,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { |
| 362 | 362 | break :b 0; |
| 363 | 363 | }; |
| 364 | 364 | |
| 365 | const llvm_cpu_features: ?[*:0]const u8 = b: { | |
| 366 | if (resolved_target.llvm_cpu_features) |x| break :b x; | |
| 365 | const llvm_cpu_features: ?[:0]const u8 = b: { | |
| 367 | 366 | if (!options.global.use_llvm) break :b null; |
| 367 | if (options.inherited.resolved_target == null) break :b options.parent.?.llvm_cpu_features; | |
| 368 | 368 | |
| 369 | // Append disabled features after enabled ones, so that their effects aren't overwritten. | |
| 369 | 370 | var buf = std.array_list.Managed(u8).init(arena); |
| 370 | 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 | 372 | for (target.cpu.arch.allFeaturesList()) |feature| { |
| 375 | 373 | if (feature.llvm_name) |llvm_name| { |
| 376 | 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 | 399 | |
| 402 | 400 | try buf.appendSlice(disabled_features.items); |
| 403 | 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 | 403 | buf.items[buf.items.len - 1] = 0; |
| 406 | buf.shrinkAndFree(buf.items.len); | |
| 407 | break :b buf.items[0 .. buf.items.len - 1 :0].ptr; | |
| 404 | break :b buf.items[0 .. buf.items.len - 1 :0]; | |
| 408 | 405 | }; |
| 409 | 406 | |
| 410 | 407 | const mod = try arena.create(Module); |
| ... | ... | @@ -417,8 +414,8 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Module { |
| 417 | 414 | .is_native_os = resolved_target.is_native_os, |
| 418 | 415 | .is_native_abi = resolved_target.is_native_abi, |
| 419 | 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 | 419 | .optimize_mode = optimize_mode, |
| 423 | 420 | .single_threaded = single_threaded, |
| 424 | 421 | .error_tracing = error_tracing, |
| ... | ... | @@ -494,8 +491,8 @@ pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: std.zig.Directories) |
| 494 | 491 | .is_native_os = false, |
| 495 | 492 | .is_native_abi = false, |
| 496 | 493 | .is_explicit_dynamic_linker = false, |
| 497 | .llvm_cpu_features = null, | |
| 498 | 494 | }, |
| 495 | .llvm_cpu_features = null, | |
| 499 | 496 | .optimize_mode = opts.optimize_mode, |
| 500 | 497 | .single_threaded = opts.single_threaded, |
| 501 | 498 | .error_tracing = opts.error_tracing, |
src/Sema.zig+22-6| ... | ... | @@ -1126,6 +1126,8 @@ fn analyzeBodyInner( |
| 1126 | 1126 | crash_info.push(sema, block, body); |
| 1127 | 1127 | defer crash_info.pop(); |
| 1128 | 1128 | |
| 1129 | const path = zcu.namespacePtr(block.namespace).fileScope(zcu).path; | |
| 1130 | ||
| 1129 | 1131 | // We use a while (true) loop here to avoid a redundant way of breaking out of |
| 1130 | 1132 | // the loop. The only way to break out of the loop is with a `noreturn` |
| 1131 | 1133 | // instruction. |
| ... | ... | @@ -1134,11 +1136,7 @@ fn analyzeBodyInner( |
| 1134 | 1136 | crash_info.setBodyIndex(i); |
| 1135 | 1137 | const inst = body[i]; |
| 1136 | 1138 | |
| 1137 | // This log is a bit expensive, and LLVM fails to optimize it away. | |
| 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 | } | |
| 1139 | std.log.scoped(.sema_zir).debug("sema ZIR {f} %{d}", .{ path.fmt(comp), inst }); | |
| 1142 | 1140 | |
| 1143 | 1141 | const air_ref: Air.Inst.Ref = inst: switch (tags[@backingInt(inst)]) { |
| 1144 | 1142 | // zig fmt: off |
| ... | ... | @@ -27920,7 +27918,25 @@ fn elemValSlice( |
| 27920 | 27918 | } |
| 27921 | 27919 | } |
| 27922 | 27920 | |
| 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 | } | |
| 27924 | 27940 | |
| 27925 | 27941 | try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_src); |
| 27926 | 27942 | try sema.validateRuntimeValue(block, slice_src, slice); |
src/Zcu.zig+250-156| ... | ... | @@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit; |
| 40 | 40 | const BuiltinFn = std.zig.BuiltinFn; |
| 41 | 41 | const codegen = @import("codegen.zig"); |
| 42 | 42 | const LlvmObject = @import("codegen/llvm.zig").Object; |
| 43 | const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled; | |
| 43 | 44 | const dev = @import("dev.zig"); |
| 44 | 45 | const Zoir = std.zig.Zoir; |
| 45 | 46 | const ZonGen = std.zig.ZonGen; |
| ... | ... | @@ -69,18 +70,18 @@ root_mod: *Module, |
| 69 | 70 | /// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests. |
| 70 | 71 | main_mod: *Module, |
| 71 | 72 | std_mod: *Module, |
| 72 | sema_prog_node: std.Progress.Node = .none, | |
| 73 | codegen_prog_node: std.Progress.Node = .none, | |
| 73 | sema_prog_node: std.Progress.Node, | |
| 74 | codegen_prog_node: std.Progress.Node, | |
| 74 | 75 | /// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value |
| 75 | 76 | /// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this |
| 76 | 77 | /// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is |
| 77 | 78 | /// completed (since semantic analysis could trigger more codegen work). |
| 78 | pending_codegen_jobs: std.atomic.Value(u32) = .init(0), | |
| 79 | pending_codegen_jobs: std.atomic.Value(u32), | |
| 79 | 80 | |
| 80 | 81 | /// This is the progress node *under* `sema_prog_node` which is currently running. |
| 81 | 82 | /// When we have to pause to analyze something else, we just temporarily rename this node. |
| 82 | 83 | /// Eventually, when we thread semantic analysis, we will want one of these per thread. |
| 83 | cur_sema_prog_node: std.Progress.Node = .none, | |
| 84 | cur_sema_prog_node: std.Progress.Node, | |
| 84 | 85 | |
| 85 | 86 | /// Used by AstGen worker to load and store ZIR cache. |
| 86 | 87 | global_zir_cache: Cache.Directory, |
| ... | ... | @@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory, |
| 89 | 90 | |
| 90 | 91 | /// This is where all `Export` values are stored. Not all values here are necessarily valid exports; |
| 91 | 92 | /// to enumerate all exports, `single_exports` and `multi_exports` must be consulted. |
| 92 | all_exports: std.ArrayList(Export) = .empty, | |
| 93 | all_exports: std.ArrayList(Export), | |
| 93 | 94 | /// This is a list of free indices in `all_exports`. These indices may be reused by exports from |
| 94 | 95 | /// future semantic analysis. |
| 95 | free_exports: std.ArrayList(Export.Index) = .empty, | |
| 96 | free_exports: std.ArrayList(Export.Index), | |
| 96 | 97 | /// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of |
| 97 | 98 | /// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit` |
| 98 | 99 | /// whose analysis triggered the export. |
| 99 | single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty, | |
| 100 | single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index), | |
| 100 | 101 | /// Like `single_exports`, but for `AnalUnit`s which perform multiple exports. |
| 101 | 102 | /// The exports are `all_exports.items[index..][0..len]`. |
| 102 | 103 | multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct { |
| 103 | 104 | index: u32, |
| 104 | 105 | len: u32, |
| 105 | }) = .empty, | |
| 106 | ||
| 107 | /// Key is the digest returned by `Builtin.hash`; value is the corresponding module. | |
| 108 | builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module) = .empty, | |
| 106 | }), | |
| 109 | 107 | |
| 110 | 108 | /// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones. |
| 111 | 109 | /// Modules whose root file is not a Zig or ZON file have the value `.none`. |
| 112 | module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional) = .empty, | |
| 110 | module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional), | |
| 111 | /// Key is the digest returned by `Builtin.hash`; value is the corresponding module. | |
| 112 | builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module), | |
| 113 | 113 | |
| 114 | 114 | /// The set of all the Zig source files in the Zig Compilation Unit. Tracked in |
| 115 | 115 | /// 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 | 132 | pub const eql = @compileError("all accesses should be through ImportTableAdapter"); |
| 133 | 133 | }, |
| 134 | 134 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 |
| 135 | ) = .empty, | |
| 136 | ||
| 135 | ), | |
| 137 | 136 | /// The set of all files in `import_table` which are "alive" this update, meaning |
| 138 | 137 | /// they are reachable by traversing imports starting from an analysis root. This |
| 139 | 138 | /// is usually all files in `import_table`, but some could be omitted if an incremental |
| 140 | 139 | /// update removes an import, or if a module specified on the CLI is never imported. |
| 141 | 140 | /// Reconstructed on every update, after AstGen and before Sema. |
| 142 | 141 | /// Value is why the file is alive. |
| 143 | alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty, | |
| 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. | |
| 149 | multi_module_err: ?struct { | |
| 150 | file: File.Index, | |
| 151 | modules: [2]*Module, | |
| 152 | refs: [2]File.Reference, | |
| 153 | } = null, | |
| 154 | ||
| 142 | alive_files: std.array_hash_map.Auto(File.Index, File.Reference), | |
| 155 | 143 | /// The set of all the files which have been loaded with `@embedFile` in the Module. |
| 156 | 144 | /// We keep track of this in order to iterate over it and check which files have been |
| 157 | 145 | /// modified on the file system when an update is requested, as well as to cache |
| ... | ... | @@ -162,49 +150,19 @@ multi_module_err: ?struct { |
| 162 | 150 | /// |
| 163 | 151 | /// This table owns all of the `*EmbedFile` memory, which is allocated into gpa. |
| 164 | 152 | embed_table: std.array_hash_map.Custom( |
| 165 | *EmbedFile, | |
| 153 | EmbedFile, | |
| 166 | 154 | void, |
| 167 | 155 | struct { |
| 168 | 156 | pub const hash = @compileError("all accesses should be through EmbedTableAdapter"); |
| 169 | 157 | pub const eql = @compileError("all accesses should be through EmbedTableAdapter"); |
| 170 | 158 | }, |
| 171 | 159 | true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918 |
| 172 | ) = .empty, | |
| 160 | ), | |
| 173 | 161 | |
| 174 | 162 | /// Stores all Type and Value objects. |
| 175 | 163 | /// The idea is that this will be periodically garbage-collected, but such logic |
| 176 | 164 | /// is not yet implemented. |
| 177 | intern_pool: InternPool = .empty, | |
| 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. | |
| 181 | analysis_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. | |
| 183 | failed_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. | |
| 185 | transitive_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. | |
| 194 | failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty, | |
| 195 | failed_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. | |
| 201 | dependency_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`. | |
| 204 | dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct { | |
| 205 | unit: AnalUnit, | |
| 206 | reason: DependencyReason, | |
| 207 | }) = .empty, | |
| 165 | intern_pool: InternPool, | |
| 208 | 166 | |
| 209 | 167 | /// Keep track of `@compileLog`s per `AnalUnit`. |
| 210 | 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 | 178 | .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset), |
| 221 | 179 | }; |
| 222 | 180 | } |
| 223 | }) = .empty, | |
| 224 | compile_log_lines: std.ArrayList(CompileLogLine) = .empty, | |
| 225 | free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty, | |
| 226 | /// This tracks files which triggered errors when generating AST/ZIR/ZOIR. | |
| 227 | /// If not `null`, the value is a retryable error (the file status is guaranteed | |
| 228 | /// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` | |
| 229 | /// or `.success`, and there are ZIR/ZOIR errors which should be printed. | |
| 230 | /// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source | |
| 231 | /// location is always the entire file. The `[]u8` memory is owned by the map | |
| 232 | /// and allocated into `gpa`. | |
| 233 | failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty, | |
| 181 | }), | |
| 182 | compile_log_lines: std.ArrayList(CompileLogLine), | |
| 183 | free_compile_log_lines: std.ArrayList(CompileLogLine.Index), | |
| 184 | ||
| 185 | illegal_module_root: ?*Module, | |
| 186 | /// If this is populated, a "file exists in multiple modules" error should be emitted. | |
| 187 | /// This causes file errors to not be shown, because we don't really know which files | |
| 188 | /// should be alive (because the user has messed up their imports somewhere!). | |
| 189 | /// Cleared and recomputed every update, after AstGen and before Sema. | |
| 190 | multi_module_err: ?struct { | |
| 191 | file: File.Index, | |
| 192 | modules: [2]*Module, | |
| 193 | refs: [2]File.Reference, | |
| 194 | }, | |
| 234 | 195 | /// AstGen is not aware of modules, and so cannot determine whether an import |
| 235 | 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 | 218 | import_string: Zir.NullTerminatedString, |
| 258 | 219 | import_token: Ast.TokenIndex, |
| 259 | 220 | kind: enum { file_outside_module_root, illegal_zig_import }, |
| 260 | }) = .empty, | |
| 261 | failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty, | |
| 262 | /// If analysis failed due to a cimport error, the corresponding Clang errors | |
| 263 | /// are stored here. | |
| 264 | cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty, | |
| 221 | }), | |
| 222 | /// This tracks files which triggered errors when generating AST/ZIR/ZOIR. | |
| 223 | /// If not `null`, the value is a retryable error (the file status is guaranteed | |
| 224 | /// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure` | |
| 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`. | |
| 229 | failed_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`. | |
| 233 | skip_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. | |
| 236 | analysis_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. | |
| 238 | failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg), | |
| 239 | /// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed. | |
| 240 | transitive_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. | |
| 248 | dependency_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`. | |
| 251 | dependency_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. | |
| 260 | failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg), | |
| 261 | failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg), | |
| 262 | failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg), | |
| 265 | 263 | |
| 266 | 264 | /// Maximum amount of distinct error values, set by --error-limit |
| 267 | 265 | error_limit: ErrorInt, |
| ... | ... | @@ -269,14 +267,14 @@ error_limit: ErrorInt, |
| 269 | 267 | /// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock |
| 270 | 268 | /// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the |
| 271 | 269 | /// lock is not needed and is compiled out. |
| 272 | outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init, | |
| 270 | outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void, | |
| 273 | 271 | /// Value is the number of PO dependencies of this AnalUnit. |
| 274 | 272 | /// This value will decrease as we perform semantic analysis to learn what is outdated. |
| 275 | 273 | /// If any of these PO deps is outdated, this value will be moved to `outdated`. |
| 276 | potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | |
| 274 | potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32), | |
| 277 | 275 | /// Value is the number of PO dependencies of this AnalUnit. |
| 278 | 276 | /// Once this value drops to 0, the AnalUnit is a candidate for re-analysis. |
| 279 | outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | |
| 277 | outdated: std.array_hash_map.Auto(AnalUnit, u32), | |
| 280 | 278 | /// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0. |
| 281 | 279 | /// Such `AnalUnit`s are ready for immediate re-analysis. |
| 282 | 280 | /// See `findOutdatedToAnalyze` for details. |
| ... | ... | @@ -286,69 +284,64 @@ outdated_ready: struct { |
| 286 | 284 | funcs: std.array_hash_map.Auto(InternPool.Index, void), |
| 287 | 285 | /// Does not contain `.func` units. |
| 288 | 286 | other: std.array_hash_map.Auto(AnalUnit, void), |
| 289 | } = .{ .funcs = .empty, .other = .empty }, | |
| 287 | }, | |
| 290 | 288 | /// This contains a list of AnalUnit whose analysis or codegen failed, but the |
| 291 | 289 | /// failure was something like running out of disk space, and trying again may |
| 292 | 290 | /// succeed. On the next update, we will flush this list, marking all members of |
| 293 | 291 | /// it as outdated. |
| 294 | retryable_failures: std.ArrayList(AnalUnit) = .empty, | |
| 292 | retryable_failures: std.ArrayList(AnalUnit), | |
| 295 | 293 | |
| 296 | 294 | /// These are the modules which we initially queue for analysis in `Compilation.update`. |
| 297 | 295 | /// `resolveReferences` will use these as the root of its reachability traversal. |
| 298 | 296 | analysis_roots_buffer: [5]*Module, |
| 299 | analysis_roots_len: usize = 0, | |
| 297 | analysis_roots_len: usize, | |
| 300 | 298 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and |
| 301 | 299 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). |
| 302 | 300 | /// Allocated into `gpa`. |
| 303 | resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null, | |
| 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`. | |
| 308 | skip_analysis_this_update: bool = false, | |
| 301 | resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference), | |
| 309 | 302 | |
| 310 | test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty, | |
| 303 | test_filters: []const []const u8, | |
| 304 | test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void), | |
| 311 | 305 | |
| 312 | global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty, | |
| 306 | global_assembly: std.array_hash_map.Auto(AnalUnit, []u8), | |
| 313 | 307 | |
| 314 | 308 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 315 | 309 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 316 | 310 | /// Value is index into `all_references` of the first reference triggered by the unit. |
| 317 | 311 | /// The `next` field on the `Reference` forms a linked list of all references |
| 318 | 312 | /// triggered by the key `AnalUnit`. |
| 319 | reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | |
| 320 | all_references: std.ArrayList(Reference) = .empty, | |
| 313 | reference_table: std.array_hash_map.Auto(AnalUnit, u32), | |
| 314 | all_references: std.ArrayList(Reference), | |
| 321 | 315 | /// Freelist of indices in `all_references`. |
| 322 | free_references: std.ArrayList(u32) = .empty, | |
| 316 | free_references: std.ArrayList(u32), | |
| 323 | 317 | |
| 324 | inline_reference_frames: std.ArrayList(InlineReferenceFrame) = .empty, | |
| 325 | free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty, | |
| 318 | inline_reference_frames: std.ArrayList(InlineReferenceFrame), | |
| 319 | free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index), | |
| 326 | 320 | |
| 327 | 321 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 328 | 322 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 329 | 323 | /// Value is index into `all_type_reference` of the first reference triggered by the unit. |
| 330 | 324 | /// The `next` field on the `TypeReference` forms a linked list of all type references |
| 331 | 325 | /// triggered by the key `AnalUnit`. |
| 332 | type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty, | |
| 333 | all_type_references: std.ArrayList(TypeReference) = .empty, | |
| 326 | type_reference_table: std.array_hash_map.Auto(AnalUnit, u32), | |
| 327 | all_type_references: std.ArrayList(TypeReference), | |
| 334 | 328 | /// Freelist of indices in `all_type_references`. |
| 335 | free_type_references: std.ArrayList(u32) = .empty, | |
| 329 | free_type_references: std.ArrayList(u32), | |
| 336 | 330 | |
| 337 | 331 | /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element. |
| 338 | std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none), | |
| 332 | std_lang_decl_values: StdLangDecl.Memoized, | |
| 339 | 333 | |
| 340 | incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void = | |
| 341 | if (build_options.enable_debug_extensions) .init else {}, | |
| 334 | incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void, | |
| 342 | 335 | |
| 343 | 336 | /// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit, |
| 344 | 337 | /// this timer must be temporarily paused and resumed later. |
| 345 | cur_analysis_timer: ?Compilation.Timer = null, | |
| 338 | cur_analysis_timer: ?Compilation.Timer, | |
| 346 | 339 | |
| 347 | 340 | codegen_task_pool: CodegenTaskPool, |
| 348 | 341 | |
| 349 | generation: u32 = 0, | |
| 342 | generation: u32, | |
| 350 | 343 | |
| 351 | /// Only access from the Sema thread. | |
| 344 | /// Only accessed from the Sema thread. | |
| 352 | 345 | anon_name_counter: u32, |
| 353 | 346 | |
| 354 | 347 | pub const DependencyReason = struct { |
| ... | ... | @@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct { |
| 434 | 427 | _ = ctx; |
| 435 | 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 | 431 | _ = ctx; |
| 439 | 432 | _ = b_index; |
| 440 | 433 | const b_path = b_file.path; |
| ... | ... | @@ -1250,10 +1243,15 @@ pub const EmbedFile = struct { |
| 1250 | 1243 | |
| 1251 | 1244 | pub const Index = enum(u32) { |
| 1252 | 1245 | _, |
| 1253 | pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile { | |
| 1254 | return zcu.embed_table.keys()[@backingInt(idx)]; | |
| 1246 | pub fn get(idx: Index, zcu: *const Zcu) *const EmbedFile { | |
| 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 | }; |
| 1258 | 1256 | |
| 1259 | 1257 | /// This struct holds data necessary to construct API-facing `AllErrors.Message`. |
| ... | ... | @@ -2894,16 +2892,130 @@ pub const CompileError = error{ |
| 2894 | 2892 | ComptimeBreak, |
| 2895 | 2893 | }; |
| 2896 | 2894 | |
| 2897 | pub 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 | 2895 | /// It is valid to not call this function before `deinit` in error paths. |
| 2902 | 2896 | /// Requires the fields on `zcu.comp` to already be initialized. |
| 2903 | pub fn initAfterCompilation(zcu: *Zcu) void { | |
| 2897 | pub fn init(zcu: *Zcu) void { | |
| 2904 | 2898 | zcu.initTracyPlots(); |
| 2905 | 2899 | } |
| 2906 | 2900 | |
| 2901 | pub 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 | ||
| 2907 | 3019 | pub fn deinit(zcu: *Zcu) void { |
| 2908 | 3020 | const comp = zcu.comp; |
| 2909 | 3021 | const io = comp.io; |
| ... | ... | @@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void { |
| 2911 | 3023 | { |
| 2912 | 3024 | if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); |
| 2913 | 3025 | |
| 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 | 3034 | zcu.module_roots.deinit(gpa); |
| 2916 | for (zcu.import_table.keys()) |file_index| { | |
| 2917 | zcu.destroyFile(file_index); | |
| 2918 | } | |
| 3035 | zcu.builtin_modules.deinit(gpa); | |
| 3036 | ||
| 3037 | for (zcu.import_table.keys()) |file| zcu.destroyFile(file); | |
| 2919 | 3038 | zcu.import_table.deinit(gpa); |
| 2920 | 3039 | zcu.alive_files.deinit(gpa); |
| 2921 | ||
| 2922 | for (zcu.embed_table.keys()) |embed_file| { | |
| 2923 | embed_file.path.deinit(gpa); | |
| 2924 | gpa.destroy(embed_file); | |
| 2925 | } | |
| 3040 | for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa); | |
| 2926 | 3041 | zcu.embed_table.deinit(gpa); |
| 2927 | 3042 | |
| 2928 | zcu.local_zir_cache.handle.close(io); | |
| 2929 | zcu.global_zir_cache.handle.close(io); | |
| 3043 | zcu.compile_logs.deinit(gpa); | |
| 3044 | zcu.compile_log_lines.deinit(gpa); | |
| 3045 | zcu.free_compile_log_lines.deinit(gpa); | |
| 2930 | 3046 | |
| 2931 | for (zcu.failed_analysis.values()) |value| value.destroy(gpa); | |
| 2932 | for (zcu.failed_codegen.values()) |value| value.destroy(gpa); | |
| 2933 | for (zcu.failed_types.values()) |value| value.destroy(gpa); | |
| 3047 | zcu.failed_imports.deinit(gpa); | |
| 3048 | for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg); | |
| 3049 | zcu.failed_files.deinit(gpa); | |
| 2934 | 3050 | zcu.analysis_in_progress.deinit(gpa); |
| 3051 | for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa); | |
| 2935 | 3052 | zcu.failed_analysis.deinit(gpa); |
| 2936 | 3053 | zcu.transitive_failed_analysis.deinit(gpa); |
| 2937 | 3054 | zcu.dependency_loops.deinit(gpa); |
| 2938 | 3055 | zcu.dependency_loop_nodes.deinit(gpa); |
| 3056 | for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa); | |
| 2939 | 3057 | zcu.failed_codegen.deinit(gpa); |
| 3058 | for (zcu.failed_types.values()) |msg| msg.destroy(gpa); | |
| 2940 | 3059 | zcu.failed_types.deinit(gpa); |
| 2941 | ||
| 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 | } | |
| 3060 | for (zcu.failed_exports.values()) |msg| msg.destroy(gpa); | |
| 2951 | 3061 | zcu.failed_exports.deinit(gpa); |
| 2952 | 3062 | |
| 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 | 3063 | zcu.potentially_outdated.deinit(gpa); |
| 2968 | 3064 | zcu.outdated.deinit(gpa); |
| 2969 | 3065 | zcu.outdated_ready.funcs.deinit(gpa); |
| 2970 | 3066 | zcu.outdated_ready.other.deinit(gpa); |
| 2971 | 3067 | zcu.retryable_failures.deinit(gpa); |
| 2972 | 3068 | |
| 3069 | if (zcu.resolved_references) |*r| r.deinit(gpa); | |
| 3070 | ||
| 2973 | 3071 | zcu.test_functions.deinit(gpa); |
| 2974 | 3072 | |
| 2975 | for (zcu.global_assembly.values()) |s| { | |
| 2976 | gpa.free(s); | |
| 2977 | } | |
| 3073 | for (zcu.global_assembly.values()) |s| gpa.free(s); | |
| 2978 | 3074 | zcu.global_assembly.deinit(gpa); |
| 2979 | 3075 | |
| 2980 | 3076 | zcu.reference_table.deinit(gpa); |
| ... | ... | @@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void { |
| 2988 | 3084 | zcu.all_type_references.deinit(gpa); |
| 2989 | 3085 | zcu.free_type_references.deinit(gpa); |
| 2990 | 3086 | |
| 2991 | if (zcu.resolved_references) |*r| r.deinit(gpa); | |
| 2992 | ||
| 2993 | 3087 | if (comp.debugIncremental()) { |
| 2994 | 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 | 4446 | .unnamed_test => true, |
| 4353 | 4447 | .@"test", .decltest => a: { |
| 4354 | 4448 | const fqn_slice = nav.fqn.toSlice(ip); |
| 4355 | if (comp.test_filters.len > 0) { | |
| 4356 | for (comp.test_filters) |test_filter| { | |
| 4449 | if (zcu.test_filters.len > 0) { | |
| 4450 | for (zcu.test_filters) |test_filter| { | |
| 4357 | 4451 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; |
| 4358 | 4452 | } else break :a false; |
| 4359 | 4453 | } |
src/Zcu/PerThread.zig+66-82| ... | ... | @@ -25,6 +25,7 @@ const InternPool = @import("../InternPool.zig"); |
| 25 | 25 | const AnalUnit = InternPool.AnalUnit; |
| 26 | 26 | const Module = @import("../Module.zig"); |
| 27 | 27 | const Sema = @import("../Sema.zig"); |
| 28 | const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled; | |
| 28 | 29 | const target_util = @import("../target.zig"); |
| 29 | 30 | const tracy = @import("../tracy.zig"); |
| 30 | 31 | const trace = tracy.trace; |
| ... | ... | @@ -147,6 +148,12 @@ pub fn update( |
| 147 | 148 | comp.link_queue.finishZcuQueue(comp); |
| 148 | 149 | } |
| 149 | 150 | |
| 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 | 158 | const tracy_trace = traceNamed(@src(), "astgen"); |
| 152 | 159 | defer tracy_trace.end(); |
| ... | ... | @@ -202,11 +209,9 @@ pub fn update( |
| 202 | 209 | // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here |
| 203 | 210 | // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one |
| 204 | 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 | 213 | const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize)); |
| 207 | astgen_group.async(io, workerUpdateEmbedFile, .{ | |
| 208 | comp, ef_index, ef, | |
| 209 | }); | |
| 214 | astgen_group.async(io, workerUpdateEmbedFile, .{ comp, ef_index, ef }); | |
| 210 | 215 | } |
| 211 | 216 | |
| 212 | 217 | try astgen_group.await(io); |
| ... | ... | @@ -218,8 +223,8 @@ pub fn update( |
| 218 | 223 | // they belong to. |
| 219 | 224 | const any_fatal_files = try pt.computeAliveFiles(); |
| 220 | 225 | |
| 221 | // If the cache mode is `whole`, add every alive source file to the manifest. | |
| 222 | 226 | switch (comp.cache_use) { |
| 227 | .none => {}, | |
| 223 | 228 | .whole => |whole| if (whole.cache_manifest) |man| { |
| 224 | 229 | for (zcu.alive_files.keys()) |file_index| { |
| 225 | 230 | const file = zcu.fileByIndex(file_index); |
| ... | ... | @@ -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 | } |
| 254 | 263 | |
| 255 | 264 | if (comp.time_report) |*tr| { |
| ... | ... | @@ -2303,10 +2312,9 @@ fn analyzeFuncBody( |
| 2303 | 2312 | |
| 2304 | 2313 | const comp = zcu.comp; |
| 2305 | 2314 | |
| 2306 | const dump_air = build_options.enable_debug_extensions and comp.verbose_air; | |
| 2307 | const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); | |
| 2308 | ||
| 2309 | if (comp.bin_file != null or zcu.llvm_object != null or dump_air or dump_llvm_ir) { | |
| 2315 | if (comp.bin_file != null or zcu.llvm_object != null or log_air: { | |
| 2316 | break :log_air debugLogScopeEnabled("illegal-air") or debugLogScopeEnabled("legal-air") or debugLogScopeEnabled("air"); | |
| 2317 | }) { | |
| 2310 | 2318 | zcu.codegen_prog_node.increaseEstimatedTotalItems(1); |
| 2311 | 2319 | comp.link_prog_node.increaseEstimatedTotalItems(1); |
| 2312 | 2320 | |
| ... | ... | @@ -2494,11 +2502,7 @@ pub fn doImport( |
| 2494 | 2502 | } |
| 2495 | 2503 | /// This is called once during `Compilation.create` and never again. "builtin" modules don't yet |
| 2496 | 2504 | /// exist, so are not added to `module_roots` here. They must be added when they are created. |
| 2497 | pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ | |
| 2498 | OutOfMemory, | |
| 2499 | /// One of the specified modules had its root source file at an illegal path. | |
| 2500 | IllegalZigImport, | |
| 2501 | }!void { | |
| 2505 | pub fn populateModuleRootTable(pt: Zcu.PerThread) Allocator.Error!void { | |
| 2502 | 2506 | const zcu = pt.zcu; |
| 2503 | 2507 | const comp = zcu.comp; |
| 2504 | 2508 | const gpa = comp.gpa; |
| ... | ... | @@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ |
| 2507 | 2511 | // We'll initially add [mod, undefined] pairs, and when we reach the pair while |
| 2508 | 2512 | // iterating, rewrite the undefined value. |
| 2509 | 2513 | const roots = &zcu.module_roots; |
| 2510 | roots.clearRetainingCapacity(); | |
| 2514 | assert(roots.count() == 0); | |
| 2511 | 2515 | |
| 2512 | 2516 | // Start with: |
| 2513 | 2517 | // * `std_mod`, which is the main root of analysis |
| ... | ... | @@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{ |
| 2542 | 2546 | errdefer path.deinit(gpa); |
| 2543 | 2547 | |
| 2544 | 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 | } |
| 2547 | 2553 | |
| 2548 | 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 | 2787 | const gpa = comp.gpa; |
| 2782 | 2788 | const io = comp.io; |
| 2783 | 2789 | |
| 2784 | const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); | |
| 2785 | if (gop.found_existing) return .{ // the `File` is up-to-date | |
| 2786 | .file = zcu.module_roots.get(gop.value_ptr.*).?.unwrap().?, | |
| 2787 | .module_root = gop.value_ptr.*, | |
| 2790 | const mod: *Module = mod: { | |
| 2791 | const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash()); | |
| 2792 | if (!gop.found_existing) { | |
| 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(); | |
| 2790 | 2800 | |
| 2791 | const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs); | |
| 2792 | assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin | |
| 2801 | if (zcu.module_roots.get(mod)) |file| { | |
| 2802 | // We have already loaded this builtin.zig before! | |
| 2803 | return .{ .file = file.unwrap().?, .module_root = mod }; | |
| 2804 | } | |
| 2793 | 2805 | |
| 2794 | 2806 | const path = try mod.root.join(gpa, comp.dirs, "builtin.zig"); |
| 2795 | 2807 | errdefer path.deinit(gpa); |
| ... | ... | @@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct |
| 2827 | 2839 | .root_type = .none, |
| 2828 | 2840 | }); |
| 2829 | 2841 | |
| 2830 | gop.value_ptr.* = mod; | |
| 2831 | 2842 | file_gop.key_ptr.* = file_index; |
| 2832 | 2843 | zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional()); |
| 2833 | 2844 | try opts.populateFile(gpa, file); |
| ... | ... | @@ -2883,22 +2894,19 @@ pub fn embedFile( |
| 2883 | 2894 | return @fromBackingInt(@intCast(gop.index)); |
| 2884 | 2895 | } |
| 2885 | 2896 | errdefer _ = zcu.embed_table.pop(); |
| 2886 | gop.key_ptr.* = try pt.newEmbedFile(path); | |
| 2897 | try pt.initEmbedFile(gop.key_ptr, path); | |
| 2887 | 2898 | return @fromBackingInt(@intCast(gop.index)); |
| 2888 | 2899 | } |
| 2889 | 2900 | |
| 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 | 2902 | const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string); |
| 2892 | 2903 | errdefer path.deinit(gpa); |
| 2893 | 2904 | const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{}); |
| 2894 | 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 { | |
| 2905 | if (!gop.found_existing) { | |
| 2898 | 2906 | errdefer _ = zcu.embed_table.pop(); |
| 2899 | gop.key_ptr.* = try pt.newEmbedFile(path); | |
| 2900 | break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) }; | |
| 2901 | } | |
| 2907 | try pt.initEmbedFile(gop.key_ptr, path); | |
| 2908 | } else path.deinit(gpa); // we're not using this key | |
| 2909 | break :ef .{ gop.key_ptr, @fromBackingInt(@intCast(gop.index)) }; | |
| 2902 | 2910 | }; |
| 2903 | 2911 | |
| 2904 | 2912 | switch (embed_file.path.isNested(cur_file.mod.?.root)) { |
| ... | ... | @@ -2913,7 +2921,7 @@ pub fn updateEmbedFile( |
| 2913 | 2921 | pt: Zcu.PerThread, |
| 2914 | 2922 | ef: *Zcu.EmbedFile, |
| 2915 | 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 | 2925 | ip_str_out: ?*?InternPool.String, |
| 2918 | 2926 | ) Allocator.Error!void { |
| 2919 | 2927 | pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) { |
| ... | ... | @@ -3000,17 +3008,13 @@ fn updateEmbedFileInner( |
| 3000 | 3008 | } |
| 3001 | 3009 | |
| 3002 | 3010 | /// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success. |
| 3003 | fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.EmbedFile { | |
| 3011 | fn initEmbedFile(pt: Zcu.PerThread, ef: *Zcu.EmbedFile, path: Compilation.Path) EmbedFileError!void { | |
| 3004 | 3012 | const zcu = pt.zcu; |
| 3005 | 3013 | const comp = zcu.comp; |
| 3006 | 3014 | const io = comp.io; |
| 3007 | const gpa = comp.gpa; | |
| 3008 | 3015 | const ip = &zcu.intern_pool; |
| 3009 | 3016 | |
| 3010 | const new_file = try gpa.create(Zcu.EmbedFile); | |
| 3011 | errdefer gpa.destroy(new_file); | |
| 3012 | ||
| 3013 | new_file.* = .{ | |
| 3017 | ef.* = .{ | |
| 3014 | 3018 | .path = path, |
| 3015 | 3019 | .val = .none, |
| 3016 | 3020 | .err = null, |
| ... | ... | @@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E |
| 3018 | 3022 | }; |
| 3019 | 3023 | |
| 3020 | 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); | |
| 3022 | 3026 | |
| 3023 | 3027 | try comp.appendFileSystemInput(path); |
| 3024 | 3028 | |
| ... | ... | @@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E |
| 3031 | 3035 | const man = whole.cache_manifest orelse break :cache; |
| 3032 | 3036 | const ip_str = opt_ip_str orelse break :cache; // this will be a compile error |
| 3033 | 3037 | |
| 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 | 3039 | const contents = ip_str.toSlice(array_len, ip); |
| 3036 | 3040 | |
| 3037 | 3041 | try whole.cache_manifest_mutex.lock(io); |
| 3038 | 3042 | defer whole.cache_manifest_mutex.unlock(io); |
| 3039 | 3043 | |
| 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 | 3045 | error.FileSystemFailure => unreachable, // contents and stat are both provided |
| 3042 | 3046 | else => |e| return e, |
| 3043 | 3047 | }; |
| 3044 | 3048 | } |
| 3045 | ||
| 3046 | return new_file; | |
| 3047 | 3049 | } |
| 3048 | 3050 | |
| 3049 | 3051 | pub fn scanNamespace( |
| ... | ... | @@ -3242,9 +3244,9 @@ const ScanDeclIter = struct { |
| 3242 | 3244 | // Perhaps we should add all test indiscriminately and filter at the end of the update. |
| 3243 | 3245 | if (!comp.config.is_test) break :a false; |
| 3244 | 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 | 3248 | const fqn_slice = fqn.toSlice(ip); |
| 3247 | for (comp.test_filters) |test_filter| { | |
| 3249 | for (zcu.test_filters) |test_filter| { | |
| 3248 | 3250 | if (std.mem.find(u8, fqn_slice, test_filter) != null) break; |
| 3249 | 3251 | } else break :a false; |
| 3250 | 3252 | } |
| ... | ... | @@ -4522,32 +4524,28 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4522 | 4524 | tracy_trace.addText(fqn.toSlice(ip)); |
| 4523 | 4525 | tracy_trace.addTextFmt("func_ip_index={d}", .{func_index}); |
| 4524 | 4526 | |
| 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}); | |
| 4526 | 4537 | |
| 4527 | 4538 | if (codegen.legalizeFeatures(pt, nav)) |features| { |
| 4528 | try air.legalize(pt, features); | |
| 4529 | // Verify the AIR again post-legalization. | |
| 4539 | // Verify the AIR again pre-legalization. | |
| 4530 | 4540 | Air.Verify.run(pt, func_index, air); |
| 4541 | try air.legalize(pt, features); | |
| 4531 | 4542 | } |
| 4532 | 4543 | |
| 4533 | var liveness: ?Air.Liveness = if (codegen.wantsLiveness(pt, nav)) | |
| 4534 | try .analyze(zcu, air.*, ip) | |
| 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 | } | |
| 4544 | std.log.scoped(.@"legal-air").debug("{f}", .{&ap}); | |
| 4545 | Air.Verify.run(pt, func_index, air); | |
| 4550 | 4546 | |
| 4547 | if (codegen.wantsLiveness(pt, nav)) liveness = try .analyze(zcu, air.*, ip); | |
| 4548 | std.log.scoped(.air).debug("{f}", .{&ap}); | |
| 4551 | 4549 | if (std.debug.runtime_safety) verify_liveness: { |
| 4552 | 4550 | var verify: Air.Liveness.Verify = .{ |
| 4553 | 4551 | .gpa = gpa, |
| ... | ... | @@ -4577,17 +4575,3 @@ fn runCodegenInner(pt: Zcu.PerThread, func_index: InternPool.Index, air: *Air) e |
| 4577 | 4575 | |
| 4578 | 4576 | return codegen.generateFunction(lf, pt, func_index, air, &liveness); |
| 4579 | 4577 | } |
| 4580 | ||
| 4581 | fn 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 | 10 | const Air = @import("../Air.zig"); |
| 11 | 11 | const codegen = @import("../codegen.zig"); |
| 12 | 12 | const Compilation = @import("../Compilation.zig"); |
| 13 | const debugLogScopeEnabled = @import("../main.zig").debugLogScopeEnabled; | |
| 13 | 14 | const InternPool = @import("../InternPool.zig"); |
| 14 | 15 | const link = @import("../link.zig"); |
| 15 | 16 | const Module = @import("../Module.zig"); |
| ... | ... | @@ -331,12 +332,10 @@ pub const Object = struct { |
| 331 | 332 | } |
| 332 | 333 | |
| 333 | 334 | pub const EmitOptions = struct { |
| 334 | pre_ir_path: ?[]const u8, | |
| 335 | pre_bc_path: ?[]const u8, | |
| 336 | 335 | bin_path: ?[:0]const u8, |
| 337 | 336 | asm_path: ?[:0]const u8, |
| 338 | post_ir_path: ?[:0]const u8, | |
| 339 | post_bc_path: ?[:0]const u8, | |
| 337 | opt_ir_path: ?[:0]const u8, | |
| 338 | opt_bc_path: ?[:0]const u8, | |
| 340 | 339 | |
| 341 | 340 | is_debug: bool, |
| 342 | 341 | is_small: bool, |
| ... | ... | @@ -351,6 +350,7 @@ pub const Object = struct { |
| 351 | 350 | const comp = zcu.comp; |
| 352 | 351 | const io = comp.io; |
| 353 | 352 | const diags = &comp.link_diags; |
| 353 | const target = &comp.root_mod.resolved_target.result; | |
| 354 | 354 | |
| 355 | 355 | { |
| 356 | 356 | if (o.errors_len_variable != .none) { |
| ... | ... | @@ -403,7 +403,7 @@ pub const Object = struct { |
| 403 | 403 | const behavior_max = try o.builder.metadataConstant(try o.builder.intConst(.i32, 7)); |
| 404 | 404 | const behavior_min = try o.builder.metadataConstant(try o.builder.intConst(.i32, 8)); |
| 405 | 405 | |
| 406 | if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |abi| { | |
| 406 | if (target_util.llvmMachineAbi(target)) |abi| { | |
| 407 | 407 | module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{ |
| 408 | 408 | behavior_error, |
| 409 | 409 | (try o.builder.metadataString("target-abi")).toMetadata(), |
| ... | ... | @@ -411,7 +411,7 @@ pub const Object = struct { |
| 411 | 411 | })); |
| 412 | 412 | } |
| 413 | 413 | |
| 414 | const pic_level = target_util.picLevel(&comp.root_mod.resolved_target.result); | |
| 414 | const pic_level = target_util.picLevel(target); | |
| 415 | 415 | if (comp.root_mod.pic) { |
| 416 | 416 | module_flags.appendAssumeCapacity(try o.builder.metadataTuple(&.{ |
| 417 | 417 | behavior_min, |
| ... | ... | @@ -434,7 +434,7 @@ pub const Object = struct { |
| 434 | 434 | (try o.builder.metadataString("Code Model")).toMetadata(), |
| 435 | 435 | try o.builder.metadataConstant(try o.builder.intConst(.i32, @as( |
| 436 | 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 | 438 | .default => unreachable, |
| 439 | 439 | .tiny => 0, |
| 440 | 440 | .small => 1, |
| ... | ... | @@ -480,7 +480,6 @@ pub const Object = struct { |
| 480 | 480 | } |
| 481 | 481 | } |
| 482 | 482 | |
| 483 | const target = &comp.root_mod.resolved_target.result; | |
| 484 | 483 | if (target.os.tag == .windows and (target.cpu.arch == .x86_64 or target.cpu.arch == .x86)) { |
| 485 | 484 | // Add the "RegCallv4" flag so that any functions using `x86_regcallcc` use regcall |
| 486 | 485 | // v4, which is essentially a requirement on Windows. See corresponding logic in |
| ... | ... | @@ -515,21 +514,26 @@ pub const Object = struct { |
| 515 | 514 | |
| 516 | 515 | const emit_asm_msg = options.asm_path orelse "(none)"; |
| 517 | 516 | const emit_bin_msg = options.bin_path orelse "(none)"; |
| 518 | const post_llvm_ir_msg = options.post_ir_path orelse "(none)"; | |
| 519 | const post_llvm_bc_msg = options.post_bc_path orelse "(none)"; | |
| 517 | const opt_llvm_ir_msg = options.opt_ir_path orelse "(none)"; | |
| 518 | const opt_llvm_bc_msg = options.opt_bc_path orelse "(none)"; | |
| 520 | 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"); | |
| 523 | 523 | |
| 524 | 524 | const context, const module = emit: { |
| 525 | if (options.pre_ir_path) |path| { | |
| 526 | if (std.mem.eql(u8, path, "-")) { | |
| 527 | o.builder.dump(io); | |
| 528 | } else { | |
| 529 | o.builder.printToFilePath(io, Io.Dir.cwd(), path) catch |err| { | |
| 530 | log.err("failed printing LLVM module to \"{s}\": {t}", .{ path, err }); | |
| 531 | }; | |
| 532 | } | |
| 525 | { | |
| 526 | var p: Builder.Print = .{ .name = comp.root_name, .builder = &o.builder, .err = null }; | |
| 527 | std.log.scoped(.@"llvm-ir").debug("{f}", .{&p}); | |
| 528 | if (p.err) |err| return err; | |
| 529 | } | |
| 530 | ||
| 531 | if (target.ofmt == .llvmir) { | |
| 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 | } |
| 534 | 538 | |
| 535 | 539 | const bitcode = try o.builder.toBitcode(o.gpa, .{ |
| ... | ... | @@ -538,23 +542,26 @@ pub const Object = struct { |
| 538 | 542 | }); |
| 539 | 543 | defer o.gpa.free(bitcode); |
| 540 | 544 | |
| 541 | if (options.pre_bc_path) |path| { | |
| 542 | var file = Io.Dir.cwd().createFile(io, path, .{}) catch |err| | |
| 543 | return diags.fail("failed to create '{s}': {t}", .{ path, err }); | |
| 545 | if (target.ofmt == .llvmbc) { | |
| 546 | const path = comp.bin_file.?.emit; | |
| 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 | 549 | defer file.close(io); |
| 545 | 550 | |
| 546 | 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 | } |
| 549 | 555 | |
| 550 | 556 | 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; | |
| 552 | 559 | |
| 553 | 560 | if (!build_options.have_llvm or !comp.config.use_lib_llvm) { |
| 554 | 561 | return diags.fail("emitting without libllvm not implemented", .{}); |
| 555 | 562 | } |
| 556 | 563 | |
| 557 | initializeLLVMTarget(io, comp.root_mod.resolved_target.result.cpu.arch); | |
| 564 | initializeLLVMTarget(io, target.cpu.arch); | |
| 558 | 565 | |
| 559 | 566 | const context: *bindings.Context = .create(); |
| 560 | 567 | errdefer context.dispose(); |
| ... | ... | @@ -577,9 +584,9 @@ pub const Object = struct { |
| 577 | 584 | }; |
| 578 | 585 | defer context.dispose(); |
| 579 | 586 | |
| 580 | var target: *bindings.Target = undefined; | |
| 587 | var llvm_target: *bindings.Target = undefined; | |
| 581 | 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 | 590 | defer bindings.disposeMessage(error_message); |
| 584 | 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 | 605 | else |
| 599 | 606 | .Static; |
| 600 | 607 | |
| 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 | 609 | .default => .Default, |
| 603 | 610 | .tiny => .Tiny, |
| 604 | 611 | .small => .Small, |
| ... | ... | @@ -607,24 +614,22 @@ pub const Object = struct { |
| 607 | 614 | .large => .Large, |
| 608 | 615 | }; |
| 609 | 616 | |
| 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 | 617 | var target_machine = bindings.TargetMachine.create( |
| 616 | target, | |
| 618 | llvm_target, | |
| 617 | 619 | target_triple_sentinel, |
| 618 | if (comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null, | |
| 619 | comp.root_mod.resolved_target.llvm_cpu_features.?, | |
| 620 | if (target.cpu.model.llvm_name) |s| s.ptr else null, | |
| 621 | comp.root_mod.llvm_cpu_features.?, | |
| 620 | 622 | opt_level, |
| 621 | 623 | reloc_mode, |
| 622 | 624 | code_model, |
| 623 | 625 | comp.function_sections, |
| 624 | 626 | comp.data_sections, |
| 625 | float_abi, | |
| 626 | if (target_util.llvmMachineAbi(&comp.root_mod.resolved_target.result)) |s| s.ptr else null, | |
| 627 | target_util.useEmulatedTls(&comp.root_mod.resolved_target.result), | |
| 627 | switch (target.abi.float()) { | |
| 628 | .hard => .Hard, | |
| 629 | .soft => .Soft, | |
| 630 | }, | |
| 631 | if (target_util.llvmMachineAbi(target)) |s| s.ptr else null, | |
| 632 | target_util.useEmulatedTls(target), | |
| 628 | 633 | ); |
| 629 | 634 | errdefer target_machine.dispose(); |
| 630 | 635 | |
| ... | ... | @@ -634,7 +639,10 @@ pub const Object = struct { |
| 634 | 639 | |
| 635 | 640 | // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. |
| 636 | 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 | 646 | var lowered_options: bindings.TargetMachine.EmitOptions = .{ |
| 639 | 647 | .is_debug = options.is_debug, |
| 640 | 648 | .is_small = options.is_small, |
| ... | ... | @@ -648,11 +656,12 @@ pub const Object = struct { |
| 648 | 656 | .allow_fast_isel = true, |
| 649 | 657 | // LLVM's RISC-V backend for some reason enables the machine outliner by default even |
| 650 | 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 | 660 | .asm_filename = null, |
| 653 | 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, | |
| 655 | .bitcode_filename = if (options.post_bc_path) |x| x.ptr else null, | |
| 662 | .llvm_ir_filename = if (options.opt_ir_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, | |
| 656 | 665 | |
| 657 | 666 | // `.coverage` value is only used when `.sancov` is enabled. |
| 658 | 667 | .sancov = options.fuzz or comp.config.san_cov_trace_pc_guard, |
| ... | ... | @@ -684,33 +693,31 @@ pub const Object = struct { |
| 684 | 693 | }; |
| 685 | 694 | if (options.asm_path != null and options.bin_path != null) { |
| 686 | 695 | if (target_machine.emitToFile(module, &error_message, &lowered_options)) { |
| 687 | defer bindings.disposeMessage(error_message); | |
| 688 | 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 | 700 | lowered_options.bin_filename = null; |
| 693 | 701 | lowered_options.llvm_ir_filename = null; |
| 694 | 702 | lowered_options.bitcode_filename = null; |
| 703 | lowered_options.llvm_ir_out = null; | |
| 695 | 704 | } |
| 696 | ||
| 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 | ||
| 705 | if (options.time_report) |_| lowered_options.time_report_out = &time_report_c_str; | |
| 702 | 706 | lowered_options.asm_filename = if (options.asm_path) |x| x.ptr else null; |
| 703 | 707 | if (target_machine.emitToFile(module, &error_message, &lowered_options)) { |
| 704 | 708 | defer bindings.disposeMessage(error_message); |
| 705 | 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| { | |
| 710 | defer std.c.free(time_report_c_str); | |
| 711 | const time_report_data = std.mem.span(time_report_c_str); | |
| 712 | assert(tr.llvm_pass_timings.len == 0); | |
| 713 | tr.llvm_pass_timings = try comp.gpa.dupe(u8, time_report_data); | |
| 713 | if (log_opt_llvm_ir) std.log.scoped(.@"opt-llvm-ir").debug("{s}", .{ | |
| 714 | llvm_ir_c_str orelse return error.OutOfMemory, | |
| 715 | }); | |
| 716 | if (options.time_report) |time_report| { | |
| 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 | } |
| 716 | 723 | |
| ... | ... | @@ -2184,10 +2191,10 @@ pub const Object = struct { |
| 2184 | 2191 | .value = try o.builder.string(s), |
| 2185 | 2192 | } }, &o.builder); |
| 2186 | 2193 | } |
| 2187 | if (owner_mod.resolved_target.llvm_cpu_features) |s| { | |
| 2194 | if (owner_mod.llvm_cpu_features) |s| { | |
| 2188 | 2195 | try attributes.addFnAttr(.{ .string = .{ |
| 2189 | 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 | 2198 | } }, &o.builder); |
| 2192 | 2199 | } |
| 2193 | 2200 |
src/codegen/llvm/bindings.zig+3-2| ... | ... | @@ -51,7 +51,7 @@ pub const Module = opaque { |
| 51 | 51 | }; |
| 52 | 52 | |
| 53 | 53 | pub const disposeMessage = LLVMDisposeMessage; |
| 54 | extern fn LLVMDisposeMessage(Message: [*:0]const u8) void; | |
| 54 | extern fn LLVMDisposeMessage(Message: ?[*:0]const u8) void; | |
| 55 | 55 | |
| 56 | 56 | pub const TargetMachine = opaque { |
| 57 | 57 | pub const FloatABI = enum(c_int) { |
| ... | ... | @@ -85,7 +85,7 @@ pub const TargetMachine = opaque { |
| 85 | 85 | pub const EmitOptions = extern struct { |
| 86 | 86 | is_debug: bool, |
| 87 | 87 | is_small: bool, |
| 88 | time_report_out: ?*[*:0]u8, | |
| 88 | time_report_out: ?*?[*:0]u8, | |
| 89 | 89 | tsan: bool, |
| 90 | 90 | sancov: bool, |
| 91 | 91 | lto: LtoPhase, |
| ... | ... | @@ -95,6 +95,7 @@ pub const TargetMachine = opaque { |
| 95 | 95 | bin_filename: ?[*:0]const u8, |
| 96 | 96 | llvm_ir_filename: ?[*:0]const u8, |
| 97 | 97 | bitcode_filename: ?[*:0]const u8, |
| 98 | llvm_ir_out: ?*?[*:0]u8, | |
| 98 | 99 | coverage: Coverage, |
| 99 | 100 | |
| 100 | 101 | pub const LtoPhase = enum(c_int) { |
src/codegen/riscv64/CodeGen.zig+1-1| ... | ... | @@ -27,7 +27,7 @@ const Target = std.Target; |
| 27 | 27 | const log = std.log.scoped(.riscv_codegen); |
| 28 | 28 | const tracking_log = std.log.scoped(.tracking); |
| 29 | 29 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| 30 | const wip_mir_log = std.log.scoped(.wip_mir); | |
| 30 | const wip_mir_log = std.log.scoped(.@"wip-mir"); | |
| 31 | 31 | const Alignment = InternPool.Alignment; |
| 32 | 32 | |
| 33 | 33 | const bits = @import("bits.zig"); |
src/codegen/x86_64/CodeGen.zig+1-1| ... | ... | @@ -5,7 +5,7 @@ const link = @import("../../link.zig"); |
| 5 | 5 | const log = std.log.scoped(.codegen); |
| 6 | 6 | const tracking_log = std.log.scoped(.tracking); |
| 7 | 7 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| 8 | const wip_mir_log = std.log.scoped(.wip_mir); | |
| 8 | const wip_mir_log = std.log.scoped(.@"wip-mir"); | |
| 9 | 9 | const Writer = std.Io.Writer; |
| 10 | 10 | |
| 11 | 11 | const Air = @import("../../Air.zig"); |
src/dev.zig+2| ... | ... | @@ -112,6 +112,7 @@ pub const Env = enum { |
| 112 | 112 | .loongarch_backend, |
| 113 | 113 | .spork8_backend, |
| 114 | 114 | .lld_linker, |
| 115 | .llvm_linker, | |
| 115 | 116 | .coff_linker, |
| 116 | 117 | .elf_linker, |
| 117 | 118 | .elf2_linker, |
| ... | ... | @@ -333,6 +334,7 @@ pub const Feature = enum { |
| 333 | 334 | spork8_backend, |
| 334 | 335 | |
| 335 | 336 | lld_linker, |
| 337 | llvm_linker, | |
| 336 | 338 | coff_linker, |
| 337 | 339 | elf_linker, |
| 338 | 340 | elf2_linker, |
src/libs/freebsd.zig-4| ... | ... | @@ -1120,10 +1120,6 @@ fn buildSharedLib( |
| 1120 | 1120 | .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, |
| 1121 | 1121 | .verbose_cc = comp.verbose_cc, |
| 1122 | 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 | 1123 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 1128 | 1124 | .version = version, |
| 1129 | 1125 | .version_script = .{ |
src/libs/glibc.zig-4| ... | ... | @@ -1268,10 +1268,6 @@ fn buildSharedLib( |
| 1268 | 1268 | .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, |
| 1269 | 1269 | .verbose_cc = comp.verbose_cc, |
| 1270 | 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 | 1271 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 1276 | 1272 | .version = version, |
| 1277 | 1273 | .version_script = .{ |
src/libs/libcxx.zig-8| ... | ... | @@ -260,10 +260,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError! |
| 260 | 260 | .c_source_files = c_source_files.items, |
| 261 | 261 | .verbose_cc = comp.verbose_cc, |
| 262 | 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 | 263 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 268 | 264 | .skip_linker_dependencies = true, |
| 269 | 265 | .environ_map = comp.environ_map, |
| ... | ... | @@ -445,10 +441,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr |
| 445 | 441 | .c_source_files = c_source_files.items, |
| 446 | 442 | .verbose_cc = comp.verbose_cc, |
| 447 | 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 | 444 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 453 | 445 | .skip_linker_dependencies = true, |
| 454 | 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 | 295 | .c_source_files = c_source_files.items, |
| 296 | 296 | .verbose_cc = comp.verbose_cc, |
| 297 | 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 | 298 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 303 | 299 | .skip_linker_dependencies = skip_linker_dependencies, |
| 304 | 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 | 157 | .c_source_files = &c_source_files, |
| 158 | 158 | .verbose_cc = comp.verbose_cc, |
| 159 | 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 | 160 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 165 | 161 | .skip_linker_dependencies = true, |
| 166 | 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 | 246 | .emit_bin = .yes_cache, |
| 247 | 247 | .verbose_cc = comp.verbose_cc, |
| 248 | 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 | 249 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 253 | 250 | .c_source_files = &.{ |
| 254 | 251 | .{ |
src/libs/netbsd.zig-4| ... | ... | @@ -771,10 +771,6 @@ fn buildSharedLib( |
| 771 | 771 | .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, |
| 772 | 772 | .verbose_cc = comp.verbose_cc, |
| 773 | 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 | 774 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 779 | 775 | .version = version, |
| 780 | 776 | .soname = soname, |
src/libs/openbsd.zig-4| ... | ... | @@ -691,10 +691,6 @@ fn buildSharedLib( |
| 691 | 691 | .emit_bin = .{ .yes_path = try bin_directory.join(arena, &.{basename}) }, |
| 692 | 692 | .verbose_cc = comp.verbose_cc, |
| 693 | 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 | 694 | .clang_passthrough_mode = comp.clang_passthrough_mode, |
| 699 | 695 | .soname = soname, |
| 700 | 696 | .c_source_files = &c_source_files, |
src/link.zig+35-4| ... | ... | @@ -550,6 +550,7 @@ pub const File = struct { |
| 550 | 550 | return &ptr.base; |
| 551 | 551 | }, |
| 552 | 552 | .lld => unreachable, // not known from ofmt |
| 553 | .llvm => |tag| return createDummy(arena, tag, comp, emit), | |
| 553 | 554 | } |
| 554 | 555 | } |
| 555 | 556 | |
| ... | ... | @@ -573,9 +574,26 @@ pub const File = struct { |
| 573 | 574 | return &ptr.base; |
| 574 | 575 | }, |
| 575 | 576 | .lld => unreachable, // not known from ofmt |
| 577 | .llvm => |tag| return createDummy(arena, tag, comp, emit), | |
| 576 | 578 | } |
| 577 | 579 | } |
| 578 | 580 | |
| 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 | 597 | pub fn cast(base: *File, comptime tag: Tag) if (dev.env.supports(tag.devFeature())) ?*tag.Type() else ?noreturn { |
| 580 | 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 | 624 | const gpa = comp.gpa; |
| 607 | 625 | const io = comp.io; |
| 608 | 626 | switch (base.tag) { |
| 609 | .lld => assert(base.file == null), | |
| 627 | .lld, .llvm => assert(base.file == null), | |
| 610 | 628 | .elf, .macho, .wasm => { |
| 611 | 629 | dev.checkAny(&.{ .coff_linker, .elf_linker, .macho_linker, .plan9_linker, .wasm_linker }); |
| 612 | 630 | if (base.file != null) return; |
| ... | ... | @@ -706,7 +724,7 @@ pub const File = struct { |
| 706 | 724 | if (!base.canMakeExecutable()) |
| 707 | 725 | return; |
| 708 | 726 | switch (base.tag) { |
| 709 | .lld => assert(base.file == null), | |
| 727 | .lld, .llvm => assert(base.file == null), | |
| 710 | 728 | .elf => if (base.file) |f| { |
| 711 | 729 | dev.check(.elf_linker); |
| 712 | 730 | f.close(io); |
| ... | ... | @@ -827,6 +845,7 @@ pub const File = struct { |
| 827 | 845 | |
| 828 | 846 | switch (base.tag) { |
| 829 | 847 | .lld => unreachable, |
| 848 | .llvm => unreachable, | |
| 830 | 849 | .plan9 => unreachable, |
| 831 | 850 | inline else => |tag| { |
| 832 | 851 | dev.check(tag.devFeature()); |
| ... | ... | @@ -862,6 +881,7 @@ pub const File = struct { |
| 862 | 881 | assert(pt.zcu.llvm_object == null); |
| 863 | 882 | switch (base.tag) { |
| 864 | 883 | .lld => unreachable, |
| 884 | .llvm => unreachable, | |
| 865 | 885 | .plan9 => unreachable, |
| 866 | 886 | inline else => |tag| { |
| 867 | 887 | dev.check(tag.devFeature()); |
| ... | ... | @@ -897,6 +917,7 @@ pub const File = struct { |
| 897 | 917 | } |
| 898 | 918 | switch (base.tag) { |
| 899 | 919 | .lld => unreachable, |
| 920 | .llvm => unreachable, | |
| 900 | 921 | .plan9 => unreachable, |
| 901 | 922 | .spirv => {}, |
| 902 | 923 | .coff => {}, |
| ... | ... | @@ -941,6 +962,7 @@ pub const File = struct { |
| 941 | 962 | base.releaseLock(); |
| 942 | 963 | if (base.file) |f| f.close(io); |
| 943 | 964 | switch (base.tag) { |
| 965 | .llvm => {}, | |
| 944 | 966 | .plan9 => unreachable, |
| 945 | 967 | inline else => |tag| { |
| 946 | 968 | dev.check(tag.devFeature()); |
| ... | ... | @@ -1003,6 +1025,7 @@ pub const File = struct { |
| 1003 | 1025 | } |
| 1004 | 1026 | assert(base.post_prelink); |
| 1005 | 1027 | switch (base.tag) { |
| 1028 | .llvm => {}, | |
| 1006 | 1029 | .plan9 => unreachable, |
| 1007 | 1030 | inline else => |tag| { |
| 1008 | 1031 | dev.check(tag.devFeature()); |
| ... | ... | @@ -1030,6 +1053,7 @@ pub const File = struct { |
| 1030 | 1053 | |
| 1031 | 1054 | switch (base.tag) { |
| 1032 | 1055 | .lld => unreachable, |
| 1056 | .llvm => unreachable, | |
| 1033 | 1057 | .plan9 => unreachable, |
| 1034 | 1058 | inline else => |tag| { |
| 1035 | 1059 | dev.check(tag.devFeature()); |
| ... | ... | @@ -1056,6 +1080,7 @@ pub const File = struct { |
| 1056 | 1080 | assert(base.comp.zcu.?.llvm_object == null); |
| 1057 | 1081 | switch (base.tag) { |
| 1058 | 1082 | .lld => unreachable, |
| 1083 | .llvm => unreachable, | |
| 1059 | 1084 | .c => unreachable, |
| 1060 | 1085 | .spirv => unreachable, |
| 1061 | 1086 | .wasm => unreachable, |
| ... | ... | @@ -1078,6 +1103,7 @@ pub const File = struct { |
| 1078 | 1103 | assert(pt.zcu.llvm_object == null); |
| 1079 | 1104 | switch (base.tag) { |
| 1080 | 1105 | .lld => unreachable, |
| 1106 | .llvm => unreachable, | |
| 1081 | 1107 | .c => unreachable, |
| 1082 | 1108 | .spirv => unreachable, |
| 1083 | 1109 | .wasm => unreachable, |
| ... | ... | @@ -1095,6 +1121,7 @@ pub const File = struct { |
| 1095 | 1121 | assert(base.comp.zcu.?.llvm_object == null); |
| 1096 | 1122 | switch (base.tag) { |
| 1097 | 1123 | .lld => unreachable, |
| 1124 | .llvm => unreachable, | |
| 1098 | 1125 | .c => unreachable, |
| 1099 | 1126 | .spirv => unreachable, |
| 1100 | 1127 | .wasm => unreachable, |
| ... | ... | @@ -1124,6 +1151,7 @@ pub const File = struct { |
| 1124 | 1151 | .spirv, |
| 1125 | 1152 | .plan9, |
| 1126 | 1153 | .lld, |
| 1154 | .llvm, | |
| 1127 | 1155 | .spork8, |
| 1128 | 1156 | => return .unimplemented, |
| 1129 | 1157 | inline else => |tag| { |
| ... | ... | @@ -1240,7 +1268,7 @@ pub const File = struct { |
| 1240 | 1268 | dev.check(tag.devFeature()); |
| 1241 | 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 | } |
| 1246 | 1274 | |
| ... | ... | @@ -1352,6 +1380,7 @@ pub const File = struct { |
| 1352 | 1380 | coff, |
| 1353 | 1381 | elf, |
| 1354 | 1382 | elf2, |
| 1383 | llvm, | |
| 1355 | 1384 | macho, |
| 1356 | 1385 | macho2, |
| 1357 | 1386 | c, |
| ... | ... | @@ -1366,13 +1395,14 @@ pub const File = struct { |
| 1366 | 1395 | .coff => Coff, |
| 1367 | 1396 | .elf => Elf, |
| 1368 | 1397 | .elf2 => Elf2, |
| 1398 | .llvm => File, | |
| 1369 | 1399 | .macho => MachO, |
| 1370 | 1400 | .macho2 => MachO2, |
| 1371 | 1401 | .c => C, |
| 1372 | 1402 | .wasm => Wasm, |
| 1373 | 1403 | .spirv => Spirv, |
| 1374 | 1404 | .lld => Lld, |
| 1375 | .plan9 => comptime unreachable, | |
| 1405 | .plan9 => unreachable, | |
| 1376 | 1406 | .spork8 => Spork8, |
| 1377 | 1407 | }; |
| 1378 | 1408 | } |
| ... | ... | @@ -1381,6 +1411,7 @@ pub const File = struct { |
| 1381 | 1411 | return switch (ofmt) { |
| 1382 | 1412 | .coff => .coff, |
| 1383 | 1413 | .elf => if (use_new_linker) .elf2 else .elf, |
| 1414 | .llvmbc, .llvmir => .llvm, | |
| 1384 | 1415 | .macho => if (use_new_linker) .macho2 else .macho, |
| 1385 | 1416 | .wasm => .wasm, |
| 1386 | 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 | 860 | |
| 861 | 861 | // Dump the state for easy debugging. |
| 862 | 862 | // State can be dumped via `--debug-log link_state`. |
| 863 | if (build_options.enable_logging) { | |
| 864 | state_log.debug("{f}", .{self.dumpState()}); | |
| 865 | } | |
| 863 | state_log.debug("{f}", .{self.dumpState()}); | |
| 866 | 864 | |
| 867 | 865 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 868 | 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 | 291 | if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; |
| 292 | 292 | } |
| 293 | 293 | |
| 294 | if (build_options.enable_logging) { | |
| 294 | if (build_options.enable_debug_extensions) { | |
| 295 | 295 | const active = elf_file.base.comp.zcu.?.activate(tid); |
| 296 | 296 | defer active.deactivate(); |
| 297 | 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 | 98 | } |
| 99 | 99 | |
| 100 | 100 | fn 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(); | |
| 102 | 102 | |
| 103 | 103 | assert(atom.visited); |
| 104 | 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 | 51 | try allocateAllocSections(elf_file); |
| 52 | 52 | try elf_file.allocateNonAllocSections(); |
| 53 | 53 | |
| 54 | if (build_options.enable_logging) { | |
| 55 | state_log.debug("{f}", .{elf_file.dumpState()}); | |
| 56 | } | |
| 54 | state_log.debug("{f}", .{elf_file.dumpState()}); | |
| 57 | 55 | |
| 58 | 56 | try elf_file.writeMergeSections(); |
| 59 | 57 | try writeSyntheticSections(elf_file); |
| ... | ... | @@ -117,10 +115,8 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation) !void { |
| 117 | 115 | break :blk pos; |
| 118 | 116 | }; |
| 119 | 117 | |
| 120 | if (build_options.enable_logging) { | |
| 121 | state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)}); | |
| 122 | state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); | |
| 123 | } | |
| 118 | state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(elf_file)}); | |
| 119 | state_log.debug("ar_strtab\n{f}\n", .{ar_strtab}); | |
| 124 | 120 | |
| 125 | 121 | const buffer = try gpa.alloc(u8, total_size); |
| 126 | 122 | defer gpa.free(buffer); |
| ... | ... | @@ -193,9 +189,7 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation) !void { |
| 193 | 189 | try allocateAllocSections(elf_file); |
| 194 | 190 | try elf_file.allocateNonAllocSections(); |
| 195 | 191 | |
| 196 | if (build_options.enable_logging) { | |
| 197 | state_log.debug("{f}", .{elf_file.dumpState()}); | |
| 198 | } | |
| 192 | state_log.debug("{f}", .{elf_file.dumpState()}); | |
| 199 | 193 | |
| 200 | 194 | try writeAtoms(elf_file); |
| 201 | 195 | try elf_file.writeMergeSections(); |
src/link/MachO.zig+1-3| ... | ... | @@ -456,9 +456,7 @@ pub fn flush( |
| 456 | 456 | self.allocateSegments(); |
| 457 | 457 | self.allocateSyntheticSymbols(); |
| 458 | 458 | |
| 459 | if (build_options.enable_logging) { | |
| 460 | state_log.debug("{f}", .{self.dumpState()}); | |
| 461 | } | |
| 459 | state_log.debug("{f}", .{self.dumpState()}); | |
| 462 | 460 | |
| 463 | 461 | // Beyond this point, everything has been allocated a virtual address and we can resolve |
| 464 | 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 | 123 | atom.getName(macho_file), |
| 124 | 124 | }); |
| 125 | 125 | |
| 126 | if (build_options.enable_logging) | |
| 126 | if (build_options.enable_debug_extensions) { | |
| 127 | 127 | track_live_level.incr(); |
| 128 | } | |
| 128 | 129 | |
| 129 | 130 | for (atom.getRelocs(macho_file)) |rel| { |
| 130 | 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 | 61 | }; |
| 62 | 62 | allocateSegment(macho_file); |
| 63 | 63 | |
| 64 | if (build_options.enable_logging) { | |
| 65 | state_log.debug("{f}", .{macho_file.dumpState()}); | |
| 66 | } | |
| 64 | state_log.debug("{f}", .{macho_file.dumpState()}); | |
| 67 | 65 | |
| 68 | 66 | try writeSections(macho_file); |
| 69 | 67 | sortRelocs(macho_file); |
| ... | ... | @@ -107,9 +105,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { |
| 107 | 105 | return diags.fail("failed to allocate sections: {s}", .{@errorName(err)}); |
| 108 | 106 | allocateSegment(macho_file); |
| 109 | 107 | |
| 110 | if (build_options.enable_logging) { | |
| 111 | state_log.debug("{f}", .{macho_file.dumpState()}); | |
| 112 | } | |
| 108 | state_log.debug("{f}", .{macho_file.dumpState()}); | |
| 113 | 109 | |
| 114 | 110 | try writeSections(macho_file); |
| 115 | 111 | sortRelocs(macho_file); |
| ... | ... | @@ -185,9 +181,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation) link.Error!void { |
| 185 | 181 | break :blk pos; |
| 186 | 182 | }; |
| 187 | 183 | |
| 188 | if (build_options.enable_logging) { | |
| 189 | state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); | |
| 190 | } | |
| 184 | state_log.debug("ar_symtab\n{f}\n", .{ar_symtab.fmt(macho_file)}); | |
| 191 | 185 | |
| 192 | 186 | const buffer = try gpa.alloc(u8, total_size); |
| 193 | 187 | defer gpa.free(buffer); |
src/main.zig+42-79| ... | ... | @@ -42,11 +42,8 @@ const thread_stack_size = 60 << 20; |
| 42 | 42 | |
| 43 | 43 | pub const std_options: std.Options = .{ |
| 44 | 44 | .logFn = log, |
| 45 | ||
| 46 | .log_level = switch (builtin.mode) { | |
| 47 | .debug => .debug, | |
| 48 | .safe, .fast => .info, | |
| 49 | .small => .err, | |
| 45 | .log_level = switch (build_options.log_level) { | |
| 46 | inline else => |log_level| @field(std.log.Level, @tagName(log_level)), | |
| 50 | 47 | }, |
| 51 | 48 | }; |
| 52 | 49 | pub const std_options_cwd = if (native_os == .wasi) wasi_cwd else null; |
| ... | ... | @@ -104,7 +101,7 @@ const normal_usage = |
| 104 | 101 | \\ help Print this help and exit |
| 105 | 102 | \\ cache-cat Print a zig-cache manifest file as zon |
| 106 | 103 | \\ std View standard library documentation in a browser |
| 107 | \\ libc Display native libc paths file or validate one | |
| 104 | \\ libc Print native libc paths file or validate one | |
| 108 | 105 | \\ targets List available compilation targets |
| 109 | 106 | \\ version Print version number and exit |
| 110 | 107 | \\ zen Print Zen of Zig and exit |
| ... | ... | @@ -126,7 +123,15 @@ const debug_usage = normal_usage ++ |
| 126 | 123 | |
| 127 | 124 | const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage; |
| 128 | 125 | |
| 129 | var log_scopes: std.ArrayList([]const u8) = .empty; | |
| 126 | var log_scopes: std.array_hash_map.String(void) = .empty; | |
| 127 | ||
| 128 | pub 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 | } | |
| 130 | 135 | |
| 131 | 136 | pub fn log( |
| 132 | 137 | comptime level: std.log.Level, |
| ... | ... | @@ -135,18 +140,11 @@ pub fn log( |
| 135 | 140 | args: anytype, |
| 136 | 141 | ) void { |
| 137 | 142 | // Hide debug messages unless: |
| 138 | // * logging enabled with `-Dlog`. | |
| 143 | // * logging enabled with `-Ddebug-extensions` or `-Dlog=debug`. | |
| 139 | 144 | // * the --debug-log arg for the scope has been provided |
| 140 | if (@backingInt(level) > @backingInt(std.options.log_level) or | |
| 141 | @backingInt(level) > @backingInt(std.log.Level.info)) | |
| 142 | { | |
| 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; | |
| 145 | switch (level) { | |
| 146 | else => {}, | |
| 147 | .debug => if (!debugLogScopeEnabled(@tagName(scope))) return, | |
| 150 | 148 | } |
| 151 | 149 | |
| 152 | 150 | // Otherwise, use the default implementation. |
| ... | ... | @@ -557,11 +555,14 @@ const compile_usage = |
| 557 | 555 | \\ -fno-emit-docs (default) Do not produce docs/ dir with html documentation |
| 558 | 556 | \\ -femit-implib[=path] (default) Produce an import .lib when building a Windows DLL |
| 559 | 557 | \\ -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 | 558 | \\ --cache-dir [path] Override the local cache directory |
| 562 | 559 | \\ --global-cache-dir [path] Override the global cache directory |
| 563 | 560 | \\ --zig-lib-dir [path] Override path to Zig installation lib directory |
| 564 | 561 | \\ --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 | 567 | \\Global Compile Options: |
| 567 | 568 | \\ --name [name] Compilation unit name (not a file path) |
| ... | ... | @@ -593,7 +594,6 @@ const compile_usage = |
| 593 | 594 | \\ -fpatchable-function-entry=[num] Add num NOPs of padding in function prologues |
| 594 | 595 | \\ -mexec-model=[value] (WASI) Execution model |
| 595 | 596 | \\ -municode (Windows) Use wmain/wWinMain as entry point |
| 596 | \\ --time-report Send timing diagnostics to '--listen' clients | |
| 597 | 597 | \\ |
| 598 | 598 | \\Per-Module Compile Options: |
| 599 | 599 | \\ --dep [[import=]name] Add an entry to the next module's import table |
| ... | ... | @@ -604,13 +604,15 @@ const compile_usage = |
| 604 | 604 | \\ safe Enable both safety checks and machine code optimizations |
| 605 | 605 | \\ small Prioritize small binary size. Safety checks off. |
| 606 | 606 | \\ -ofmt=[fmt] Override target object format |
| 607 | \\ elf Executable and Linking Format | |
| 608 | 607 | \\ c C source code |
| 609 | \\ wasm WebAssembly | |
| 610 | 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 | 612 | \\ macho macOS relocatables |
| 612 | \\ spirv Standard, Portable Intermediate Representation V (SPIR-V) | |
| 613 | 613 | \\ plan9 Plan 9 from Bell Labs object format |
| 614 | \\ spirv Standard, Portable Intermediate Representation V (SPIR-V) | |
| 615 | \\ wasm WebAssembly | |
| 614 | 616 | \\ hex (planned feature) Intel IHEX |
| 615 | 617 | \\ raw (planned feature) Dump machine code directly |
| 616 | 618 | \\ -mcpu [cpu] Specify target CPU and feature set |
| ... | ... | @@ -791,15 +793,6 @@ const compile_usage = |
| 791 | 793 | \\Debug Options (Zig Compiler Development): |
| 792 | 794 | \\ -fopt-bisect-limit=[limit] Only run [limit] first LLVM optimization passes |
| 793 | 795 | \\ -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 | 796 | \\ --debug-log [scope] Enable printing debug/info log messages for scope |
| 804 | 797 | \\ --debug-compile-errors Crash with helpful diagnostics at the first compile error |
| 805 | 798 | \\ --debug-link-snapshot Dump linker state and output file information for troubleshooting |
| ... | ... | @@ -933,17 +926,11 @@ fn buildOutputType( |
| 933 | 926 | var listen: Listen = .none; |
| 934 | 927 | var debug_compile_errors = false; |
| 935 | 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 | 929 | var verbose_cc = (native_os != .wasi or builtin.link_libc) and |
| 939 | 930 | EnvVar.ZIG_VERBOSE_CC.isSet(environ_map); |
| 940 | var verbose_air = false; | |
| 941 | var verbose_intern_pool = false; | |
| 942 | var verbose_generic_instances = false; | |
| 943 | var verbose_llvm_ir: ?[]const u8 = null; | |
| 944 | var verbose_llvm_bc: ?[]const u8 = null; | |
| 931 | var verbose_link = (native_os != .wasi or builtin.link_libc) and | |
| 932 | EnvVar.ZIG_VERBOSE_LINK.isSet(environ_map); | |
| 945 | 933 | var link_depfile: ?[]const u8 = null; |
| 946 | var verbose_llvm_cpu_features = false; | |
| 947 | 934 | var time_report = false; |
| 948 | 935 | var stack_report = false; |
| 949 | 936 | var show_builtin = false; |
| ... | ... | @@ -1809,24 +1796,10 @@ fn buildOutputType( |
| 1809 | 1796 | } else { |
| 1810 | 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 | 1799 | } else if (mem.eql(u8, arg, "--verbose-cc")) { |
| 1815 | 1800 | verbose_cc = true; |
| 1816 | } else if (mem.eql(u8, arg, "--verbose-air")) { | |
| 1817 | verbose_air = 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; | |
| 1801 | } else if (mem.eql(u8, arg, "--verbose-link")) { | |
| 1802 | verbose_link = true; | |
| 1830 | 1803 | } else if (mem.cutPrefix(u8, arg, "-T")) |rest| { |
| 1831 | 1804 | linker_script = rest; |
| 1832 | 1805 | } else if (mem.cutPrefix(u8, arg, "-L")) |rest| { |
| ... | ... | @@ -3395,7 +3368,7 @@ fn buildOutputType( |
| 3395 | 3368 | const target = &main_mod.resolved_target.result; |
| 3396 | 3369 | |
| 3397 | 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 | 3372 | fatal("cannot emit {s} binary with the LLVM backend; only '-femit-asm' is supported", .{ |
| 3400 | 3373 | @tagName(target.cpu.arch), |
| 3401 | 3374 | }); |
| ... | ... | @@ -3729,13 +3702,7 @@ fn buildOutputType( |
| 3729 | 3702 | .libc_installation = if (create_module.libc_installation) |*lci| lci else null, |
| 3730 | 3703 | .verbose_cc = verbose_cc, |
| 3731 | 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 | 3705 | .link_depfile = link_depfile, |
| 3738 | .verbose_llvm_cpu_features = verbose_llvm_cpu_features, | |
| 3739 | 3706 | .time_report = time_report, |
| 3740 | 3707 | .stack_report = stack_report, |
| 3741 | 3708 | .build_id = build_id, |
| ... | ... | @@ -3956,10 +3923,10 @@ fn buildOutputType( |
| 3956 | 3923 | }); |
| 3957 | 3924 | } |
| 3958 | 3925 | |
| 3959 | try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.items.len + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); | |
| 3960 | for (log_scopes.items) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); | |
| 3961 | if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); | |
| 3926 | try test_exec_args.ensureUnusedCapacity(arena, 2 * log_scopes.count() + @intFromBool(verbose_link) + @intFromBool(verbose_cc)); | |
| 3927 | for (log_scopes.keys()) |log_scope| test_exec_args.appendSliceAssumeCapacity(&.{ "--debug-log", log_scope }); | |
| 3962 | 3928 | if (verbose_cc) test_exec_args.appendAssumeCapacity("--verbose-cc"); |
| 3929 | if (verbose_link) test_exec_args.appendAssumeCapacity("--verbose-link"); | |
| 3963 | 3930 | } |
| 3964 | 3931 | |
| 3965 | 3932 | try runOrTest( |
| ... | ... | @@ -4446,13 +4413,12 @@ fn serve( |
| 4446 | 4413 | switch (hdr.tag) { |
| 4447 | 4414 | .exit => return cleanExit(io), |
| 4448 | 4415 | .update => { |
| 4449 | file_system_inputs.clearRetainingCapacity(); | |
| 4450 | ||
| 4451 | 4416 | if (arg_mode == .translate_c) { |
| 4452 | 4417 | var arena_instance = std.heap.ArenaAllocator.init(gpa); |
| 4453 | 4418 | defer arena_instance.deinit(); |
| 4454 | 4419 | const arena = arena_instance.allocator(); |
| 4455 | 4420 | var output: Compilation.TranslateCResult = undefined; |
| 4421 | file_system_inputs.clearRetainingCapacity(); | |
| 4456 | 4422 | try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map); |
| 4457 | 4423 | defer output.deinit(gpa); |
| 4458 | 4424 | |
| ... | ... | @@ -4470,7 +4436,6 @@ fn serve( |
| 4470 | 4436 | |
| 4471 | 4437 | continue; |
| 4472 | 4438 | } |
| 4473 | ||
| 4474 | 4439 | try comp.makeBinFileWritable(); |
| 4475 | 4440 | try comp.update(main_progress_node); |
| 4476 | 4441 | try comp.makeBinFileExecutable(); |
| ... | ... | @@ -4496,7 +4461,6 @@ fn serve( |
| 4496 | 4461 | //); |
| 4497 | 4462 | }, |
| 4498 | 4463 | .hot_update => { |
| 4499 | file_system_inputs.clearRetainingCapacity(); | |
| 4500 | 4464 | if (child_pid) |pid| { |
| 4501 | 4465 | try comp.hotCodeSwap(main_progress_node, pid); |
| 4502 | 4466 | try serveUpdateResults(&server, comp); |
| ... | ... | @@ -5627,17 +5591,17 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: |
| 5627 | 5591 | } |
| 5628 | 5592 | } |
| 5629 | 5593 | |
| 5630 | const display_path = zig_source_path orelse "<stdin>"; | |
| 5594 | const print_path = zig_source_path orelse "<stdin>"; | |
| 5631 | 5595 | const source: [:0]const u8 = s: { |
| 5632 | 5596 | var f = if (zig_source_path) |p| file: { |
| 5633 | 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 | 5600 | } else Io.File.stdin(); |
| 5637 | 5601 | defer if (zig_source_path != null) f.close(io); |
| 5638 | 5602 | var file_reader: Io.File.Reader = f.reader(io, &stdin_buffer); |
| 5639 | 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 | }; |
| 5643 | 5607 | |
| ... | ... | @@ -5661,7 +5625,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: |
| 5661 | 5625 | |
| 5662 | 5626 | if (zir.hasCompileErrors()) { |
| 5663 | 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 | 5629 | var error_bundle = try wip_errors.toOwnedBundle(""); |
| 5666 | 5630 | try error_bundle.renderToStderr(io, .{}, color); |
| 5667 | 5631 | if (zir.loweringFailed()) { |
| ... | ... | @@ -5731,7 +5695,7 @@ fn cmdAstCheck(arena: Allocator, io: Io, args: []const []const u8, environ_map: |
| 5731 | 5695 | const zoir = try ZonGen.generate(arena, tree, .{}); |
| 5732 | 5696 | if (zoir.hasCompileErrors()) { |
| 5733 | 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 | 5699 | var error_bundle = try wip_errors.toOwnedBundle(""); |
| 5736 | 5700 | error_bundle.renderToStderr(io, .{}, color) catch {}; |
| 5737 | 5701 | process.exit(1); |
| ... | ... | @@ -6254,9 +6218,8 @@ fn randInt(io: Io, comptime T: type) T { |
| 6254 | 6218 | } |
| 6255 | 6219 | |
| 6256 | 6220 | fn addDebugLog(arena: Allocator, scope_name: []const u8) error{OutOfMemory}!void { |
| 6257 | if (!build_options.enable_logging) { | |
| 6258 | warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}); | |
| 6259 | } else { | |
| 6260 | try log_scopes.append(arena, scope_name); | |
| 6221 | switch (build_options.log_level) { | |
| 6222 | else => warn("Zig was compiled without logging enabled (-Dlog). --debug-log has no effect.", .{}), | |
| 6223 | .debug => try log_scopes.put(arena, try arena.dupe(u8, 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 | 193 | .coff, |
| 194 | 194 | .elf, |
| 195 | 195 | .hex, |
| 196 | .llvmbc, | |
| 197 | .llvmir, | |
| 196 | 198 | .macho, |
| 197 | 199 | .spirv, |
| 198 | 200 | .raw, |
src/zig_llvm.cpp+5-3| ... | ... | @@ -410,6 +410,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi |
| 410 | 410 | // Code generation phase |
| 411 | 411 | codegen_pm.run(llvm_module); |
| 412 | 412 | |
| 413 | if (options->llvm_ir_out != nullptr) { | |
| 414 | *options->llvm_ir_out = LLVMPrintModuleToString(module_ref); | |
| 415 | } | |
| 416 | ||
| 413 | 417 | if (options->llvm_ir_filename) { |
| 414 | 418 | if (LLVMPrintModuleToFile(module_ref, options->llvm_ir_filename, error_message)) { |
| 415 | 419 | return true; |
| ... | ... | @@ -430,9 +434,7 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi |
| 430 | 434 | auto os = raw_string_ostream(out_str); |
| 431 | 435 | TimerGroup::printAll(os); |
| 432 | 436 | TimerGroup::clearAll(); |
| 433 | auto c_str = (char *)malloc(out_str.length() + 1); | |
| 434 | strcpy(c_str, out_str.c_str()); | |
| 435 | *options->time_report_out = c_str; | |
| 437 | *options->time_report_out = LLVMCreateMessage(out_str.c_str()); | |
| 436 | 438 | } |
| 437 | 439 | return false; |
| 438 | 440 | } |
src/zig_llvm.h+6-2| ... | ... | @@ -67,8 +67,8 @@ struct ZigLLVMEmitOptions { |
| 67 | 67 | bool is_debug; |
| 68 | 68 | bool is_small; |
| 69 | 69 | // If not null, and `ZigLLVMTargetMachineEmitToFile` returns `false` indicating success, this |
| 70 | // `char *` will be populated with a `malloc`-allocated string containing the serialized (as | |
| 71 | // JSON) time report data. The caller is responsible for freeing that memory. | |
| 70 | // `char *` will be populated with the serialized (as JSON) time report data. The caller is | |
| 71 | // responsible for freeing that memory with `disposeMessage`. | |
| 72 | 72 | char **time_report_out; |
| 73 | 73 | bool tsan; |
| 74 | 74 | bool sancov; |
| ... | ... | @@ -79,6 +79,10 @@ struct ZigLLVMEmitOptions { |
| 79 | 79 | const char *bin_filename; |
| 80 | 80 | const char *llvm_ir_filename; |
| 81 | 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 | 86 | ZigLLVMCoverageOptions coverage; |
| 83 | 87 | }; |
| 84 | 88 |
stage1/config.zig.in+1-1| ... | ... | @@ -6,7 +6,7 @@ pub const llvm_has_xtensa = false; |
| 6 | 6 | pub const version: [:0]const u8 = "@RESOLVED_ZIG_VERSION@"; |
| 7 | 7 | pub const semver = @import("std").SemanticVersion.parse(version) catch unreachable; |
| 8 | 8 | pub const enable_debug_extensions = false; |
| 9 | pub const enable_logging = false; | |
| 9 | pub const log_level: @import("std").log.Level = .err; | |
| 10 | 10 | pub const enable_link_snapshots = false; |
| 11 | 11 | pub const enable_tracy = false; |
| 12 | 12 | pub const value_tracing = false; |
test/Runner.zig created+2605| ... | ... | @@ -0,0 +1,2605 @@ |
| 1 | const assert = std.debug.assert; | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const std = @import("std"); | |
| 4 | const 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 | |
| 12 | pub 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 | ||
| 256 | gpa: std.mem.Allocator, | |
| 257 | arena: *std.heap.ArenaAllocator, | |
| 258 | environ_map: std.process.Environ.Map, | |
| 259 | io: std.Io, | |
| 260 | prog_node: std.Progress.Node, | |
| 261 | args: Args, | |
| 262 | host: std.Target, | |
| 263 | server: std.zig.Server, | |
| 264 | eb_wip: std.zig.ErrorBundle.Wip, | |
| 265 | ||
| 266 | const 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 | ||
| 304 | fn 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 | ||
| 312 | const FailError = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable; | |
| 313 | fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError { | |
| 314 | return runner.failString(try runner.eb_wip.printString(fmt, args)); | |
| 315 | } | |
| 316 | fn failString(runner: *Runner, msg: std.zig.ErrorBundle.String) FailError { | |
| 317 | try runner.eb_wip.addRootErrorMessage(.{ .msg = msg }); | |
| 318 | return error.AlreadyReported; | |
| 319 | } | |
| 320 | ||
| 321 | pub const ProtocolError = error{ | |
| 322 | ServerReadFailed, | |
| 323 | ServerWriteFailed, | |
| 324 | ServerEndOfStream, | |
| 325 | } || FailError; | |
| 326 | pub 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 | ||
| 620 | fn 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 | } | |
| 629 | fn 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 | ||
| 645 | pub 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 | }; | |
| 786 | pub 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 | ||
| 832 | const 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 | ||
| 899 | const TestError = error{ | |
| 900 | SkipTest, | |
| 901 | } || FailError; | |
| 902 | fn 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 | } | |
| 1109 | const Command = enum { todo, skip, exe, lib, obj, write, delete, update, check }; | |
| 1110 | fn 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 | ||
| 1409 | fn 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 | } | |
| 1588 | const 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 | ||
| 2121 | const 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 | }; | |
| 2142 | pub 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 | } | |
| 2403 | fn 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 | 1209 | assert(slice[2] == 0); |
| 1210 | 1210 | } |
| 1211 | 1211 | } |
| 1212 | ||
| 1213 | test "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 | 9 | llvm_has_xtensa: bool, |
| 10 | 10 | }; |
| 11 | 11 | |
| 12 | pub fn addCases(cases: *Cases, build_options: BuildOptions, b: *std.Build) !void { | |
| 12 | pub fn addCases(cases: *Cases, b: *std.Build) !void { | |
| 13 | 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 @@ |
| 1 | const E = enum {}; | |
| 2 | const U = union { | |
| 3 | foo: struct { a: u8, b: noreturn }, | |
| 4 | bar: E, | |
| 5 | }; | |
| 6 | export 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 | } | |
| 13 | export 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 | } | |
| 22 | export 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 | } | |
| 29 | export 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const E = enum {}; | |
| 12 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const E = enum {}; | |
| 12 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub 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 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const E = enum {}; | |
| 12 | pub 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 | 9 | } |
| 10 | 10 | |
| 11 | 11 | const U = union { |
| 12 | foo: struct { a: u8, b: noreturn, }, | |
| 12 | foo: struct { a: u8, b: noreturn }, | |
| 13 | 13 | bar: enum {}, |
| 14 | 14 | }; |
| 15 | 15 | pub fn main() error{TestFailed}!void { |
test/cases/safety/load_uninstantiable_union_from_slice.zig deleted-24| ... | ... | @@ -1,24 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | pub 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 | ||
| 11 | const U = union { | |
| 12 | foo: struct { a: u8, b: noreturn, }, | |
| 13 | bar: enum {}, | |
| 14 | }; | |
| 15 | pub 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 | 3 | -Mroot=basic.zig |
| 4 | 4 | #} |
| 5 | 5 | |
| 6 | #write basic.zig basic.zig | |
| 6 | #write basic.zig @basic.zig | |
| 7 | 7 | #update |
| 8 | #check lldb lldb | |
| 8 | #check lldb @lldb |
test/debugger/enums+5-7| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | #todo { | |
| 2 | passes, but prints errors | |
| 3 | #} | |
| 4 | #skip x86_64-linux-none-whole-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-whole-selfhosted-new-pic | |
| 6 | #skip x86_64-linux-none-incremental-selfhosted-new-nopic | |
| 7 | #skip x86_64-linux-none-incremental-selfhosted-new-pic | |
| 1 | #todo "passes, but prints errors" | |
| 2 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic | |
| 3 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-pic | |
| 4 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic | |
| 8 | 6 | |
| 9 | 7 | #exe { |
| 10 | 8 | --name enums |
test/debugger/errors+5-7| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | #todo { | |
| 2 | passes, but prints errors | |
| 3 | #} | |
| 4 | #skip x86_64-linux-none-whole-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-whole-selfhosted-new-pic | |
| 6 | #skip x86_64-linux-none-incremental-selfhosted-new-nopic | |
| 7 | #skip x86_64-linux-none-incremental-selfhosted-new-pic | |
| 1 | #todo "passes, but prints errors" | |
| 2 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic | |
| 3 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-pic | |
| 4 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic | |
| 8 | 6 | |
| 9 | 7 | #exe { |
| 10 | 8 | --name errors |
test/debugger/inline_call/manifest+8-10| ... | ... | @@ -1,8 +1,6 @@ |
| 1 | #todo { | |
| 2 | implement inline line info in lldb | |
| 3 | #} | |
| 4 | #skip x86_64-linux-none-incremental-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-incremental-selfhosted-new-pic | |
| 1 | #todo "implement inline line info in lldb" | |
| 2 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic | |
| 3 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic | |
| 6 | 4 | |
| 7 | 5 | #exe { |
| 8 | 6 | --name inline_call |
| ... | ... | @@ -10,9 +8,9 @@ implement inline line info in lldb |
| 10 | 8 | -Mmodule=mod0.zig |
| 11 | 9 | #} |
| 12 | 10 | |
| 13 | #write root0.zig root0.zig | |
| 14 | #write root1.zig root1.zig | |
| 15 | #write mod0.zig mod0.zig | |
| 16 | #write mod1.zig mod1.zig | |
| 11 | #write root0.zig @root0.zig | |
| 12 | #write root1.zig @root1.zig | |
| 13 | #write mod0.zig @mod0.zig | |
| 14 | #write mod1.zig @mod1.zig | |
| 17 | 15 | #update |
| 18 | #check lldb lldb | |
| 16 | #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 | 3 | -Mroot=main.zig |
| 4 | 4 | #} |
| 5 | 5 | |
| 6 | #write main.zig main.zig | |
| 6 | #write main.zig @main.zig | |
| 7 | 7 | #update |
| 8 | #check lldb lldb | |
| 8 | #check lldb @lldb |
test/debugger/step_single_stmt_loops/manifest+2-2| ... | ... | @@ -3,6 +3,6 @@ |
| 3 | 3 | -Mroot=step_single_stmt_loops.zig |
| 4 | 4 | #} |
| 5 | 5 | |
| 6 | #write step_single_stmt_loops.zig step_single_stmt_loops.zig | |
| 6 | #write step_single_stmt_loops.zig @step_single_stmt_loops.zig | |
| 7 | 7 | #update |
| 8 | #check lldb lldb | |
| 8 | #check lldb @lldb |
test/debugger/unions+5-7| ... | ... | @@ -1,10 +1,8 @@ |
| 1 | #todo { | |
| 2 | passes, but prints errors | |
| 3 | #} | |
| 4 | #skip x86_64-linux-none-whole-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-whole-selfhosted-new-pic | |
| 6 | #skip x86_64-linux-none-incremental-selfhosted-new-nopic | |
| 7 | #skip x86_64-linux-none-incremental-selfhosted-new-pic | |
| 1 | #todo "passes, but prints errors" | |
| 2 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-nopic | |
| 3 | #skip x86_64-linux-none-baseline-whole-selfhosted-new-pic | |
| 4 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-nopic | |
| 5 | #skip x86_64-linux-none-baseline-incremental-selfhosted-new-pic | |
| 8 | 6 | |
| 9 | 7 | #exe { |
| 10 | 8 | --name unions |
test/incremental/add_decl+5-10| ... | ... | @@ -24,8 +24,7 @@ const foo = "good morning\n"; |
| 24 | 24 | const bar = "good evening\n"; |
| 25 | 25 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 26 | 26 | #} |
| 27 | #update { | |
| 28 | add new declaration#} | |
| 27 | #update "add new declaration" | |
| 29 | 28 | #check stdout { |
| 30 | 29 | good morning |
| 31 | 30 | #} |
| ... | ... | @@ -39,8 +38,7 @@ const foo = "good morning\n"; |
| 39 | 38 | const bar = "good evening\n"; |
| 40 | 39 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 41 | 40 | #} |
| 42 | #update { | |
| 43 | reference new declaration#} | |
| 41 | #update "reference new declaration" | |
| 44 | 42 | #check stdout { |
| 45 | 43 | good evening |
| 46 | 44 | #} |
| ... | ... | @@ -54,8 +52,7 @@ const foo = "good morning\n"; |
| 54 | 52 | const bar = "good evening\n"; |
| 55 | 53 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 56 | 54 | #} |
| 57 | #update { | |
| 58 | reference missing declaration#} | |
| 55 | #update "reference missing declaration" | |
| 59 | 56 | #check errors { |
| 60 | 57 | main.zig:3:52: error: use of undeclared identifier 'qux' |
| 61 | 58 | #} |
| ... | ... | @@ -70,8 +67,7 @@ const bar = "good evening\n"; |
| 70 | 67 | const qux = "good night\n"; |
| 71 | 68 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 72 | 69 | #} |
| 73 | #update { | |
| 74 | add missing declaration#} | |
| 70 | #update "add missing declaration" | |
| 75 | 71 | #check stdout { |
| 76 | 72 | good night |
| 77 | 73 | #} |
| ... | ... | @@ -84,8 +80,7 @@ pub fn main() !void { |
| 84 | 80 | const qux = "good night\n"; |
| 85 | 81 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 86 | 82 | #} |
| 87 | #update { | |
| 88 | remove unused declarations#} | |
| 83 | #update "remove unused declarations" | |
| 89 | 84 | #check stdout { |
| 90 | 85 | good night |
| 91 | 86 | #} |
test/incremental/add_decl_namespaced+5-10| ... | ... | @@ -24,8 +24,7 @@ const foo = "good morning\n"; |
| 24 | 24 | const bar = "good evening\n"; |
| 25 | 25 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 26 | 26 | #} |
| 27 | #update { | |
| 28 | add new declaration#} | |
| 27 | #update "add new declaration" | |
| 29 | 28 | #check stdout { |
| 30 | 29 | good morning |
| 31 | 30 | #} |
| ... | ... | @@ -39,8 +38,7 @@ const foo = "good morning\n"; |
| 39 | 38 | const bar = "good evening\n"; |
| 40 | 39 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 41 | 40 | #} |
| 42 | #update { | |
| 43 | reference new declaration#} | |
| 41 | #update "reference new declaration" | |
| 44 | 42 | #check stdout { |
| 45 | 43 | good evening |
| 46 | 44 | #} |
| ... | ... | @@ -54,8 +52,7 @@ const foo = "good morning\n"; |
| 54 | 52 | const bar = "good evening\n"; |
| 55 | 53 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 56 | 54 | #} |
| 57 | #update { | |
| 58 | reference missing declaration#} | |
| 55 | #update "reference missing declaration" | |
| 59 | 56 | #check errors { |
| 60 | 57 | main.zig:3:59: error: root source file struct 'main' has no member named 'qux' |
| 61 | 58 | main.zig:1:1: note: struct declared here |
| ... | ... | @@ -71,8 +68,7 @@ const bar = "good evening\n"; |
| 71 | 68 | const qux = "good night\n"; |
| 72 | 69 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 73 | 70 | #} |
| 74 | #update { | |
| 75 | add missing declaration#} | |
| 71 | #update "add missing declaration" | |
| 76 | 72 | #check stdout { |
| 77 | 73 | good night |
| 78 | 74 | #} |
| ... | ... | @@ -85,8 +81,7 @@ pub fn main() !void { |
| 85 | 81 | const qux = "good night\n"; |
| 86 | 82 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 87 | 83 | #} |
| 88 | #update { | |
| 89 | remove unused declarations#} | |
| 84 | #update "remove unused declarations" | |
| 90 | 85 | #check stdout { |
| 91 | 86 | good night |
| 92 | 87 | #} |
test/incremental/add_decls_around_bad_field_expr+1-2| ... | ... | @@ -32,8 +32,7 @@ pub fn main() void { |
| 32 | 32 | _ = @as(@This(), undefined); |
| 33 | 33 | } |
| 34 | 34 | #} |
| 35 | #update { | |
| 36 | add more decls around error#} | |
| 35 | #update "add more decls around error" | |
| 37 | 36 | #check errors { |
| 38 | 37 | main.zig:4:15: error: root source file struct 'main' has no member named 'does_not_exist' |
| 39 | 38 | main.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 | 14 | }; |
| 15 | 15 | #} |
| 16 | 16 | #update |
| 17 | #check stdout { | |
| 18 | #} | |
| 17 | #check stdout | |
| 19 | 18 | |
| 20 | 19 | #write main.zig { |
| 21 | 20 | pub fn main() void { |
| ... | ... | @@ -29,7 +28,5 @@ const S = struct { |
| 29 | 28 | bar: u32, |
| 30 | 29 | }; |
| 31 | 30 | #} |
| 32 | #update { | |
| 33 | add field to outer struct, change decl used by inner struct#} | |
| 34 | #check stdout { | |
| 35 | #} | |
| 31 | #update "add field to outer struct, change decl used by inner struct" | |
| 32 | #check stdout |
test/incremental/add_remove_struct_fields/manifest+7-10| ... | ... | @@ -2,30 +2,27 @@ |
| 2 | 2 | -Mroot=main.zig |
| 3 | 3 | #} |
| 4 | 4 | |
| 5 | #write main.zig 0/main.zig | |
| 5 | #write main.zig @0/main.zig | |
| 6 | 6 | #update |
| 7 | 7 | #check stdout { |
| 8 | 8 | 1 100 |
| 9 | 9 | #} |
| 10 | 10 | |
| 11 | #write main.zig 1/main.zig | |
| 12 | #update { | |
| 13 | add a field#} | |
| 11 | #write main.zig @1/main.zig | |
| 12 | #update "add a field" | |
| 14 | 13 | #check stdout { |
| 15 | 14 | 2 100 |
| 16 | 15 | #} |
| 17 | 16 | |
| 18 | #write main.zig 2/main.zig | |
| 19 | #update { | |
| 20 | remove all fields#} | |
| 17 | #write main.zig @2/main.zig | |
| 18 | #update "remove all fields" | |
| 21 | 19 | #check errors { |
| 22 | 20 | main.zig:15:24: error: no field named 'x' in struct 'main.S' |
| 23 | 21 | main.zig:1:11: note: struct declared here |
| 24 | 22 | #} |
| 25 | 23 | |
| 26 | #write main.zig 3/main.zig | |
| 27 | #update { | |
| 28 | remove reference to non-existent field#} | |
| 24 | #write main.zig @3/main.zig | |
| 25 | #update "remove reference to non-existent field" | |
| 29 | 26 | #check stdout { |
| 30 | 27 | 0 <no fields> |
| 31 | 28 | #} |
test/incremental/add_remove_toplevel_fields/manifest+7-10| ... | ... | @@ -2,30 +2,27 @@ |
| 2 | 2 | -Mroot=main.zig |
| 3 | 3 | #} |
| 4 | 4 | |
| 5 | #write main.zig 0/main.zig | |
| 5 | #write main.zig @0/main.zig | |
| 6 | 6 | #update |
| 7 | 7 | #check stdout { |
| 8 | 8 | 1 100 |
| 9 | 9 | #} |
| 10 | 10 | |
| 11 | #write main.zig 1/main.zig | |
| 12 | #update { | |
| 13 | add a field#} | |
| 11 | #write main.zig @1/main.zig | |
| 12 | #update "add a field" | |
| 14 | 13 | #check stdout { |
| 15 | 14 | 2 100 |
| 16 | 15 | #} |
| 17 | 16 | |
| 18 | #write main.zig 2/main.zig | |
| 19 | #update { | |
| 20 | remove all fields#} | |
| 17 | #write main.zig @2/main.zig | |
| 18 | #update "remove all fields" | |
| 21 | 19 | #check errors { |
| 22 | 20 | main.zig:15:24: error: no field named 'x' in struct 'main' |
| 23 | 21 | main.zig:1:1: note: struct declared here |
| 24 | 22 | #} |
| 25 | 23 | |
| 26 | #write main.zig 3/main.zig | |
| 27 | #update { | |
| 28 | remove reference to non-existent field#} | |
| 24 | #write main.zig @3/main.zig | |
| 25 | #update "remove reference to non-existent field" | |
| 29 | 26 | #check stdout { |
| 30 | 27 | 0 <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 | 16 | pub fn main() !void { |
| 17 | 17 | @compileError("uh oh"); |
| 18 | 18 | #} |
| 19 | #update { | |
| 20 | add parse error#} | |
| 19 | #update "add parse error" | |
| 21 | 20 | #check errors { |
| 22 | 21 | main.zig:3:1: error: expected statement, found 'EOF' |
| 23 | 22 | #} |
| ... | ... | @@ -27,8 +26,7 @@ pub fn main() !void { |
| 27 | 26 | @compileError("uh oh"); |
| 28 | 27 | } |
| 29 | 28 | #} |
| 30 | #update { | |
| 31 | fix parse error#} | |
| 29 | #update "fix parse error" | |
| 32 | 30 | #check errors { |
| 33 | 31 | main.zig:2:5: error: uh oh |
| 34 | 32 | #} |
| ... | ... | @@ -37,8 +35,7 @@ main.zig:2:5: error: uh oh |
| 37 | 35 | pub fn main() !void { |
| 38 | 36 | @compileError("uh oh"); |
| 39 | 37 | #} |
| 40 | #update { | |
| 41 | add parse error again#} | |
| 38 | #update "add parse error again" | |
| 42 | 39 | #check errors { |
| 43 | 40 | main.zig:3:1: error: expected statement, found 'EOF' |
| 44 | 41 | #} |
| ... | ... | @@ -47,8 +44,7 @@ main.zig:3:1: error: expected statement, found 'EOF' |
| 47 | 44 | pub fn main() !void { |
| 48 | 45 | //@compileError("uh oh"); |
| 49 | 46 | #} |
| 50 | #update { | |
| 51 | comment @compileError call#} | |
| 47 | #update "comment @compileError call" | |
| 52 | 48 | #check errors { |
| 53 | 49 | main.zig:3:1: error: expected statement, found 'EOF' |
| 54 | 50 | #} |
| ... | ... | @@ -58,7 +54,5 @@ pub fn main() !void { |
| 58 | 54 | //@compileError("uh oh"); |
| 59 | 55 | } |
| 60 | 56 | #} |
| 61 | #update { | |
| 62 | fix parse error again#} | |
| 63 | #check stdout { | |
| 64 | #} | |
| 57 | #update "fix parse error again" | |
| 58 | #check stdout |
test/incremental/bad_import+2-4| ... | ... | @@ -26,8 +26,7 @@ comptime { |
| 26 | 26 | _ = @import("this_is/not_real.zig"); |
| 27 | 27 | } |
| 28 | 28 | #} |
| 29 | #update { | |
| 30 | change bad import#} | |
| 29 | #update "change bad import" | |
| 31 | 30 | #check errors { |
| 32 | 31 | this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound |
| 33 | 32 | foo.zig:2:17: note: file imported here |
| ... | ... | @@ -41,8 +40,7 @@ pub fn main() !void { |
| 41 | 40 | const std = @import("std"); |
| 42 | 41 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 43 | 42 | #} |
| 44 | #update { | |
| 45 | remove import of 'foo.zig'#} | |
| 43 | #update "remove import of 'foo.zig'" | |
| 46 | 44 | #check stdout { |
| 47 | 45 | success |
| 48 | 46 | #} |
test/incremental/change_bitpack_backing_int+3-6| ... | ... | @@ -38,8 +38,7 @@ comptime { |
| 38 | 38 | const std = @import("std"); |
| 39 | 39 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 40 | 40 | #} |
| 41 | #update { | |
| 42 | make backing types signed#} | |
| 41 | #update "make backing types signed" | |
| 43 | 42 | #check errors { |
| 44 | 43 | main.zig:5:5: error: found compile log statement |
| 45 | 44 | main.zig:8:5: note: also here |
| ... | ... | @@ -62,8 +61,7 @@ comptime { |
| 62 | 61 | const std = @import("std"); |
| 63 | 62 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 64 | 63 | #} |
| 65 | #update { | |
| 66 | make backing types too small#} | |
| 64 | #update "make backing types too small" | |
| 67 | 65 | #check errors { |
| 68 | 66 | main.zig:1:20: error: backing integer bit width does not match total bit width of fields |
| 69 | 67 | main.zig:1:27: note: backing integer 'i5' has bit width '5' |
| ... | ... | @@ -87,8 +85,7 @@ comptime { |
| 87 | 85 | const std = @import("std"); |
| 88 | 86 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 89 | 87 | #} |
| 90 | #update { | |
| 91 | make backing types too big#} | |
| 88 | #update "make backing types too big" | |
| 92 | 89 | #check errors { |
| 93 | 90 | main.zig:1:20: error: backing integer bit width does not match total bit width of fields |
| 94 | 91 | main.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 | 12 | #write foo.zig { |
| 13 | 13 | pub const T = struct { x: u8 }; |
| 14 | 14 | #} |
| 15 | #update { | |
| 16 | T is struct#} | |
| 15 | #update "T is struct" | |
| 17 | 16 | #check errors { |
| 18 | 17 | main.zig:3:5: error: found compile log statement |
| 19 | 18 | |
| ... | ... | @@ -25,8 +24,7 @@ Compile Log Output: |
| 25 | 24 | #write foo.zig { |
| 26 | 25 | pub const T = union {}; |
| 27 | 26 | #} |
| 28 | #update { | |
| 29 | T is union#} | |
| 27 | #update "T is union" | |
| 30 | 28 | #check errors { |
| 31 | 29 | main.zig:3:5: error: found compile log statement |
| 32 | 30 | |
| ... | ... | @@ -38,8 +36,7 @@ Compile Log Output: |
| 38 | 36 | #write foo.zig { |
| 39 | 37 | pub const T = enum {}; |
| 40 | 38 | #} |
| 41 | #update { | |
| 42 | T is enum#} | |
| 39 | #update "T is enum" | |
| 43 | 40 | #check errors { |
| 44 | 41 | main.zig:3:5: error: found compile log statement |
| 45 | 42 | |
| ... | ... | @@ -51,8 +48,7 @@ Compile Log Output: |
| 51 | 48 | #write foo.zig { |
| 52 | 49 | pub const T = opaque {}; |
| 53 | 50 | #} |
| 54 | #update { | |
| 55 | T is opaque#} | |
| 51 | #update "T is opaque" | |
| 56 | 52 | #check errors { |
| 57 | 53 | main.zig:3:5: error: found compile log statement |
| 58 | 54 | |
| ... | ... | @@ -64,8 +60,7 @@ Compile Log Output: |
| 64 | 60 | #write foo.zig { |
| 65 | 61 | pub const T = packed struct {}; |
| 66 | 62 | #} |
| 67 | #update { | |
| 68 | T is packed struct#} | |
| 63 | #update "T is packed struct" | |
| 69 | 64 | #check errors { |
| 70 | 65 | main.zig:3:5: error: found compile log statement |
| 71 | 66 | |
| ... | ... | @@ -77,8 +72,7 @@ Compile Log Output: |
| 77 | 72 | #write foo.zig { |
| 78 | 73 | pub const T = packed union { x: void }; // packed unions need at least 1 field |
| 79 | 74 | #} |
| 80 | #update { | |
| 81 | T is packed union#} | |
| 75 | #update "T is packed union" | |
| 82 | 76 | #check errors { |
| 83 | 77 | main.zig:3:5: error: found compile log statement |
| 84 | 78 | |
| ... | ... | @@ -90,8 +84,7 @@ Compile Log Output: |
| 90 | 84 | #write foo.zig { |
| 91 | 85 | pub const T = extern struct {}; |
| 92 | 86 | #} |
| 93 | #update { | |
| 94 | T is extern struct#} | |
| 87 | #update "T is extern struct" | |
| 95 | 88 | #check errors { |
| 96 | 89 | main.zig:3:5: error: found compile log statement |
| 97 | 90 | |
| ... | ... | @@ -103,8 +96,7 @@ Compile Log Output: |
| 103 | 96 | #write foo.zig { |
| 104 | 97 | pub const T = extern union { x: void }; // extern unions need at least 1 field |
| 105 | 98 | #} |
| 106 | #update { | |
| 107 | T is extern union#} | |
| 99 | #update "T is extern union" | |
| 108 | 100 | #check errors { |
| 109 | 101 | main.zig:3:5: error: found compile log statement |
| 110 | 102 |
test/incremental/change_embed_file+5-10| ... | ... | @@ -21,15 +21,13 @@ Hello, World! |
| 21 | 21 | #write string.txt { |
| 22 | 22 | Hello again, World! |
| 23 | 23 | #} |
| 24 | #update { | |
| 25 | change file contents#} | |
| 24 | #update "change file contents" | |
| 26 | 25 | #check stdout { |
| 27 | 26 | Hello again, World! |
| 28 | 27 | #} |
| 29 | 28 | |
| 30 | 29 | #delete string.txt |
| 31 | #update { | |
| 32 | delete file#} | |
| 30 | #update "delete file" | |
| 33 | 31 | #check errors { |
| 34 | 32 | main.zig:2:27: error: failed opening "string.txt": FileNotFound |
| 35 | 33 | #} |
| ... | ... | @@ -42,8 +40,7 @@ pub fn main() !void { |
| 42 | 40 | } |
| 43 | 41 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 44 | 42 | #} |
| 45 | #update { | |
| 46 | remove reference to file#} | |
| 43 | #update "remove reference to file" | |
| 47 | 44 | #check stdout { |
| 48 | 45 | a hardcoded string |
| 49 | 46 | #} |
| ... | ... | @@ -56,8 +53,7 @@ pub fn main() !void { |
| 56 | 53 | } |
| 57 | 54 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 58 | 55 | #} |
| 59 | #update { | |
| 60 | re-introduce reference to file#} | |
| 56 | #update "re-introduce reference to file" | |
| 61 | 57 | #check errors { |
| 62 | 58 | main.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 | 61 | #write string.txt { |
| 66 | 62 | We're back, World! |
| 67 | 63 | #} |
| 68 | #update { | |
| 69 | recreate file#} | |
| 64 | #update "recreate file" | |
| 70 | 65 | #check stdout { |
| 71 | 66 | We're back, World! |
| 72 | 67 | #} |
test/incremental/change_enum_tag_type/manifest+9-13| ... | ... | @@ -2,29 +2,26 @@ |
| 2 | 2 | -Mroot=main.zig |
| 3 | 3 | #} |
| 4 | 4 | |
| 5 | #write main.zig 0/main.zig | |
| 5 | #write main.zig @0/main.zig | |
| 6 | 6 | #update |
| 7 | 7 | #check stdout { |
| 8 | 8 | a |
| 9 | 9 | #} |
| 10 | 10 | |
| 11 | #write main.zig 1/main.zig | |
| 12 | #update { | |
| 13 | too many enum fields#} | |
| 11 | #write main.zig @1/main.zig | |
| 12 | #update "too many enum fields" | |
| 14 | 13 | #check errors { |
| 15 | 14 | main.zig:7:5: error: enum tag value '4' too large for type 'u2' |
| 16 | 15 | #} |
| 17 | 16 | |
| 18 | #write main.zig 2/main.zig | |
| 19 | #update { | |
| 20 | increase tag size#} | |
| 17 | #write main.zig @2/main.zig | |
| 18 | #update "increase tag size" | |
| 21 | 19 | #check stdout { |
| 22 | 20 | a |
| 23 | 21 | #} |
| 24 | 22 | |
| 25 | #write main.zig 3/main.zig | |
| 26 | #update { | |
| 27 | specify tag directly#} | |
| 23 | #write main.zig @3/main.zig | |
| 24 | #update "specify tag directly" | |
| 28 | 25 | #check errors { |
| 29 | 26 | main.zig:9:5: error: found compile log statement |
| 30 | 27 | |
| ... | ... | @@ -32,9 +29,8 @@ Compile Log Output: |
| 32 | 29 | @as(type, u3) |
| 33 | 30 | #} |
| 34 | 31 | |
| 35 | #write main.zig 4/main.zig | |
| 36 | #update { | |
| 37 | change directly-specified tag type#} | |
| 32 | #write main.zig @4/main.zig | |
| 33 | #update "change directly-specified tag type" | |
| 38 | 34 | #check errors { |
| 39 | 35 | main.zig:9:5: error: found compile log statement |
| 40 | 36 |
test/incremental/change_exports/manifest+14-21| ... | ... | @@ -2,50 +2,43 @@ |
| 2 | 2 | -Mroot=main.zig |
| 3 | 3 | #} |
| 4 | 4 | |
| 5 | #write main.zig 0/main.zig | |
| 5 | #write main.zig @0/main.zig | |
| 6 | 6 | #update |
| 7 | 7 | #check stdout { |
| 8 | 8 | 123 |
| 9 | 9 | #} |
| 10 | 10 | |
| 11 | #write main.zig 1/main.zig | |
| 12 | #update { | |
| 13 | add conflict#} | |
| 11 | #write main.zig @1/main.zig | |
| 12 | #update "add conflict" | |
| 14 | 13 | #check errors { |
| 15 | 14 | main.zig:6:5: error: exported symbol collision: foo |
| 16 | 15 | main.zig:1:1: note: other symbol here |
| 17 | 16 | #} |
| 18 | 17 | |
| 19 | #write main.zig 2/main.zig | |
| 20 | #update { | |
| 21 | resolve conflict#} | |
| 18 | #write main.zig @2/main.zig | |
| 19 | #update "resolve conflict" | |
| 22 | 20 | #check stdout { |
| 23 | 21 | 123 456 |
| 24 | 22 | #} |
| 25 | 23 | |
| 26 | #write main.zig 3/main.zig | |
| 27 | #update { | |
| 28 | put exports in decl#} | |
| 24 | #write main.zig @3/main.zig | |
| 25 | #update "put exports in decl" | |
| 29 | 26 | #check stdout { |
| 30 | 27 | 123 456 |
| 31 | 28 | #} |
| 32 | 29 | |
| 33 | #write main.zig 4/main.zig | |
| 34 | #update { | |
| 35 | remove reference to exporting decl#} | |
| 36 | #check stdout { | |
| 37 | #} | |
| 30 | #write main.zig @4/main.zig | |
| 31 | #update "remove reference to exporting decl" | |
| 32 | #check stdout | |
| 38 | 33 | |
| 39 | #write main.zig 5/main.zig | |
| 40 | #update { | |
| 41 | mark consts as export#} | |
| 34 | #write main.zig @5/main.zig | |
| 35 | #update "mark consts as export" | |
| 42 | 36 | #check stdout { |
| 43 | 37 | 123 456 |
| 44 | 38 | #} |
| 45 | 39 | |
| 46 | #write main.zig 6/main.zig | |
| 47 | #update { | |
| 48 | reintroduce reference to exporting decl, introducing conflict#} | |
| 40 | #write main.zig @6/main.zig | |
| 41 | #update "reintroduce reference to exporting decl, introducing conflict" | |
| 49 | 42 | #check errors { |
| 50 | 43 | main.zig:5:5: error: exported symbol collision: bar |
| 51 | 44 | main.zig:2:1: note: other symbol here |
test/incremental/change_fn_type+2-4| ... | ... | @@ -29,8 +29,7 @@ fn foo(x: i64) !void { |
| 29 | 29 | const std = @import("std"); |
| 30 | 30 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 31 | 31 | #} |
| 32 | #update { | |
| 33 | change function type#} | |
| 32 | #update "change function type" | |
| 34 | 33 | #check stdout { |
| 35 | 34 | 123 |
| 36 | 35 | #} |
| ... | ... | @@ -46,8 +45,7 @@ fn foo(x: i64) !void { |
| 46 | 45 | const std = @import("std"); |
| 47 | 46 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 48 | 47 | #} |
| 49 | #update { | |
| 50 | change function argument#} | |
| 48 | #update "change function argument" | |
| 51 | 49 | #check stdout { |
| 52 | 50 | -42 |
| 53 | 51 | #} |
test/incremental/change_generic_line_number+1-2| ... | ... | @@ -39,8 +39,7 @@ pub fn main() !void { |
| 39 | 39 | try Printer("bar\n").print(); |
| 40 | 40 | } |
| 41 | 41 | #} |
| 42 | #update { | |
| 43 | change line number#} | |
| 42 | #update "change line number" | |
| 44 | 43 | #check stdout { |
| 45 | 44 | foo |
| 46 | 45 | bar |
test/incremental/change_line_number+1-2| ... | ... | @@ -22,8 +22,7 @@ pub fn main() !void { |
| 22 | 22 | } |
| 23 | 23 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 24 | 24 | #} |
| 25 | #update { | |
| 26 | change line number#} | |
| 25 | #update "change line number" | |
| 27 | 26 | #check stdout { |
| 28 | 27 | foo |
| 29 | 28 | #} |
test/incremental/change_module+4-8| ... | ... | @@ -41,8 +41,7 @@ comptime { |
| 41 | 41 | //_ = @import("other.zig"); |
| 42 | 42 | } |
| 43 | 43 | #} |
| 44 | #update { | |
| 45 | change module of other.zig#} | |
| 44 | #update "change module of other.zig" | |
| 46 | 45 | #check errors { |
| 47 | 46 | other.zig:2:5: error: found compile log statement |
| 48 | 47 | |
| ... | ... | @@ -61,8 +60,7 @@ comptime { |
| 61 | 60 | _ = @import("other.zig"); |
| 62 | 61 | } |
| 63 | 62 | #} |
| 64 | #update { | |
| 65 | put other.zig in both modules#} | |
| 63 | #update "put other.zig in both modules" | |
| 66 | 64 | #check errors { |
| 67 | 65 | other.zig:1:1: error: file exists in modules 'root' and 'foo' |
| 68 | 66 | other.zig:1:1: note: files must belong to only one module |
| ... | ... | @@ -81,7 +79,5 @@ comptime { |
| 81 | 79 | //_ = @import("other.zig"); |
| 82 | 80 | } |
| 83 | 81 | #} |
| 84 | #update { | |
| 85 | put other.zig in no modules#} | |
| 86 | #check stdout { | |
| 87 | #} | |
| 82 | #update "put other.zig in no modules" | |
| 83 | #check stdout |
test/incremental/change_panic_handler+2-4| ... | ... | @@ -39,8 +39,7 @@ fn myPanic(msg: []const u8, _: ?usize) noreturn { |
| 39 | 39 | const std = @import("std"); |
| 40 | 40 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 41 | 41 | #} |
| 42 | #update { | |
| 43 | change the panic handler body#} | |
| 42 | #update "change the panic handler body" | |
| 44 | 43 | #check stdout { |
| 45 | 44 | new panic message: integer overflow |
| 46 | 45 | #} |
| ... | ... | @@ -61,8 +60,7 @@ fn myPanicNew(msg: []const u8, _: ?usize) noreturn { |
| 61 | 60 | const std = @import("std"); |
| 62 | 61 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 63 | 62 | #} |
| 64 | #update { | |
| 65 | change the panic handler function value#} | |
| 63 | #update "change the panic handler function value" | |
| 66 | 64 | #check stdout { |
| 67 | 65 | third panic message: integer overflow |
| 68 | 66 | #} |
test/incremental/change_panic_handler_explicit/manifest+5-7| ... | ... | @@ -2,22 +2,20 @@ |
| 2 | 2 | -Mroot=main.zig |
| 3 | 3 | #} |
| 4 | 4 | |
| 5 | #write main.zig 0/main.zig | |
| 5 | #write main.zig @0/main.zig | |
| 6 | 6 | #update |
| 7 | 7 | #check stdout { |
| 8 | 8 | panic message: integer overflow |
| 9 | 9 | #} |
| 10 | 10 | |
| 11 | #write main.zig 1/main.zig | |
| 12 | #update { | |
| 13 | change the panic handler body#} | |
| 11 | #write main.zig @1/main.zig | |
| 12 | #update "change the panic handler body" | |
| 14 | 13 | #check stdout { |
| 15 | 14 | new panic message: integer overflow |
| 16 | 15 | #} |
| 17 | 16 | |
| 18 | #write main.zig 2/main.zig | |
| 19 | #update { | |
| 20 | change the panic handler function value#} | |
| 17 | #write main.zig @2/main.zig | |
| 18 | #update "change the panic handler function value" | |
| 21 | 19 | #check stdout { |
| 22 | 20 | third 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 | 13 | const std = @import("std"); |
| 14 | 14 | #} |
| 15 | 15 | #update |
| 16 | #check stdout { | |
| 17 | foo#} | |
| 16 | #check stdout "foo" | |
| 18 | 17 | |
| 19 | 18 | #write main.zig { |
| 20 | 19 | fn getEnum(s: @Struct(.auto, null, &.{"field"}, &.{Enum}, &.{.{}})) Enum { |
| ... | ... | @@ -26,7 +25,5 @@ pub fn main(init: std.process.Init) !void { |
| 26 | 25 | const Enum = enum { foo, bar }; |
| 27 | 26 | const std = @import("std"); |
| 28 | 27 | #} |
| 29 | #update { | |
| 30 | change field type#} | |
| 31 | #check stdout { | |
| 32 | bar#} | |
| 28 | #update "change field type" | |
| 29 | #check stdout "bar" |
test/incremental/change_shift_op+1-2| ... | ... | @@ -29,8 +29,7 @@ fn foo(x: u16) !void { |
| 29 | 29 | const std = @import("std"); |
| 30 | 30 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 31 | 31 | #} |
| 32 | #update { | |
| 33 | change to right shift#} | |
| 32 | #update "change to right shift" | |
| 34 | 33 | #check stdout { |
| 35 | 34 | 0x130 |
| 36 | 35 | #} |
test/incremental/change_struct_same_fields+2-4| ... | ... | @@ -39,8 +39,7 @@ fn foo(val: *const S) !void { |
| 39 | 39 | const std = @import("std"); |
| 40 | 40 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 41 | 41 | #} |
| 42 | #update { | |
| 43 | change struct layout#} | |
| 42 | #update "change struct layout" | |
| 44 | 43 | #check stdout { |
| 45 | 44 | 100 200 |
| 46 | 45 | #} |
| ... | ... | @@ -61,8 +60,7 @@ fn foo(val: *const S) !void { |
| 61 | 60 | const std = @import("std"); |
| 62 | 61 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 63 | 62 | #} |
| 64 | #update { | |
| 65 | change values#} | |
| 63 | #update "change values" | |
| 66 | 64 | #check stdout { |
| 67 | 65 | 1234 5678 |
| 68 | 66 | #} |
test/incremental/change_union_tag_type+2-4| ... | ... | @@ -29,8 +29,7 @@ pub fn main(init: std.process.Init) !void { |
| 29 | 29 | } |
| 30 | 30 | const std = @import("std"); |
| 31 | 31 | #} |
| 32 | #update { | |
| 33 | change tag type#} | |
| 32 | #update "change tag type" | |
| 34 | 33 | #check errors { |
| 35 | 34 | main.zig:3:24: error: no field named 'a' in enum 'main.B' |
| 36 | 35 | main.zig:2:11: note: enum declared here |
| ... | ... | @@ -47,8 +46,7 @@ pub fn main(init: std.process.Init) !void { |
| 47 | 46 | } |
| 48 | 47 | const std = @import("std"); |
| 49 | 48 | #} |
| 50 | #update { | |
| 51 | change field name to match new tag type#} | |
| 49 | #update "change field name to match new tag type" | |
| 52 | 50 | #check stdout { |
| 53 | 51 | b |
| 54 | 52 | #} |
test/incremental/change_zon_file+5-10| ... | ... | @@ -21,15 +21,13 @@ Hello, World! |
| 21 | 21 | #write message.zon { |
| 22 | 22 | "Hello again, World!\n" |
| 23 | 23 | #} |
| 24 | #update { | |
| 25 | change ZON file contents#} | |
| 24 | #update "change ZON file contents" | |
| 26 | 25 | #check stdout { |
| 27 | 26 | Hello again, World! |
| 28 | 27 | #} |
| 29 | 28 | |
| 30 | 29 | #delete message.zon |
| 31 | #update { | |
| 32 | delete file#} | |
| 30 | #update "delete file" | |
| 33 | 31 | #check errors { |
| 34 | 32 | message.zon:1:1: error: unable to load "message.zon": FileNotFound |
| 35 | 33 | main.zig:2:37: note: file imported here |
| ... | ... | @@ -43,8 +41,7 @@ pub fn main() !void { |
| 43 | 41 | } |
| 44 | 42 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 45 | 43 | #} |
| 46 | #update { | |
| 47 | remove reference to ZON file#} | |
| 44 | #update "remove reference to ZON file" | |
| 48 | 45 | #check errors { |
| 49 | 46 | message.zon:1:1: error: unable to load "message.zon": FileNotFound |
| 50 | 47 | main.zig:2:37: note: file imported here |
| ... | ... | @@ -53,8 +50,7 @@ main.zig:2:37: note: file imported here |
| 53 | 50 | #write message.zon { |
| 54 | 51 | "We're back, World!\n" |
| 55 | 52 | #} |
| 56 | #update { | |
| 57 | recreate ZON file#} | |
| 53 | #update "recreate ZON file" | |
| 58 | 54 | #check stdout { |
| 59 | 55 | a hardcoded string |
| 60 | 56 | #} |
| ... | ... | @@ -67,8 +63,7 @@ pub fn main() !void { |
| 67 | 63 | } |
| 68 | 64 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 69 | 65 | #} |
| 70 | #update { | |
| 71 | re-introduce reference to ZON file#} | |
| 66 | #update "re-introduce reference to ZON file" | |
| 72 | 67 | #check stdout { |
| 73 | 68 | We're back, World! |
| 74 | 69 | #} |
test/incremental/change_zon_file_no_result_type+1-2| ... | ... | @@ -26,8 +26,7 @@ Hello, World! |
| 26 | 26 | .b_number = 0, |
| 27 | 27 | } |
| 28 | 28 | #} |
| 29 | #update { | |
| 30 | change ZON file#} | |
| 29 | #update "change ZON file" | |
| 31 | 30 | #check stdout { |
| 32 | 31 | Hello again, World! |
| 33 | 32 | #} |
test/incremental/compile_error_then_log+2-4| ... | ... | @@ -11,8 +11,7 @@ comptime { |
| 11 | 11 | @compileLog("this is a log"); |
| 12 | 12 | } |
| 13 | 13 | #} |
| 14 | #update { | |
| 15 | compile error#} | |
| 14 | #update "compile error" | |
| 16 | 15 | #check errors { |
| 17 | 16 | main.zig:3:5: error: this is an error |
| 18 | 17 | |
| ... | ... | @@ -29,8 +28,7 @@ comptime { |
| 29 | 28 | @compileLog("this is a log"); |
| 30 | 29 | } |
| 31 | 30 | #} |
| 32 | #update { | |
| 33 | remove the compile error#} | |
| 31 | #update "remove the compile error" | |
| 34 | 32 | #check errors { |
| 35 | 33 | main.zig:6:5: error: found compile log statement |
| 36 | 34 |
test/incremental/compile_log+3-6| ... | ... | @@ -9,8 +9,7 @@ pub fn main() !void { |
| 9 | 9 | } |
| 10 | 10 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 11 | 11 | #} |
| 12 | #update { | |
| 13 | no compile log#} | |
| 12 | #update "no compile log" | |
| 14 | 13 | #check stdout { |
| 15 | 14 | Hello, World! |
| 16 | 15 | #} |
| ... | ... | @@ -23,8 +22,7 @@ pub fn main() !void { |
| 23 | 22 | } |
| 24 | 23 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 25 | 24 | #} |
| 26 | #update { | |
| 27 | add compile log#} | |
| 25 | #update "add compile log" | |
| 28 | 26 | #check errors { |
| 29 | 27 | main.zig:4:5: error: found compile log statement |
| 30 | 28 | |
| ... | ... | @@ -39,8 +37,7 @@ pub fn main() !void { |
| 39 | 37 | } |
| 40 | 38 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 41 | 39 | #} |
| 42 | #update { | |
| 43 | remove compile log#} | |
| 40 | #update "remove compile log" | |
| 44 | 41 | #check stdout { |
| 45 | 42 | Hello, World! |
| 46 | 43 | #} |
test/incremental/delete_comptime_decls+1-2| ... | ... | @@ -44,8 +44,7 @@ comptime { |
| 44 | 44 | _ = y; |
| 45 | 45 | } |
| 46 | 46 | #} |
| 47 | #update { | |
| 48 | delete and modify comptime decls#} | |
| 47 | #update "delete and modify comptime decls" | |
| 49 | 48 | #check errors { |
| 50 | 49 | main.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 | 15 | pub fn main() void {} |
| 16 | 16 | #} |
| 17 | 17 | #update |
| 18 | #check stdout { | |
| 19 | #} | |
| 18 | #check stdout | |
| 20 | 19 | |
| 21 | 20 | #write main.zig { |
| 22 | 21 | const foo = @as(u16, 123); |
| ... | ... | @@ -30,8 +29,7 @@ comptime { |
| 30 | 29 | } |
| 31 | 30 | pub fn main() void {} |
| 32 | 31 | #} |
| 33 | #update { | |
| 34 | change the type#} | |
| 32 | #update "change the type" | |
| 35 | 33 | #check errors { |
| 36 | 34 | main.zig:8:37: error: reached unreachable code |
| 37 | 35 | #} |
test/incremental/do_nothing+4-9| ... | ... | @@ -1,6 +1,4 @@ |
| 1 | #todo { | |
| 2 | it'd be great if we could actually check that no analysis happened! | |
| 3 | #} | |
| 1 | #todo "it'd be great if we could actually check that no analysis happened!" | |
| 4 | 2 | #exe { |
| 5 | 3 | -Mroot=main.zig |
| 6 | 4 | #} |
| ... | ... | @@ -25,8 +23,7 @@ const O = opaque { |
| 25 | 23 | }; |
| 26 | 24 | #} |
| 27 | 25 | #update |
| 28 | #check stdout { | |
| 29 | #} | |
| 26 | #check stdout | |
| 30 | 27 | |
| 31 | 28 | #write main.zig { |
| 32 | 29 | pub fn main() void { |
| ... | ... | @@ -47,7 +44,5 @@ const O = opaque { |
| 47 | 44 | } |
| 48 | 45 | }; |
| 49 | 46 | #} |
| 50 | #update { | |
| 51 | do literally nothing#} | |
| 52 | #check stdout { | |
| 53 | #} | |
| 47 | #update "do literally nothing" | |
| 48 | #check stdout |
test/incremental/fix_astgen_failure+4-8| ... | ... | @@ -12,8 +12,7 @@ pub fn hello() !void { |
| 12 | 12 | try std.Io.File.stdout().writeStreamingAll(io, "Hello, World!\n"); |
| 13 | 13 | } |
| 14 | 14 | #} |
| 15 | #update { | |
| 16 | error#} | |
| 15 | #update "error" | |
| 17 | 16 | #check errors { |
| 18 | 17 | foo.zig:2:9: error: use of undeclared identifier 'std' |
| 19 | 18 | #} |
| ... | ... | @@ -25,8 +24,7 @@ pub fn hello() !void { |
| 25 | 24 | } |
| 26 | 25 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 27 | 26 | #} |
| 28 | #update { | |
| 29 | fix the error#} | |
| 27 | #update "fix the error" | |
| 30 | 28 | #check stdout { |
| 31 | 29 | Hello, World! |
| 32 | 30 | #} |
| ... | ... | @@ -38,8 +36,7 @@ pub fn hello() !void { |
| 38 | 36 | } |
| 39 | 37 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 40 | 38 | #} |
| 41 | #update { | |
| 42 | add new error#} | |
| 39 | #update "add new error" | |
| 43 | 40 | #check errors { |
| 44 | 41 | foo.zig:3:52: error: use of undeclared identifier 'hello_str' |
| 45 | 42 | #} |
| ... | ... | @@ -52,8 +49,7 @@ pub fn hello() !void { |
| 52 | 49 | } |
| 53 | 50 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 54 | 51 | #} |
| 55 | #update { | |
| 56 | fix the new error#} | |
| 52 | #update "fix the new error" | |
| 57 | 53 | #check stdout { |
| 58 | 54 | Hello, World! Again! |
| 59 | 55 | #} |
test/incremental/function_becomes_inline+3-6| ... | ... | @@ -12,8 +12,7 @@ fn foo() !void { |
| 12 | 12 | const std = @import("std"); |
| 13 | 13 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 14 | 14 | #} |
| 15 | #update { | |
| 16 | non-inline version#} | |
| 15 | #update "non-inline version" | |
| 17 | 16 | #check stdout { |
| 18 | 17 | Hello, World! |
| 19 | 18 | #} |
| ... | ... | @@ -28,8 +27,7 @@ inline fn foo() !void { |
| 28 | 27 | const std = @import("std"); |
| 29 | 28 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 30 | 29 | #} |
| 31 | #update { | |
| 32 | make function inline#} | |
| 30 | #update "make function inline" | |
| 33 | 31 | #check stdout { |
| 34 | 32 | Hello, World! |
| 35 | 33 | #} |
| ... | ... | @@ -44,8 +42,7 @@ inline fn foo() !void { |
| 44 | 42 | const std = @import("std"); |
| 45 | 43 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 46 | 44 | #} |
| 47 | #update { | |
| 48 | change string#} | |
| 45 | #update "change string" | |
| 49 | 46 | #check stdout { |
| 50 | 47 | Hello, `inline` World! |
| 51 | 48 | #} |
test/incremental/hello+1-2| ... | ... | @@ -21,8 +21,7 @@ pub fn main() !void { |
| 21 | 21 | try std.Io.File.stdout().writeStreamingAll(io, "おはようございます\n"); |
| 22 | 22 | } |
| 23 | 23 | #} |
| 24 | #update { | |
| 25 | change the string#} | |
| 24 | #update "change the string" | |
| 26 | 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 | 35 | } |
| 36 | 36 | const std = @import("std"); |
| 37 | 37 | #} |
| 38 | #update { | |
| 39 | increase array length#} | |
| 38 | #update "increase array length" | |
| 40 | 39 | #check stdout { |
| 41 | 40 | arr[999] = 234 |
| 42 | 41 | #} |
test/incremental/make_decl_pub+1-2| ... | ... | @@ -28,8 +28,7 @@ pub fn hello() !void { |
| 28 | 28 | } |
| 29 | 29 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 30 | 30 | #} |
| 31 | #update { | |
| 32 | make hello pub#} | |
| 31 | #update "make hello pub" | |
| 33 | 32 | #check stdout { |
| 34 | 33 | Hello, 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 | 29 | } |
| 30 | 30 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 31 | 31 | #} |
| 32 | #update { | |
| 33 | change the string#} | |
| 32 | #update "change the string" | |
| 34 | 33 | #check stdout { |
| 35 | 34 | bar |
| 36 | 35 | #} |
test/incremental/move_src+1-2| ... | ... | @@ -36,8 +36,7 @@ fn bar() u32 { |
| 36 | 36 | } |
| 37 | 37 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 38 | 38 | #} |
| 39 | #update { | |
| 40 | add newline#} | |
| 39 | #update "add newline" | |
| 41 | 40 | #check stdout { |
| 42 | 41 | 8 123 |
| 43 | 42 | #} |
test/incremental/pointer_to_decl_with_astgen_error+4-8| ... | ... | @@ -9,8 +9,7 @@ pub fn main() void { |
| 9 | 9 | } |
| 10 | 10 | #} |
| 11 | 11 | #update |
| 12 | #check stdout { | |
| 13 | #} | |
| 12 | #check stdout | |
| 14 | 13 | |
| 15 | 14 | #write main.zig { |
| 16 | 15 | const foo = something; |
| ... | ... | @@ -18,8 +17,7 @@ pub fn main() void { |
| 18 | 17 | _ = &foo; |
| 19 | 18 | } |
| 20 | 19 | #} |
| 21 | #update { | |
| 22 | introduce use of undeclared identifier#} | |
| 20 | #update "introduce use of undeclared identifier" | |
| 23 | 21 | #check errors { |
| 24 | 22 | main.zig:1:13: error: use of undeclared identifier 'something' |
| 25 | 23 | #} |
| ... | ... | @@ -30,7 +28,5 @@ pub fn main() void { |
| 30 | 28 | _ = &foo; |
| 31 | 29 | } |
| 32 | 30 | #} |
| 33 | #update { | |
| 34 | revert use of undeclared identifier#} | |
| 35 | #check stdout { | |
| 36 | #} | |
| 31 | #update "revert use of undeclared identifier" | |
| 32 | #check stdout |
test/incremental/recursive_function_becomes_non_recursive+1-2| ... | ... | @@ -31,8 +31,7 @@ fn foo(recurse: bool) !void { |
| 31 | 31 | const std = @import("std"); |
| 32 | 32 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 33 | 33 | #} |
| 34 | #update { | |
| 35 | eliminate recursion and change argument#} | |
| 34 | #update "eliminate recursion and change argument" | |
| 36 | 35 | #check stdout { |
| 37 | 36 | x==1 |
| 38 | 37 | #} |
test/incremental/remove_enum_field+1-2| ... | ... | @@ -31,8 +31,7 @@ pub fn main() !void { |
| 31 | 31 | const std = @import("std"); |
| 32 | 32 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 33 | 33 | #} |
| 34 | #update { | |
| 35 | remove enum field#} | |
| 34 | #update "remove enum field" | |
| 36 | 35 | #check errors { |
| 37 | 36 | main.zig:7:68: error: enum 'main.MyEnum' has no member named 'foo' |
| 38 | 37 | main.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 | 28 | } |
| 29 | 29 | #} |
| 30 | 30 | #update |
| 31 | #check stdout { | |
| 32 | 0#} | |
| 31 | #check stdout "0" | |
| 33 | 32 | |
| 34 | 33 | #write main.zig { |
| 35 | 34 | //! This update must preserve `bar` `InternPool.Index` value, while changing its wasm function type. |
| ... | ... | @@ -54,7 +53,5 @@ pub fn main() !void { |
| 54 | 53 | try bar(.one); |
| 55 | 54 | } |
| 56 | 55 | #} |
| 57 | #update { | |
| 58 | remove foo and change bar wasm function type#} | |
| 59 | #check stdout { | |
| 60 | 1#} | |
| 56 | #update "remove foo and change bar wasm function type" | |
| 57 | #check stdout "1" |
test/incremental/remove_invalid_union_backing_enum+2-4| ... | ... | @@ -33,7 +33,5 @@ pub fn main() void { |
| 33 | 33 | _ = u; |
| 34 | 34 | } |
| 35 | 35 | #} |
| 36 | #update { | |
| 37 | remove invalid backing enum#} | |
| 38 | #check stdout { | |
| 39 | #} | |
| 36 | #update "remove invalid backing enum" | |
| 37 | #check stdout |
test/incremental/struct_reification_becomes_anon_init+1-2| ... | ... | @@ -23,8 +23,7 @@ pub fn main(init: std.process.Init) !void { |
| 23 | 23 | } |
| 24 | 24 | const std = @import("std"); |
| 25 | 25 | #} |
| 26 | #update { | |
| 27 | change to `@TypeOf` anonymous init#} | |
| 26 | #update "change to `@TypeOf` anonymous init" | |
| 28 | 27 | #check stdout { |
| 29 | 28 | anon_field |
| 30 | 29 | #} |
test/incremental/tag_name+5-10| ... | ... | @@ -11,8 +11,7 @@ pub fn main() !void { |
| 11 | 11 | } |
| 12 | 12 | #} |
| 13 | 13 | #update |
| 14 | #check stdout { | |
| 15 | first#} | |
| 14 | #check stdout "first" | |
| 16 | 15 | |
| 17 | 16 | #write main.zig { |
| 18 | 17 | const std = @import("std"); |
| ... | ... | @@ -22,10 +21,8 @@ pub fn main() !void { |
| 22 | 21 | try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); |
| 23 | 22 | } |
| 24 | 23 | #} |
| 25 | #update { | |
| 26 | no change#} | |
| 27 | #check stdout { | |
| 28 | first#} | |
| 24 | #update "no change" | |
| 25 | #check stdout "first" | |
| 29 | 26 | |
| 30 | 27 | #write main.zig { |
| 31 | 28 | const std = @import("std"); |
| ... | ... | @@ -35,7 +32,5 @@ pub fn main() !void { |
| 35 | 32 | try std.Io.File.stdout().writeStreamingAll(io, @tagName(some_enum)); |
| 36 | 33 | } |
| 37 | 34 | #} |
| 38 | #update { | |
| 39 | swap fields#} | |
| 40 | #check stdout { | |
| 41 | first#} | |
| 35 | #update "swap fields" | |
| 36 | #check stdout "first" |
test/incremental/temporary_analysis_error_in_generic_signature+2-4| ... | ... | @@ -33,8 +33,7 @@ fn bar(comptime x: u8) @This().FooAlias { |
| 33 | 33 | } |
| 34 | 34 | const std = @import("std"); |
| 35 | 35 | #} |
| 36 | #update { | |
| 37 | change generic signature to use non-existent member#} | |
| 36 | #update "change generic signature to use non-existent member" | |
| 38 | 37 | #check errors { |
| 39 | 38 | main.zig:8:31: error: root source file struct 'main' has no member named 'FooAlias' |
| 40 | 39 | main.zig:1:1: note: struct declared here |
| ... | ... | @@ -54,8 +53,7 @@ fn bar(comptime x: u8) @This().FooAlias { |
| 54 | 53 | } |
| 55 | 54 | const std = @import("std"); |
| 56 | 55 | #} |
| 57 | #update { | |
| 58 | add that member, fixing the error#} | |
| 56 | #update "add that member, fixing the error" | |
| 59 | 57 | #check stdout { |
| 60 | 58 | Z |
| 61 | 59 | #} |
test/incremental/temporary_parse_error+4-8| ... | ... | @@ -7,14 +7,12 @@ const std = @import("std"); |
| 7 | 7 | pub fn main() !void {} |
| 8 | 8 | #} |
| 9 | 9 | #update |
| 10 | #check stdout { | |
| 11 | #} | |
| 10 | #check stdout | |
| 12 | 11 | |
| 13 | 12 | #write main.zig { |
| 14 | 13 | pub fn main() !void { |
| 15 | 14 | #} |
| 16 | #update { | |
| 17 | introduce parse error#} | |
| 15 | #update "introduce parse error" | |
| 18 | 16 | #check errors { |
| 19 | 17 | main.zig:2:1: error: expected statement, found 'EOF' |
| 20 | 18 | #} |
| ... | ... | @@ -22,7 +20,5 @@ main.zig:2:1: error: expected statement, found 'EOF' |
| 22 | 20 | #write main.zig { |
| 23 | 21 | pub fn main() !void {} |
| 24 | 22 | #} |
| 25 | #update { | |
| 26 | fix parse error#} | |
| 27 | #check stdout { | |
| 28 | #} | |
| 23 | #update "fix parse error" | |
| 24 | #check stdout |
test/incremental/type_becomes_comptime_only+5-10| ... | ... | @@ -14,8 +14,7 @@ pub fn main() void { |
| 14 | 14 | } |
| 15 | 15 | #} |
| 16 | 16 | #update |
| 17 | #check stdout { | |
| 18 | #} | |
| 17 | #check stdout | |
| 19 | 18 | |
| 20 | 19 | #write main.zig { |
| 21 | 20 | const SomeType = comptime_int; |
| ... | ... | @@ -28,10 +27,8 @@ pub fn main() void { |
| 28 | 27 | s.foo(); |
| 29 | 28 | } |
| 30 | 29 | #} |
| 31 | #update { | |
| 32 | make S comptime-only#} | |
| 33 | #check stdout { | |
| 34 | #} | |
| 30 | #update "make S comptime-only" | |
| 31 | #check stdout | |
| 35 | 32 | |
| 36 | 33 | #write main.zig { |
| 37 | 34 | const SomeType = u16; |
| ... | ... | @@ -44,7 +41,5 @@ pub fn main() void { |
| 44 | 41 | s.foo(); |
| 45 | 42 | } |
| 46 | 43 | #} |
| 47 | #update { | |
| 48 | make S runtime again#} | |
| 49 | #check stdout { | |
| 50 | #} | |
| 44 | #update "make S runtime again" | |
| 45 | #check stdout |
test/incremental/type_dependency_loop+7-14| ... | ... | @@ -24,10 +24,8 @@ pub fn main() void { |
| 24 | 24 | _ = B; |
| 25 | 25 | } |
| 26 | 26 | #} |
| 27 | #update { | |
| 28 | remove reference to dependency loop#} | |
| 29 | #check stdout { | |
| 30 | #} | |
| 27 | #update "remove reference to dependency loop" | |
| 28 | #check stdout | |
| 31 | 29 | |
| 32 | 30 | #write main.zig { |
| 33 | 31 | pub const A = struct { b: B }; |
| ... | ... | @@ -36,10 +34,8 @@ pub fn main() void { |
| 36 | 34 | _ = B; |
| 37 | 35 | } |
| 38 | 36 | #} |
| 39 | #update { | |
| 40 | change dependency loop without fixing it#} | |
| 41 | #check stdout { | |
| 42 | #} | |
| 37 | #update "change dependency loop without fixing it" | |
| 38 | #check stdout | |
| 43 | 39 | |
| 44 | 40 | #write main.zig { |
| 45 | 41 | pub const A = struct { b: B }; |
| ... | ... | @@ -48,8 +44,7 @@ pub fn main() void { |
| 48 | 44 | _ = @as(B, undefined); |
| 49 | 45 | } |
| 50 | 46 | #} |
| 51 | #update { | |
| 52 | reference dependency loop again#} | |
| 47 | #update "reference dependency loop again" | |
| 53 | 48 | #check errors { |
| 54 | 49 | error: dependency loop with length 2 |
| 55 | 50 | 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 | 59 | _ = @as(B, undefined); |
| 65 | 60 | } |
| 66 | 61 | #} |
| 67 | #update { | |
| 68 | fix dependency loop#} | |
| 69 | #check stdout { | |
| 70 | #} | |
| 62 | #update "fix dependency loop" | |
| 63 | #check stdout |
test/incremental/unreferenced_error+3-6| ... | ... | @@ -23,8 +23,7 @@ pub fn main() !void { |
| 23 | 23 | const a = @compileError("bad a"); |
| 24 | 24 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 25 | 25 | #} |
| 26 | #update { | |
| 27 | introduce compile error#} | |
| 26 | #update "introduce compile error" | |
| 28 | 27 | #check errors { |
| 29 | 28 | main.zig:5:11: error: bad a |
| 30 | 29 | #} |
| ... | ... | @@ -38,8 +37,7 @@ const a = @compileError("bad a"); |
| 38 | 37 | const b = "Hi there!\n"; |
| 39 | 38 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 40 | 39 | #} |
| 41 | #update { | |
| 42 | remove error reference#} | |
| 40 | #update "remove error reference" | |
| 43 | 41 | #check stdout { |
| 44 | 42 | Hi there! |
| 45 | 43 | #} |
| ... | ... | @@ -53,8 +51,7 @@ const a = "Back to a\n"; |
| 53 | 51 | const b = @compileError("bad b"); |
| 54 | 52 | const io = std.Io.Threaded.global_single_threaded.io(); |
| 55 | 53 | #} |
| 56 | #update { | |
| 57 | introduce and remove reference to error#} | |
| 54 | #update "introduce and remove reference to error" | |
| 58 | 55 | #check stdout { |
| 59 | 56 | Back 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 { | |
| 33 | export fn entry(ptr: *allowzero i16) i16 { | |
| 34 | return ptr.*; | |
| 35 | } | |
| 36 | #} | |
| 37 | #update "load" | |
| 38 | #check llvm { | |
| 39 | define #...@test.entry(ptr #...%0) #...#0 #...{ | |
| 40 | #...load i16, ptr %0#... | |
| 41 | } | |
| 42 | ||
| 43 | #... | |
| 44 | attributes #0 = {#... null_pointer_is_valid #...} | |
| 45 | #} | |
| 46 | ||
| 47 | #write test.zig { | |
| 48 | export fn entry(ptr: *allowzero i16) void { | |
| 49 | ptr.* = 42; | |
| 50 | } | |
| 51 | #} | |
| 52 | #update "store" | |
| 53 | #check llvm { | |
| 54 | define #...@test.entry(ptr #...%0) #...#0 #...{ | |
| 55 | #...store i16 42, ptr %0#... | |
| 56 | } | |
| 57 | ||
| 58 | #... | |
| 59 | attributes #0 = {#... null_pointer_is_valid #...} | |
| 60 | #} | |
| 61 | ||
| 62 | #write test.zig { | |
| 63 | export fn entry(ptr: *allowzero i16) i16 { | |
| 64 | return entry2(ptr[0..1]); | |
| 65 | } | |
| 66 | fn entry2(slice: []allowzero i16) i16 { | |
| 67 | @setRuntimeSafety(false); | |
| 68 | return slice[0]; | |
| 69 | } | |
| 70 | #} | |
| 71 | #update "slice load" | |
| 72 | #check llvm { | |
| 73 | define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{ | |
| 74 | #...load i16, ptr %#... | |
| 75 | } | |
| 76 | ||
| 77 | #... | |
| 78 | attributes #2 = {#... null_pointer_is_valid #...} | |
| 79 | #} | |
| 80 | ||
| 81 | #write test.zig { | |
| 82 | export fn entry(ptr: *allowzero i16) void { | |
| 83 | entry2(ptr[0..1]); | |
| 84 | } | |
| 85 | fn entry2(slice: []allowzero i16) void { | |
| 86 | @setRuntimeSafety(false); | |
| 87 | slice[0] = 42; | |
| 88 | } | |
| 89 | #} | |
| 90 | #update "slice store" | |
| 91 | #check llvm { | |
| 92 | define #...@test.entry2(#..., ptr #...%1, #...) #...#2 #...{ | |
| 93 | #...store i16 42, ptr %#... | |
| 94 | } | |
| 95 | ||
| 96 | #... | |
| 97 | attributes #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 { | |
| 78 | export fn entry(arr: *const [16]u8) @Vector(16, u8) { | |
| 79 | return arr.*; | |
| 80 | } | |
| 81 | #} | |
| 82 | #update "one vector load" | |
| 83 | #check llvm { | |
| 84 | define #...<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 { | |
| 92 | export 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 { | |
| 100 | define #...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 { | |
| 29 | export fn entry(ptr: *volatile i16) void { | |
| 30 | ptr.* = 123; | |
| 31 | ptr.* = 321; | |
| 32 | } | |
| 33 | #} | |
| 34 | #update "volatile" | |
| 35 | #check llvm { | |
| 36 | define #...@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 { | |
| 44 | export fn entry(ptr: *volatile i16) void { | |
| 45 | entry2(ptr[0..1]); | |
| 46 | } | |
| 47 | fn 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 { | |
| 55 | define #...@test.entry(#...) #...{ | |
| 56 | #... | |
| 57 | } | |
| 58 | ||
| 59 | #... | |
| 60 | define #...@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 { | |
| 74 | export 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 { | |
| 82 | define #...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 { | |
| 21 | export fn entry(ptr: *i16) i16 { | |
| 22 | return ptr.*; | |
| 23 | } | |
| 24 | #} | |
| 25 | #update "store" | |
| 26 | #check llvm { | |
| 27 | define #...@test.entry(ptr #...nonnull #...%0) #...{ | |
| 28 | #...load i16, ptr %0#... | |
| 29 | } | |
| 30 | ||
| 31 | #} | |
| 32 | ||
| 33 | #write test.zig { | |
| 34 | export fn entry(ptr: *i16) void { | |
| 35 | ptr.* = 42; | |
| 36 | } | |
| 37 | #} | |
| 38 | #update "load" | |
| 39 | #check llvm { | |
| 40 | define #...@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 { | |
| 37 | export fn entry(ptr: *i16) void { | |
| 38 | _ = @atomicLoad(i16, ptr, .acquire); | |
| 39 | } | |
| 40 | #} | |
| 41 | #update "atomic acquire" | |
| 42 | #check llvm { | |
| 43 | define #...@test.entry(ptr #...%0) #...{ | |
| 44 | #...load atomic i16, ptr %0 acquire#... | |
| 45 | } | |
| 46 | ||
| 47 | #} | |
| 48 | ||
| 49 | #write test.zig { | |
| 50 | export fn entry(ptr: *volatile i16) void { | |
| 51 | _ = @atomicLoad(i16, ptr, .unordered); | |
| 52 | } | |
| 53 | #} | |
| 54 | #update "atomic volatile unordered" | |
| 55 | #check llvm { | |
| 56 | define #...@test.entry(ptr #...%0) #...{ | |
| 57 | #...load atomic volatile i16, ptr %0 unordered#... | |
| 58 | } | |
| 59 | ||
| 60 | #} | |
| 61 | ||
| 62 | #write test.zig { | |
| 63 | export fn entry(ptr: *volatile i16) void { | |
| 64 | _ = ptr.*; | |
| 65 | } | |
| 66 | #} | |
| 67 | #update "volatile" | |
| 68 | #check llvm { | |
| 69 | define #...@test.entry(ptr #...%0) #...{ | |
| 70 | #...load volatile i16, ptr %0#... | |
| 71 | } | |
| 72 | ||
| 73 | #} | |
| 74 | ||
| 75 | #write test.zig { | |
| 76 | export fn entry(ptr: *volatile i16) void { | |
| 77 | entry2(ptr[0..1]); | |
| 78 | } | |
| 79 | fn entry2(slice: []volatile i16) void { | |
| 80 | @setRuntimeSafety(false); | |
| 81 | _ = slice[0]; | |
| 82 | } | |
| 83 | #} | |
| 84 | #update "volatile slice" | |
| 85 | #check llvm { | |
| 86 | define #...@test.entry(#...) #...{ | |
| 87 | #... | |
| 88 | } | |
| 89 | ||
| 90 | #... | |
| 91 | define #...@test.entry2(#...) #...{ | |
| 92 | #...load volatile i16, ptr %#... | |
| 93 | } | |
| 94 | ||
| 95 | #} | |
| 96 | ||
| 97 | #write test.zig { | |
| 98 | const S = packed struct(u16) { a: u2, b: u8, c: u6 }; | |
| 99 | export fn entry(ptr: *volatile S) void { | |
| 100 | _ = ptr.b; | |
| 101 | } | |
| 102 | #} | |
| 103 | #update "volatile packed" | |
| 104 | #check llvm { | |
| 105 | define #...@test.entry(ptr #...%0) #...{ | |
| 106 | #...load volatile i16, ptr %#... | |
| 107 | } | |
| 108 | ||
| 109 | #} |
test/llvm_ir.zig deleted-170| ... | ... | @@ -1,170 +0,0 @@ |
| 1 | pub 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 | ||
| 169 | const std = @import("std"); | |
| 170 | const tests = @import("tests.zig"); |
test/llvm_targets.zig deleted-382| ... | ... | @@ -1,382 +0,0 @@ |
| 1 | const std = @import("std"); | |
| 2 | const Cases = @import("src/Cases.zig"); | |
| 3 | ||
| 4 | const 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 | ||
| 365 | pub 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 | 75 | |
| 76 | 76 | emit_asm: bool = false, |
| 77 | 77 | emit_bin: bool = true, |
| 78 | emit_h: bool = false, | |
| 79 | 78 | is_test: bool = false, |
| 80 | 79 | expect_exact: bool = false, |
| 81 | 80 | backend: Backend = .auto, |
| ... | ... | @@ -165,38 +164,6 @@ pub fn exeFromCompiledC(ctx: *Cases, name: []const u8, target_query: std.Target. |
| 165 | 164 | return &ctx.cases.items[ctx.cases.items.len - 1]; |
| 166 | 165 | } |
| 167 | 166 | |
| 168 | pub 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 | ||
| 200 | 167 | pub fn addObj( |
| 201 | 168 | ctx: *Cases, |
| 202 | 169 | name: []const u8, |
test/src/LlvmIr.zig deleted-135| ... | ... | @@ -1,135 +0,0 @@ |
| 1 | b: *std.Build, | |
| 2 | options: Options, | |
| 3 | root_step: *std.Build.Step, | |
| 4 | ||
| 5 | pub const Options = struct { | |
| 6 | enable_llvm: bool, | |
| 7 | test_filters: []const []const u8, | |
| 8 | test_target_filters: []const []const u8, | |
| 9 | }; | |
| 10 | ||
| 11 | const 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 | ||
| 45 | pub 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 | ||
| 60 | pub 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 | ||
| 75 | pub 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 | ||
| 134 | const LlvmIr = @This(); | |
| 135 | const std = @import("std"); |
test/src/Runner.zig deleted-2140| ... | ... | @@ -1,2140 +0,0 @@ |
| 1 | const assert = std.debug.assert; | |
| 2 | const builtin = @import("builtin"); | |
| 3 | const std = @import("std"); | |
| 4 | const Runner = @This(); | |
| 5 | ||
| 6 | gpa: std.mem.Allocator, | |
| 7 | arena: *std.heap.ArenaAllocator, | |
| 8 | environ_map: std.process.Environ.Map, | |
| 9 | io: std.Io, | |
| 10 | prog_node: std.Progress.Node, | |
| 11 | args: Args, | |
| 12 | host: std.Target, | |
| 13 | server: std.zig.Server, | |
| 14 | eb_wip: std.zig.ErrorBundle.Wip, | |
| 15 | ||
| 16 | const 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 | ||
| 54 | fn 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 | ||
| 62 | const FailError = error{AlreadyReported} || std.mem.Allocator.Error || std.Io.Cancelable; | |
| 63 | fn fail(runner: *Runner, comptime fmt: []const u8, args: anytype) FailError { | |
| 64 | return runner.failString(try runner.eb_wip.printString(fmt, args)); | |
| 65 | } | |
| 66 | fn 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 | ||
| 73 | pub const ProtocolError = error{ | |
| 74 | ServerReadFailed, | |
| 75 | ServerWriteFailed, | |
| 76 | ServerEndOfStream, | |
| 77 | } || FailError; | |
| 78 | pub 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 | ||
| 372 | fn 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 | } | |
| 381 | fn 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 | ||
| 397 | pub 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 | }; | |
| 537 | pub 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 | ||
| 583 | const 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 | ||
| 594 | const TestError = error{ | |
| 595 | SkipTest, | |
| 596 | } || FailError; | |
| 597 | fn 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 | } | |
| 752 | const Command = enum { todo, skip, exe, lib, obj, write, delete, update, check }; | |
| 753 | fn 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 | ||
| 1002 | fn 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 | } | |
| 1145 | const 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 | ||
| 1656 | const 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 | }; | |
| 1677 | pub 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 | } | |
| 1938 | fn 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 | 6 | const Step = std.Build.Step; |
| 7 | 7 | |
| 8 | 8 | // Cases |
| 9 | const llvm_ir = @import("llvm_ir.zig"); | |
| 10 | 9 | const libc = @import("libc.zig"); |
| 11 | 10 | const link = @import("link.zig"); |
| 12 | 11 | |
| 13 | 12 | // Implementations |
| 14 | 13 | pub const ErrorTracesContext = @import("src/ErrorTrace.zig"); |
| 15 | 14 | pub const StackTracesContext = @import("src/StackTrace.zig"); |
| 16 | pub const LlvmIrContext = @import("src/LlvmIr.zig"); | |
| 17 | 15 | pub const LibcContext = @import("src/Libc.zig"); |
| 18 | 16 | pub const LinkContext = @import("src/Link.zig"); |
| 19 | 17 | |
| ... | ... | @@ -2188,150 +2186,6 @@ const link_targets = blk: { |
| 2188 | 2186 | }; |
| 2189 | 2187 | }; |
| 2190 | 2188 | |
| 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 | |
| 2196 | const 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 | ||
| 2204 | pub 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 | ||
| 2266 | pub 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 | ||
| 2335 | 2189 | pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step { |
| 2336 | 2190 | const step = b.step("test-stack-traces", "Run the stack trace tests"); |
| 2337 | 2191 | |
| ... | ... | @@ -3170,7 +3024,6 @@ pub fn addCases( |
| 3170 | 3024 | b: *std.Build, |
| 3171 | 3025 | parent_step: *Step, |
| 3172 | 3026 | case_test_options: @import("src/Cases.zig").CaseTestOptions, |
| 3173 | build_options: @import("cases.zig").BuildOptions, | |
| 3174 | 3027 | ) !void { |
| 3175 | 3028 | const arena = b.allocator; |
| 3176 | 3029 | const gpa = b.allocator; |
| ... | ... | @@ -3184,7 +3037,7 @@ pub fn addCases( |
| 3184 | 3037 | defer dir.close(io); |
| 3185 | 3038 | |
| 3186 | 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); | |
| 3188 | 3041 | |
| 3189 | 3042 | cases.lowerToBuildSteps( |
| 3190 | 3043 | b, |
| ... | ... | @@ -3193,6 +3046,7 @@ pub fn addCases( |
| 3193 | 3046 | ); |
| 3194 | 3047 | } |
| 3195 | 3048 | |
| 3049 | pub const RunnerTarget = @import("Runner.zig").Target; | |
| 3196 | 3050 | pub const RunnerOptions = struct { |
| 3197 | 3051 | test_filters: []const []const u8, |
| 3198 | 3052 | test_target_filters: []const []const u8, |
| ... | ... | @@ -3205,10 +3059,13 @@ pub const RunnerOptions = struct { |
| 3205 | 3059 | skip_darwin: bool, |
| 3206 | 3060 | skip_linux: bool, |
| 3207 | 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 | 3066 | gdb: ?[]const u8, |
| 3209 | 3067 | lldb: ?[]const u8, |
| 3210 | 3068 | }; |
| 3211 | ||
| 3212 | 3069 | pub fn addRunnerTests( |
| 3213 | 3070 | b: *std.Build, |
| 3214 | 3071 | runner: *std.Build.Step.Compile, |
| ... | ... | @@ -3224,21 +3081,24 @@ pub fn addRunnerTests( |
| 3224 | 3081 | defer tests_dir.close(b.graph.io); |
| 3225 | 3082 | var test_it = tests_dir.iterate(); |
| 3226 | 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 | 3084 | switch (@"test".kind) { |
| 3233 | 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 | 3090 | .directory => {}, |
| 3236 | 3091 | } |
| 3237 | 3092 | |
| 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 | 3097 | const run = b.addRunArtifact(runner); |
| 3239 | 3098 | run.setName(@"test".name); |
| 3240 | 3099 | run.enableProtocolMode(); |
| 3241 | 3100 | |
| 3101 | const test_path = tests_path.path(b, @"test".name); | |
| 3242 | 3102 | switch (@"test".kind) { |
| 3243 | 3103 | else => continue, |
| 3244 | 3104 | .file => run.addFileArg(test_path), |
| ... | ... | @@ -3249,7 +3109,7 @@ pub fn addRunnerTests( |
| 3249 | 3109 | _ = run.addPrefixedOutputDirectoryArg("--src=", "src"); |
| 3250 | 3110 | |
| 3251 | 3111 | for (matrix) |test_target| { |
| 3252 | const resolved_target = b.resolveTargetQuery(test_target.target); | |
| 3112 | const resolved_target = b.resolveTargetQuery(test_target.toQuery()); | |
| 3253 | 3113 | |
| 3254 | 3114 | if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) |
| 3255 | 3115 | continue; |
| ... | ... | @@ -3265,15 +3125,18 @@ pub fn addRunnerTests( |
| 3265 | 3125 | if (options.skip_darwin and target.os.tag.isDarwin()) continue; |
| 3266 | 3126 | if (options.skip_linux and target.os.tag == .linux) continue; |
| 3267 | 3127 | |
| 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 | } | |
| 3269 | 3138 | |
| 3270 | const target_str = b.fmt("{s}-{t}-{t}-{t}-{t}", .{ | |
| 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 | }); | |
| 3139 | const target_str = b.fmt("{f}", .{test_target}); | |
| 3277 | 3140 | |
| 3278 | 3141 | for (options.test_target_filters) |filter| { |
| 3279 | 3142 | if (std.mem.find(u8, target_str, filter) != null) break; |
| ... | ... | @@ -3303,25 +3166,6 @@ fn isEditorFileName(name: []const u8) bool { |
| 3303 | 3166 | std.mem.endsWith(u8, name, "~") or std.mem.endsWith(u8, name, ".swp"); |
| 3304 | 3167 | } |
| 3305 | 3168 | |
| 3306 | pub 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 | ||
| 3325 | 3169 | const libc_test_nsz_targets: []const std.Target.Query = &.{ |
| 3326 | 3170 | .{ |
| 3327 | 3171 | .cpu_arch = .arm, |