authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-25 00:02:58-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-25 00:02:58-07:00
log015cd79f89aefd26fb1df91f3d07f7dcade21c4a
tree715e950ffc29e59938152f0691e059863980dd62
parentff2ec0dc5ad272113379ff485bb71c6c1637d948

stage2: implement caching for ZIR code

Notably this exposed an issue with the language having to do with the secret safety tag on untagged unions. How can we have our cake and eat it too? Not solved in this commit. I will file a language proposal to tackle this issue soon. Fixes a compile error in `std.fs.File.readvAll`.

6 files changed, 587 insertions(+), 22 deletions(-)

BRANCH_TODO+3-5
...@@ -1,15 +1,10 @@...@@ -1,15 +1,10 @@
1 * nested function decl: how to refer to params?
2 * look for cached zir code
3 * save zir code to cache
4 * keep track of file dependencies/dependants1 * keep track of file dependencies/dependants
5 * unload files from memory when a dependency is dropped2 * unload files from memory when a dependency is dropped
6 * implement zir error notes
73
8 * implement the new AstGen compile errors4 * implement the new AstGen compile errors
95
10 * get rid of failed_root_src_file6 * get rid of failed_root_src_file
11 * get rid of Scope.DeclRef7 * get rid of Scope.DeclRef
12 * get rid of optional_type_from_ptr_elem
13 * handle decl collision with usingnamespace8 * handle decl collision with usingnamespace
14 * the decl doing the looking up needs to create a decl dependency9 * the decl doing the looking up needs to create a decl dependency
15 on each usingnamespace decl10 on each usingnamespace decl
...@@ -38,6 +33,9 @@...@@ -38,6 +33,9 @@
38 AstGen can report more than one compile error.33 AstGen can report more than one compile error.
3934
40 * AstGen: add result location pointers to function calls35 * AstGen: add result location pointers to function calls
36 * nested function decl: how to refer to params?
37
38 * detect when to put cached ZIR into the local cache instead of the global one
4139
42 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|40 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
43 pkg.namespace_hash41 pkg.namespace_hash
lib/std/fs/file.zig+1-1
...@@ -482,7 +482,7 @@ pub const File = struct {...@@ -482,7 +482,7 @@ pub const File = struct {
482 /// order to handle partial reads from the underlying OS layer.482 /// order to handle partial reads from the underlying OS layer.
483 /// See https://github.com/ziglang/zig/issues/7699483 /// See https://github.com/ziglang/zig/issues/7699
484 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {484 pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
485 if (iovecs.len == 0) return;485 if (iovecs.len == 0) return 0;
486486
487 var i: usize = 0;487 var i: usize = 0;
488 var off: usize = 0;488 var off: usize = 0;
src/Compilation.zig+8-6
...@@ -434,10 +434,10 @@ pub const AllErrors = struct {...@@ -434,10 +434,10 @@ pub const AllErrors = struct {
434 arena: *Allocator,434 arena: *Allocator,
435 errors: *std.ArrayList(Message),435 errors: *std.ArrayList(Message),
436 file: *Module.Scope.File,436 file: *Module.Scope.File,
437 source: []const u8,
438 ) !void {437 ) !void {
439 assert(file.zir_loaded);438 assert(file.zir_loaded);
440 assert(file.tree_loaded);439 assert(file.tree_loaded);
440 assert(file.source_loaded);
441 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];441 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
442 assert(payload_index != 0);442 assert(payload_index != 0);
443443
...@@ -466,7 +466,7 @@ pub const AllErrors = struct {...@@ -466,7 +466,7 @@ pub const AllErrors = struct {
466 }466 }
467 break :blk token_starts[note_item.data.token] + note_item.data.byte_offset;467 break :blk token_starts[note_item.data.token] + note_item.data.byte_offset;
468 };468 };
469 const loc = std.zig.findLineColumn(source, byte_offset);469 const loc = std.zig.findLineColumn(file.source, byte_offset);
470470
471 note.* = .{471 note.* = .{
472 .src = .{472 .src = .{
...@@ -492,7 +492,7 @@ pub const AllErrors = struct {...@@ -492,7 +492,7 @@ pub const AllErrors = struct {
492 }492 }
493 break :blk token_starts[item.data.token] + item.data.byte_offset;493 break :blk token_starts[item.data.token] + item.data.byte_offset;
494 };494 };
495 const loc = std.zig.findLineColumn(source, byte_offset);495 const loc = std.zig.findLineColumn(file.source, byte_offset);
496496
497 try errors.append(.{497 try errors.append(.{
498 .src = .{498 .src = .{
...@@ -1709,9 +1709,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1709,9 +1709,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1709 if (entry.value) |msg| {1709 if (entry.value) |msg| {
1710 try AllErrors.add(module, &arena, &errors, msg.*);1710 try AllErrors.add(module, &arena, &errors, msg.*);
1711 } else {1711 } else {
1712 // Must be ZIR errors.1712 // Must be ZIR errors. In order for ZIR errors to exist, the parsing
1713 const source = try entry.key.getSource(module.gpa);1713 // must have completed successfully.
1714 try AllErrors.addZir(&arena.allocator, &errors, entry.key, source);1714 const tree = try entry.key.getTree(module.gpa);
1715 assert(tree.errors.len == 0);
1716 try AllErrors.addZir(&arena.allocator, &errors, entry.key);
1715 }1717 }
1716 }1718 }
1717 for (module.failed_decls.items()) |entry| {1719 for (module.failed_decls.items()) |entry| {
src/Module.zig+264-9
...@@ -15,6 +15,7 @@ const ast = std.zig.ast;...@@ -15,6 +15,7 @@ const ast = std.zig.ast;
1515
16const Module = @This();16const Module = @This();
17const Compilation = @import("Compilation.zig");17const Compilation = @import("Compilation.zig");
18const Cache = @import("Cache.zig");
18const Value = @import("value.zig").Value;19const Value = @import("value.zig").Value;
19const Type = @import("type.zig").Type;20const Type = @import("type.zig").Type;
20const TypedValue = @import("TypedValue.zig");21const TypedValue = @import("TypedValue.zig");
...@@ -771,6 +772,15 @@ pub const Scope = struct {...@@ -771,6 +772,15 @@ pub const Scope = struct {
771 return source;772 return source;
772 }773 }
773774
775 pub fn getTree(file: *File, gpa: *Allocator) !*const ast.Tree {
776 if (file.tree_loaded) return &file.tree;
777
778 const source = try file.getSource(gpa);
779 file.tree = try std.zig.parse(gpa, source);
780 file.tree_loaded = true;
781 return &file.tree;
782 }
783
774 pub fn destroy(file: *File, gpa: *Allocator) void {784 pub fn destroy(file: *File, gpa: *Allocator) void {
775 file.deinit(gpa);785 file.deinit(gpa);
776 gpa.destroy(file);786 gpa.destroy(file);
...@@ -2676,6 +2686,20 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {...@@ -2676,6 +2686,20 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
2676 gpa.free(export_list);2686 gpa.free(export_list);
2677}2687}
26782688
2689const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
2690// TODO This is taking advantage of matching stage1 debug union layout.
2691// We need a better language feature for initializing a union with
2692// a runtime known tag.
2693const Stage1DataLayout = extern struct {
2694 safety_tag: u8,
2695 data: [8]u8 align(8),
2696};
2697comptime {
2698 if (data_has_safety_tag) {
2699 assert(@sizeOf(Stage1DataLayout) == @sizeOf(Zir.Inst.Data));
2700 }
2701}
2702
2679pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {2703pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
2680 const tracy = trace(@src());2704 const tracy = trace(@src());
2681 defer tracy.end();2705 defer tracy.end();
...@@ -2684,15 +2708,166 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2684,15 +2708,166 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2684 const gpa = mod.gpa;2708 const gpa = mod.gpa;
26852709
2686 // In any case we need to examine the stat of the file to determine the course of action.2710 // In any case we need to examine the stat of the file to determine the course of action.
2687 var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});2711 var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
2688 defer f.close();2712 defer source_file.close();
26892713
2690 const stat = try f.stat();2714 const stat = try source_file.stat();
2715
2716 const want_local_cache = file.pkg == mod.root_pkg;
2717 const digest = hash: {
2718 var path_hash: Cache.HashHelper = .{};
2719 if (!want_local_cache) {
2720 path_hash.addOptionalBytes(file.pkg.root_src_directory.path);
2721 }
2722 path_hash.addBytes(file.sub_file_path);
2723 break :hash path_hash.final();
2724 };
2725 const cache_directory = if (want_local_cache)
2726 comp.local_cache_directory
2727 else
2728 comp.global_cache_directory;
2729
2730 var cache_file: ?std.fs.File = null;
2731 defer if (cache_file) |f| f.close();
2732
2733 // TODO do this before spawning astgen workers
2734 var zir_dir = try cache_directory.handle.makeOpenPath("z", .{});
2735 defer zir_dir.close();
26912736
2692 // Determine whether we need to reload the file from disk and redo parsing and AstGen.2737 // Determine whether we need to reload the file from disk and redo parsing and AstGen.
2693 switch (file.status) {2738 switch (file.status) {
2694 .never_loaded, .retryable_failure => {2739 .never_loaded, .retryable_failure => cached: {
2695 log.debug("first-time AstGen: {s}", .{file.sub_file_path});2740 // First, load the cached ZIR code, if any.
2741 log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
2742 file.sub_file_path, want_local_cache, &digest,
2743 });
2744
2745 // We ask for a lock in order to coordinate with other zig processes.
2746 // If another process is already working on this file, we will get the cached
2747 // version. Likewise if we're working on AstGen and another process asks for
2748 // the cached file, they'll get it.
2749 cache_file = zir_dir.openFile(&digest, .{ .lock = .Shared }) catch |err| switch (err) {
2750 error.PathAlreadyExists => unreachable, // opening for reading
2751 error.NoSpaceLeft => unreachable, // opening for reading
2752 error.NotDir => unreachable, // no dir components
2753 error.InvalidUtf8 => unreachable, // it's a hex encoded name
2754 error.BadPathName => unreachable, // it's a hex encoded name
2755 error.NameTooLong => unreachable, // it's a fixed size name
2756 error.PipeBusy => unreachable, // it's not a pipe
2757 error.WouldBlock => unreachable, // not asking for non-blocking I/O
2758
2759 error.SymLinkLoop,
2760 error.FileNotFound,
2761 error.Unexpected,
2762 => break :cached,
2763
2764 else => |e| return e, // Retryable errors are handled at callsite.
2765 };
2766
2767 // First we read the header to determine the lengths of arrays.
2768 const header = cache_file.?.reader().readStruct(Zir.Header) catch |err| switch (err) {
2769 // This can happen if Zig bails out of this function between creating
2770 // the cached file and writing it.
2771 error.EndOfStream => break :cached,
2772 else => |e| return e,
2773 };
2774 const unchanged_metadata =
2775 stat.size == header.stat_size and
2776 stat.mtime == header.stat_mtime and
2777 stat.inode == header.stat_inode;
2778
2779 if (!unchanged_metadata) {
2780 log.debug("AstGen cache stale: {s}", .{file.sub_file_path});
2781 break :cached;
2782 }
2783 log.debug("AstGen cache hit: {s}", .{file.sub_file_path});
2784
2785 var instructions: std.MultiArrayList(Zir.Inst) = .{};
2786 defer instructions.deinit(gpa);
2787
2788 try instructions.resize(gpa, header.instructions_len);
2789
2790 var zir: Zir = .{
2791 .instructions = instructions.toOwnedSlice(),
2792 .string_bytes = &.{},
2793 .extra = &.{},
2794 };
2795 var keep_zir = false;
2796 defer if (!keep_zir) zir.deinit(gpa);
2797
2798 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
2799 zir.extra = try gpa.alloc(u32, header.extra_len);
2800
2801 const safety_buffer = if (data_has_safety_tag)
2802 try gpa.alloc([8]u8, header.instructions_len)
2803 else
2804 undefined;
2805 defer if (data_has_safety_tag) gpa.free(safety_buffer);
2806
2807 const data_ptr = if (data_has_safety_tag)
2808 @ptrCast([*]u8, safety_buffer.ptr)
2809 else
2810 @ptrCast([*]u8, zir.instructions.items(.data).ptr);
2811
2812 var iovecs = [_]std.os.iovec{
2813 .{
2814 .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr),
2815 .iov_len = header.instructions_len,
2816 },
2817 .{
2818 .iov_base = data_ptr,
2819 .iov_len = header.instructions_len * 8,
2820 },
2821 .{
2822 .iov_base = zir.string_bytes.ptr,
2823 .iov_len = header.string_bytes_len,
2824 },
2825 .{
2826 .iov_base = @ptrCast([*]u8, zir.extra.ptr),
2827 .iov_len = header.extra_len * 4,
2828 },
2829 };
2830 const amt_read = try cache_file.?.readvAll(&iovecs);
2831 const amt_expected = zir.instructions.len * 9 +
2832 zir.string_bytes.len +
2833 zir.extra.len * 4;
2834 if (amt_read != amt_expected) {
2835 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
2836 zir.deinit(gpa);
2837 break :cached;
2838 }
2839 if (data_has_safety_tag) {
2840 const tags = zir.instructions.items(.tag);
2841 for (zir.instructions.items(.data)) |*data, i| {
2842 const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])];
2843 const as_struct = @ptrCast(*Stage1DataLayout, data);
2844 as_struct.* = .{
2845 .safety_tag = @enumToInt(union_tag),
2846 .data = safety_buffer[i],
2847 };
2848 }
2849 }
2850
2851 keep_zir = true;
2852 file.zir = zir;
2853 file.zir_loaded = true;
2854 file.stat_size = header.stat_size;
2855 file.stat_inode = header.stat_inode;
2856 file.stat_mtime = header.stat_mtime;
2857 file.status = .success;
2858 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
2859
2860 // TODO don't report compile errors until Sema @importFile
2861 if (file.zir.hasCompileErrors()) {
2862 {
2863 const lock = comp.mutex.acquire();
2864 defer lock.release();
2865 try mod.failed_files.putNoClobber(gpa, file, null);
2866 }
2867 file.status = .astgen_failure;
2868 return error.AnalysisFail;
2869 }
2870 return;
2696 },2871 },
2697 .parse_failure, .astgen_failure, .success => {2872 .parse_failure, .astgen_failure, .success => {
2698 const unchanged_metadata =2873 const unchanged_metadata =
...@@ -2708,6 +2883,29 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2708,6 +2883,29 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2708 log.debug("metadata changed: {s}", .{file.sub_file_path});2883 log.debug("metadata changed: {s}", .{file.sub_file_path});
2709 },2884 },
2710 }2885 }
2886 if (cache_file) |f| {
2887 f.close();
2888 cache_file = null;
2889 }
2890 cache_file = zir_dir.createFile(&digest, .{ .lock = .Exclusive }) catch |err| switch (err) {
2891 error.NotDir => unreachable, // no dir components
2892 error.InvalidUtf8 => unreachable, // it's a hex encoded name
2893 error.BadPathName => unreachable, // it's a hex encoded name
2894 error.NameTooLong => unreachable, // it's a fixed size name
2895 error.PipeBusy => unreachable, // it's not a pipe
2896 error.WouldBlock => unreachable, // not asking for non-blocking I/O
2897 error.FileNotFound => unreachable, // no dir components
2898
2899 else => |e| {
2900 const pkg_path = file.pkg.root_src_directory.path orelse ".";
2901 const cache_path = cache_directory.path orelse ".";
2902 log.warn("unable to save cached ZIR code for {s}/{s} to {s}/z/{s}: {s}", .{
2903 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(e),
2904 });
2905 return;
2906 },
2907 };
2908
2711 // Clear compile error for this file.2909 // Clear compile error for this file.
2712 switch (file.status) {2910 switch (file.status) {
2713 .success, .retryable_failure => {},2911 .success, .retryable_failure => {},
...@@ -2726,7 +2924,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2726,7 +2924,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
27262924
2727 const source = try gpa.allocSentinel(u8, stat.size, 0);2925 const source = try gpa.allocSentinel(u8, stat.size, 0);
2728 defer if (!file.source_loaded) gpa.free(source);2926 defer if (!file.source_loaded) gpa.free(source);
2729 const amt = try f.readAll(source);2927 const amt = try source_file.readAll(source);
2730 if (amt != stat.size)2928 if (amt != stat.size)
2731 return error.UnexpectedEndOfFile;2929 return error.UnexpectedEndOfFile;
27322930
...@@ -2770,7 +2968,67 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2770,7 +2968,67 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
27702968
2771 file.zir = try AstGen.generate(gpa, file);2969 file.zir = try AstGen.generate(gpa, file);
2772 file.zir_loaded = true;2970 file.zir_loaded = true;
2971 file.status = .success;
2972 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
2973
2974 const safety_buffer = if (data_has_safety_tag)
2975 try gpa.alloc([8]u8, file.zir.instructions.len)
2976 else
2977 undefined;
2978 defer if (data_has_safety_tag) gpa.free(safety_buffer);
2979 const data_ptr = if (data_has_safety_tag)
2980 @ptrCast([*]const u8, safety_buffer.ptr)
2981 else
2982 @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr);
2983 if (data_has_safety_tag) {
2984 // The `Data` union has a safety tag but in the file format we store it without.
2985 const tags = file.zir.instructions.items(.tag);
2986 for (file.zir.instructions.items(.data)) |*data, i| {
2987 const as_struct = @ptrCast(*const Stage1DataLayout, data);
2988 safety_buffer[i] = as_struct.data;
2989 }
2990 }
2991
2992 const header: Zir.Header = .{
2993 .instructions_len = @intCast(u32, file.zir.instructions.len),
2994 .string_bytes_len = @intCast(u32, file.zir.string_bytes.len),
2995 .extra_len = @intCast(u32, file.zir.extra.len),
2996
2997 .stat_size = stat.size,
2998 .stat_inode = stat.inode,
2999 .stat_mtime = stat.mtime,
3000 };
3001 var iovecs = [_]std.os.iovec_const{
3002 .{
3003 .iov_base = @ptrCast([*]const u8, &header),
3004 .iov_len = @sizeOf(Zir.Header),
3005 },
3006 .{
3007 .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr),
3008 .iov_len = file.zir.instructions.len,
3009 },
3010 .{
3011 .iov_base = data_ptr,
3012 .iov_len = file.zir.instructions.len * 8,
3013 },
3014 .{
3015 .iov_base = file.zir.string_bytes.ptr,
3016 .iov_len = file.zir.string_bytes.len,
3017 },
3018 .{
3019 .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr),
3020 .iov_len = file.zir.extra.len * 4,
3021 },
3022 };
3023 cache_file.?.writevAll(&iovecs) catch |err| {
3024 const pkg_path = file.pkg.root_src_directory.path orelse ".";
3025 const cache_path = cache_directory.path orelse ".";
3026 log.warn("unable to write cached ZIR code for {s}/{s} to {s}/z/{s}: {s}", .{
3027 pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err),
3028 });
3029 };
27733030
3031 // TODO don't report compile errors until Sema @importFile
2774 if (file.zir.hasCompileErrors()) {3032 if (file.zir.hasCompileErrors()) {
2775 {3033 {
2776 const lock = comp.mutex.acquire();3034 const lock = comp.mutex.acquire();
...@@ -2780,9 +3038,6 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2780,9 +3038,6 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2780 file.status = .astgen_failure;3038 file.status = .astgen_failure;
2781 return error.AnalysisFail;3039 return error.AnalysisFail;
2782 }3040 }
2783
2784 log.debug("AstGen success: {s}", .{file.sub_file_path});
2785 file.status = .success;
2786}3041}
27873042
2788pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {3043pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
src/Zir.zig+310
...@@ -37,6 +37,17 @@ string_bytes: []u8,...@@ -37,6 +37,17 @@ string_bytes: []u8,
37/// The first few indexes are reserved. See `ExtraIndex` for the values.37/// The first few indexes are reserved. See `ExtraIndex` for the values.
38extra: []u32,38extra: []u32,
3939
40/// The data stored at byte offset 0 when ZIR is stored in a file.
41pub const Header = extern struct {
42 instructions_len: u32,
43 string_bytes_len: u32,
44 extra_len: u32,
45
46 stat_size: u64,
47 stat_inode: std.fs.File.INode,
48 stat_mtime: i128,
49};
50
40pub const ExtraIndex = enum(u32) {51pub const ExtraIndex = enum(u32) {
41 /// Ref. The main struct decl for this file.52 /// Ref. The main struct decl for this file.
42 main_struct,53 main_struct,
...@@ -139,6 +150,7 @@ pub const Inst = struct {...@@ -139,6 +150,7 @@ pub const Inst = struct {
139 data: Data,150 data: Data,
140151
141 /// These names are used directly as the instruction names in the text format.152 /// These names are used directly as the instruction names in the text format.
153 /// See `data_field_map` for a list of which `Data` fields are used by each `Tag`.
142 pub const Tag = enum(u8) {154 pub const Tag = enum(u8) {
143 /// Arithmetic addition, asserts no integer overflow.155 /// Arithmetic addition, asserts no integer overflow.
144 /// Uses the `pl_node` union field. Payload is `Bin`.156 /// Uses the `pl_node` union field. Payload is `Bin`.
...@@ -932,6 +944,7 @@ pub const Inst = struct {...@@ -932,6 +944,7 @@ pub const Inst = struct {
932 /// Uses the `un_node` field. The AST node is the var decl.944 /// Uses the `un_node` field. The AST node is the var decl.
933 resolve_inferred_alloc,945 resolve_inferred_alloc,
934946
947 /// Implements `resume` syntax. Uses `un_node` field.
935 @"resume",948 @"resume",
936 @"await",949 @"await",
937 await_nosuspend,950 await_nosuspend,
...@@ -1202,6 +1215,276 @@ pub const Inst = struct {...@@ -1202,6 +1215,276 @@ pub const Inst = struct {
1202 => true,1215 => true,
1203 };1216 };
1204 }1217 }
1218
1219 /// Used by debug safety-checking code.
1220 pub const data_tags = list: {
1221 @setEvalBranchQuota(2000);
1222 break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{
1223 .add = .pl_node,
1224 .addwrap = .pl_node,
1225 .array_cat = .pl_node,
1226 .array_mul = .pl_node,
1227 .array_type = .bin,
1228 .array_type_sentinel = .array_type_sentinel,
1229 .vector_type = .pl_node,
1230 .elem_type = .un_node,
1231 .indexable_ptr_len = .un_node,
1232 .anyframe_type = .un_node,
1233 .as = .bin,
1234 .as_node = .pl_node,
1235 .bit_and = .pl_node,
1236 .bitcast = .pl_node,
1237 .bitcast_result_ptr = .pl_node,
1238 .bit_not = .un_node,
1239 .bit_or = .pl_node,
1240 .block = .pl_node,
1241 .block_inline = .pl_node,
1242 .block_inline_var = .pl_node,
1243 .suspend_block = .pl_node,
1244 .bool_and = .pl_node,
1245 .bool_not = .un_node,
1246 .bool_or = .pl_node,
1247 .bool_br_and = .bool_br,
1248 .bool_br_or = .bool_br,
1249 .@"break" = .@"break",
1250 .break_inline = .@"break",
1251 .breakpoint = .node,
1252 .call = .pl_node,
1253 .call_chkused = .pl_node,
1254 .call_compile_time = .pl_node,
1255 .call_nosuspend = .pl_node,
1256 .call_async = .pl_node,
1257 .cmp_lt = .pl_node,
1258 .cmp_lte = .pl_node,
1259 .cmp_eq = .pl_node,
1260 .cmp_gte = .pl_node,
1261 .cmp_gt = .pl_node,
1262 .cmp_neq = .pl_node,
1263 .coerce_result_ptr = .bin,
1264 .condbr = .pl_node,
1265 .condbr_inline = .pl_node,
1266 .struct_decl = .pl_node,
1267 .struct_decl_packed = .pl_node,
1268 .struct_decl_extern = .pl_node,
1269 .union_decl = .pl_node,
1270 .union_decl_packed = .pl_node,
1271 .union_decl_extern = .pl_node,
1272 .enum_decl = .pl_node,
1273 .enum_decl_nonexhaustive = .pl_node,
1274 .opaque_decl = .pl_node,
1275 .error_set_decl = .pl_node,
1276 .dbg_stmt_node = .node,
1277 .decl_ref = .str_tok,
1278 .decl_val = .str_tok,
1279 .load = .un_node,
1280 .div = .pl_node,
1281 .elem_ptr = .bin,
1282 .elem_ptr_node = .pl_node,
1283 .elem_val = .bin,
1284 .elem_val_node = .pl_node,
1285 .ensure_result_used = .un_node,
1286 .ensure_result_non_error = .un_node,
1287 .error_union_type = .pl_node,
1288 .error_value = .str_tok,
1289 .@"export" = .pl_node,
1290 .field_ptr = .pl_node,
1291 .field_val = .pl_node,
1292 .field_ptr_named = .pl_node,
1293 .field_val_named = .pl_node,
1294 .func = .pl_node,
1295 .func_inferred = .pl_node,
1296 .import = .str_tok,
1297 .int = .int,
1298 .int_big = .str,
1299 .float = .float,
1300 .float128 = .pl_node,
1301 .int_type = .int_type,
1302 .is_non_null = .un_node,
1303 .is_null = .un_node,
1304 .is_non_null_ptr = .un_node,
1305 .is_null_ptr = .un_node,
1306 .is_err = .un_node,
1307 .is_err_ptr = .un_node,
1308 .loop = .pl_node,
1309 .repeat = .node,
1310 .repeat_inline = .node,
1311 .merge_error_sets = .pl_node,
1312 .mod_rem = .pl_node,
1313 .mul = .pl_node,
1314 .mulwrap = .pl_node,
1315 .param_type = .param_type,
1316 .ref = .un_tok,
1317 .ret_node = .un_node,
1318 .ret_coerce = .un_tok,
1319 .ptr_type_simple = .ptr_type_simple,
1320 .ptr_type = .ptr_type,
1321 .slice_start = .pl_node,
1322 .slice_end = .pl_node,
1323 .slice_sentinel = .pl_node,
1324 .store = .bin,
1325 .store_node = .pl_node,
1326 .store_to_block_ptr = .bin,
1327 .store_to_inferred_ptr = .bin,
1328 .str = .str,
1329 .sub = .pl_node,
1330 .subwrap = .pl_node,
1331 .negate = .un_node,
1332 .negate_wrap = .un_node,
1333 .typeof = .un_tok,
1334 .typeof_elem = .un_node,
1335 .typeof_log2_int_type = .un_node,
1336 .log2_int_type = .un_node,
1337 .@"unreachable" = .@"unreachable",
1338 .xor = .pl_node,
1339 .optional_type = .un_node,
1340 .optional_payload_safe = .un_node,
1341 .optional_payload_unsafe = .un_node,
1342 .optional_payload_safe_ptr = .un_node,
1343 .optional_payload_unsafe_ptr = .un_node,
1344 .err_union_payload_safe = .un_node,
1345 .err_union_payload_unsafe = .un_node,
1346 .err_union_payload_safe_ptr = .un_node,
1347 .err_union_payload_unsafe_ptr = .un_node,
1348 .err_union_code = .un_node,
1349 .err_union_code_ptr = .un_node,
1350 .ensure_err_payload_void = .un_tok,
1351 .enum_literal = .str_tok,
1352 .switch_block = .pl_node,
1353 .switch_block_multi = .pl_node,
1354 .switch_block_else = .pl_node,
1355 .switch_block_else_multi = .pl_node,
1356 .switch_block_under = .pl_node,
1357 .switch_block_under_multi = .pl_node,
1358 .switch_block_ref = .pl_node,
1359 .switch_block_ref_multi = .pl_node,
1360 .switch_block_ref_else = .pl_node,
1361 .switch_block_ref_else_multi = .pl_node,
1362 .switch_block_ref_under = .pl_node,
1363 .switch_block_ref_under_multi = .pl_node,
1364 .switch_capture = .switch_capture,
1365 .switch_capture_ref = .switch_capture,
1366 .switch_capture_multi = .switch_capture,
1367 .switch_capture_multi_ref = .switch_capture,
1368 .switch_capture_else = .switch_capture,
1369 .switch_capture_else_ref = .switch_capture,
1370 .validate_struct_init_ptr = .pl_node,
1371 .validate_array_init_ptr = .pl_node,
1372 .struct_init_empty = .un_node,
1373 .field_type = .pl_node,
1374 .field_type_ref = .pl_node,
1375 .struct_init = .pl_node,
1376 .struct_init_ref = .pl_node,
1377 .struct_init_anon = .pl_node,
1378 .struct_init_anon_ref = .pl_node,
1379 .array_init = .pl_node,
1380 .array_init_anon = .pl_node,
1381 .array_init_ref = .pl_node,
1382 .array_init_anon_ref = .pl_node,
1383 .union_init_ptr = .pl_node,
1384 .type_info = .un_node,
1385 .size_of = .un_node,
1386 .bit_size_of = .un_node,
1387 .fence = .node,
1388
1389 .ptr_to_int = .un_node,
1390 .error_to_int = .un_node,
1391 .int_to_error = .un_node,
1392 .compile_error = .un_node,
1393 .set_eval_branch_quota = .un_node,
1394 .enum_to_int = .un_node,
1395 .align_of = .un_node,
1396 .bool_to_int = .un_node,
1397 .embed_file = .un_node,
1398 .error_name = .un_node,
1399 .panic = .un_node,
1400 .set_align_stack = .un_node,
1401 .set_cold = .un_node,
1402 .set_float_mode = .un_node,
1403 .set_runtime_safety = .un_node,
1404 .sqrt = .un_node,
1405 .sin = .un_node,
1406 .cos = .un_node,
1407 .exp = .un_node,
1408 .exp2 = .un_node,
1409 .log = .un_node,
1410 .log2 = .un_node,
1411 .log10 = .un_node,
1412 .fabs = .un_node,
1413 .floor = .un_node,
1414 .ceil = .un_node,
1415 .trunc = .un_node,
1416 .round = .un_node,
1417 .tag_name = .un_node,
1418 .reify = .un_node,
1419 .type_name = .un_node,
1420 .frame_type = .un_node,
1421 .frame_size = .un_node,
1422
1423 .float_to_int = .pl_node,
1424 .int_to_float = .pl_node,
1425 .int_to_ptr = .pl_node,
1426 .int_to_enum = .pl_node,
1427 .float_cast = .pl_node,
1428 .int_cast = .pl_node,
1429 .err_set_cast = .pl_node,
1430 .ptr_cast = .pl_node,
1431 .truncate = .pl_node,
1432 .align_cast = .pl_node,
1433
1434 .has_decl = .pl_node,
1435 .has_field = .pl_node,
1436
1437 .clz = .un_node,
1438 .ctz = .un_node,
1439 .pop_count = .un_node,
1440 .byte_swap = .un_node,
1441 .bit_reverse = .un_node,
1442
1443 .div_exact = .pl_node,
1444 .div_floor = .pl_node,
1445 .div_trunc = .pl_node,
1446 .mod = .pl_node,
1447 .rem = .pl_node,
1448
1449 .shl = .pl_node,
1450 .shl_exact = .pl_node,
1451 .shr = .pl_node,
1452 .shr_exact = .pl_node,
1453
1454 .bit_offset_of = .pl_node,
1455 .byte_offset_of = .pl_node,
1456 .cmpxchg_strong = .pl_node,
1457 .cmpxchg_weak = .pl_node,
1458 .splat = .pl_node,
1459 .reduce = .pl_node,
1460 .shuffle = .pl_node,
1461 .atomic_load = .pl_node,
1462 .atomic_rmw = .pl_node,
1463 .atomic_store = .pl_node,
1464 .mul_add = .pl_node,
1465 .builtin_call = .pl_node,
1466 .field_ptr_type = .bin,
1467 .field_parent_ptr = .pl_node,
1468 .memcpy = .pl_node,
1469 .memset = .pl_node,
1470 .builtin_async_call = .pl_node,
1471 .c_import = .pl_node,
1472
1473 .alloc = .un_node,
1474 .alloc_mut = .un_node,
1475 .alloc_comptime = .un_node,
1476 .alloc_inferred = .node,
1477 .alloc_inferred_mut = .node,
1478 .alloc_inferred_comptime = .node,
1479 .resolve_inferred_alloc = .un_node,
1480
1481 .@"resume" = .un_node,
1482 .@"await" = .un_node,
1483 .await_nosuspend = .un_node,
1484
1485 .extended = .extended,
1486 });
1487 };
1205 };1488 };
12061489
1207 /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.1490 /// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
...@@ -1842,6 +2125,33 @@ pub const Inst = struct {...@@ -1842,6 +2125,33 @@ pub const Inst = struct {
1842 assert(@sizeOf(Data) == 8);2125 assert(@sizeOf(Data) == 8);
1843 }2126 }
1844 }2127 }
2128
2129 /// TODO this has to be kept in sync with `Data` which we want to be an untagged
2130 /// union. There is some kind of language awkwardness here and it has to do with
2131 /// deserializing an untagged union (in this case `Data`) from a file, and trying
2132 /// to preserve the hidden safety field.
2133 pub const FieldEnum = enum {
2134 extended,
2135 un_node,
2136 un_tok,
2137 pl_node,
2138 bin,
2139 str,
2140 str_tok,
2141 tok,
2142 node,
2143 int,
2144 float,
2145 array_type_sentinel,
2146 ptr_type_simple,
2147 ptr_type,
2148 int_type,
2149 bool_br,
2150 param_type,
2151 @"unreachable",
2152 @"break",
2153 switch_capture,
2154 };
1845 };2155 };
18462156
1847 /// Trailing:2157 /// Trailing:
src/main.zig+1-1
...@@ -3606,7 +3606,7 @@ pub fn cmdAstgen(...@@ -3606,7 +3606,7 @@ pub fn cmdAstgen(
36063606
3607 if (file.zir.hasCompileErrors()) {3607 if (file.zir.hasCompileErrors()) {
3608 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);3608 var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
3609 try Compilation.AllErrors.addZir(arena, &errors, &file, source);3609 try Compilation.AllErrors.addZir(arena, &errors, &file);
3610 const ttyconf = std.debug.detectTTYConfig();3610 const ttyconf = std.debug.detectTTYConfig();
3611 for (errors.items) |full_err_msg| {3611 for (errors.items) |full_err_msg| {
3612 full_err_msg.renderToStdErr(ttyconf);3612 full_err_msg.renderToStdErr(ttyconf);