Commit 015cd79f89
Changed files (6)
lib/std/fs/file.zig
@@ -482,7 +482,7 @@ pub const File = struct {
/// order to handle partial reads from the underlying OS layer.
/// See https://github.com/ziglang/zig/issues/7699
pub fn readvAll(self: File, iovecs: []os.iovec) ReadError!usize {
- if (iovecs.len == 0) return;
+ if (iovecs.len == 0) return 0;
var i: usize = 0;
var off: usize = 0;
src/Compilation.zig
@@ -434,10 +434,10 @@ pub const AllErrors = struct {
arena: *Allocator,
errors: *std.ArrayList(Message),
file: *Module.Scope.File,
- source: []const u8,
) !void {
assert(file.zir_loaded);
assert(file.tree_loaded);
+ assert(file.source_loaded);
const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
assert(payload_index != 0);
@@ -466,7 +466,7 @@ pub const AllErrors = struct {
}
break :blk token_starts[note_item.data.token] + note_item.data.byte_offset;
};
- const loc = std.zig.findLineColumn(source, byte_offset);
+ const loc = std.zig.findLineColumn(file.source, byte_offset);
note.* = .{
.src = .{
@@ -492,7 +492,7 @@ pub const AllErrors = struct {
}
break :blk token_starts[item.data.token] + item.data.byte_offset;
};
- const loc = std.zig.findLineColumn(source, byte_offset);
+ const loc = std.zig.findLineColumn(file.source, byte_offset);
try errors.append(.{
.src = .{
@@ -1709,9 +1709,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
if (entry.value) |msg| {
try AllErrors.add(module, &arena, &errors, msg.*);
} else {
- // Must be ZIR errors.
- const source = try entry.key.getSource(module.gpa);
- try AllErrors.addZir(&arena.allocator, &errors, entry.key, source);
+ // Must be ZIR errors. In order for ZIR errors to exist, the parsing
+ // must have completed successfully.
+ const tree = try entry.key.getTree(module.gpa);
+ assert(tree.errors.len == 0);
+ try AllErrors.addZir(&arena.allocator, &errors, entry.key);
}
}
for (module.failed_decls.items()) |entry| {
src/main.zig
@@ -3606,7 +3606,7 @@ pub fn cmdAstgen(
if (file.zir.hasCompileErrors()) {
var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena);
- try Compilation.AllErrors.addZir(arena, &errors, &file, source);
+ try Compilation.AllErrors.addZir(arena, &errors, &file);
const ttyconf = std.debug.detectTTYConfig();
for (errors.items) |full_err_msg| {
full_err_msg.renderToStdErr(ttyconf);
src/Module.zig
@@ -15,6 +15,7 @@ const ast = std.zig.ast;
const Module = @This();
const Compilation = @import("Compilation.zig");
+const Cache = @import("Cache.zig");
const Value = @import("value.zig").Value;
const Type = @import("type.zig").Type;
const TypedValue = @import("TypedValue.zig");
@@ -771,6 +772,15 @@ pub const Scope = struct {
return source;
}
+ pub fn getTree(file: *File, gpa: *Allocator) !*const ast.Tree {
+ if (file.tree_loaded) return &file.tree;
+
+ const source = try file.getSource(gpa);
+ file.tree = try std.zig.parse(gpa, source);
+ file.tree_loaded = true;
+ return &file.tree;
+ }
+
pub fn destroy(file: *File, gpa: *Allocator) void {
file.deinit(gpa);
gpa.destroy(file);
@@ -2676,6 +2686,20 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
gpa.free(export_list);
}
+const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
+// TODO This is taking advantage of matching stage1 debug union layout.
+// We need a better language feature for initializing a union with
+// a runtime known tag.
+const Stage1DataLayout = extern struct {
+ safety_tag: u8,
+ data: [8]u8 align(8),
+};
+comptime {
+ if (data_has_safety_tag) {
+ assert(@sizeOf(Stage1DataLayout) == @sizeOf(Zir.Inst.Data));
+ }
+}
+
pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node) !void {
const tracy = trace(@src());
defer tracy.end();
@@ -2684,15 +2708,166 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
const gpa = mod.gpa;
// In any case we need to examine the stat of the file to determine the course of action.
- var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
- defer f.close();
+ var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});
+ defer source_file.close();
- const stat = try f.stat();
+ const stat = try source_file.stat();
+
+ const want_local_cache = file.pkg == mod.root_pkg;
+ const digest = hash: {
+ var path_hash: Cache.HashHelper = .{};
+ if (!want_local_cache) {
+ path_hash.addOptionalBytes(file.pkg.root_src_directory.path);
+ }
+ path_hash.addBytes(file.sub_file_path);
+ break :hash path_hash.final();
+ };
+ const cache_directory = if (want_local_cache)
+ comp.local_cache_directory
+ else
+ comp.global_cache_directory;
+
+ var cache_file: ?std.fs.File = null;
+ defer if (cache_file) |f| f.close();
+
+ // TODO do this before spawning astgen workers
+ var zir_dir = try cache_directory.handle.makeOpenPath("z", .{});
+ defer zir_dir.close();
// Determine whether we need to reload the file from disk and redo parsing and AstGen.
switch (file.status) {
- .never_loaded, .retryable_failure => {
- log.debug("first-time AstGen: {s}", .{file.sub_file_path});
+ .never_loaded, .retryable_failure => cached: {
+ // First, load the cached ZIR code, if any.
+ log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
+ file.sub_file_path, want_local_cache, &digest,
+ });
+
+ // We ask for a lock in order to coordinate with other zig processes.
+ // If another process is already working on this file, we will get the cached
+ // version. Likewise if we're working on AstGen and another process asks for
+ // the cached file, they'll get it.
+ cache_file = zir_dir.openFile(&digest, .{ .lock = .Shared }) catch |err| switch (err) {
+ error.PathAlreadyExists => unreachable, // opening for reading
+ error.NoSpaceLeft => unreachable, // opening for reading
+ error.NotDir => unreachable, // no dir components
+ error.InvalidUtf8 => unreachable, // it's a hex encoded name
+ error.BadPathName => unreachable, // it's a hex encoded name
+ error.NameTooLong => unreachable, // it's a fixed size name
+ error.PipeBusy => unreachable, // it's not a pipe
+ error.WouldBlock => unreachable, // not asking for non-blocking I/O
+
+ error.SymLinkLoop,
+ error.FileNotFound,
+ error.Unexpected,
+ => break :cached,
+
+ else => |e| return e, // Retryable errors are handled at callsite.
+ };
+
+ // First we read the header to determine the lengths of arrays.
+ const header = cache_file.?.reader().readStruct(Zir.Header) catch |err| switch (err) {
+ // This can happen if Zig bails out of this function between creating
+ // the cached file and writing it.
+ error.EndOfStream => break :cached,
+ else => |e| return e,
+ };
+ const unchanged_metadata =
+ stat.size == header.stat_size and
+ stat.mtime == header.stat_mtime and
+ stat.inode == header.stat_inode;
+
+ if (!unchanged_metadata) {
+ log.debug("AstGen cache stale: {s}", .{file.sub_file_path});
+ break :cached;
+ }
+ log.debug("AstGen cache hit: {s}", .{file.sub_file_path});
+
+ var instructions: std.MultiArrayList(Zir.Inst) = .{};
+ defer instructions.deinit(gpa);
+
+ try instructions.resize(gpa, header.instructions_len);
+
+ var zir: Zir = .{
+ .instructions = instructions.toOwnedSlice(),
+ .string_bytes = &.{},
+ .extra = &.{},
+ };
+ var keep_zir = false;
+ defer if (!keep_zir) zir.deinit(gpa);
+
+ zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
+ zir.extra = try gpa.alloc(u32, header.extra_len);
+
+ const safety_buffer = if (data_has_safety_tag)
+ try gpa.alloc([8]u8, header.instructions_len)
+ else
+ undefined;
+ defer if (data_has_safety_tag) gpa.free(safety_buffer);
+
+ const data_ptr = if (data_has_safety_tag)
+ @ptrCast([*]u8, safety_buffer.ptr)
+ else
+ @ptrCast([*]u8, zir.instructions.items(.data).ptr);
+
+ var iovecs = [_]std.os.iovec{
+ .{
+ .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr),
+ .iov_len = header.instructions_len,
+ },
+ .{
+ .iov_base = data_ptr,
+ .iov_len = header.instructions_len * 8,
+ },
+ .{
+ .iov_base = zir.string_bytes.ptr,
+ .iov_len = header.string_bytes_len,
+ },
+ .{
+ .iov_base = @ptrCast([*]u8, zir.extra.ptr),
+ .iov_len = header.extra_len * 4,
+ },
+ };
+ const amt_read = try cache_file.?.readvAll(&iovecs);
+ const amt_expected = zir.instructions.len * 9 +
+ zir.string_bytes.len +
+ zir.extra.len * 4;
+ if (amt_read != amt_expected) {
+ log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
+ zir.deinit(gpa);
+ break :cached;
+ }
+ if (data_has_safety_tag) {
+ const tags = zir.instructions.items(.tag);
+ for (zir.instructions.items(.data)) |*data, i| {
+ const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])];
+ const as_struct = @ptrCast(*Stage1DataLayout, data);
+ as_struct.* = .{
+ .safety_tag = @enumToInt(union_tag),
+ .data = safety_buffer[i],
+ };
+ }
+ }
+
+ keep_zir = true;
+ file.zir = zir;
+ file.zir_loaded = true;
+ file.stat_size = header.stat_size;
+ file.stat_inode = header.stat_inode;
+ file.stat_mtime = header.stat_mtime;
+ file.status = .success;
+ log.debug("AstGen cached success: {s}", .{file.sub_file_path});
+
+ // TODO don't report compile errors until Sema @importFile
+ if (file.zir.hasCompileErrors()) {
+ {
+ const lock = comp.mutex.acquire();
+ defer lock.release();
+ try mod.failed_files.putNoClobber(gpa, file, null);
+ }
+ file.status = .astgen_failure;
+ return error.AnalysisFail;
+ }
+ return;
},
.parse_failure, .astgen_failure, .success => {
const unchanged_metadata =
@@ -2708,6 +2883,29 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
log.debug("metadata changed: {s}", .{file.sub_file_path});
},
}
+ if (cache_file) |f| {
+ f.close();
+ cache_file = null;
+ }
+ cache_file = zir_dir.createFile(&digest, .{ .lock = .Exclusive }) catch |err| switch (err) {
+ error.NotDir => unreachable, // no dir components
+ error.InvalidUtf8 => unreachable, // it's a hex encoded name
+ error.BadPathName => unreachable, // it's a hex encoded name
+ error.NameTooLong => unreachable, // it's a fixed size name
+ error.PipeBusy => unreachable, // it's not a pipe
+ error.WouldBlock => unreachable, // not asking for non-blocking I/O
+ error.FileNotFound => unreachable, // no dir components
+
+ else => |e| {
+ const pkg_path = file.pkg.root_src_directory.path orelse ".";
+ const cache_path = cache_directory.path orelse ".";
+ log.warn("unable to save cached ZIR code for {s}/{s} to {s}/z/{s}: {s}", .{
+ pkg_path, file.sub_file_path, cache_path, &digest, @errorName(e),
+ });
+ return;
+ },
+ };
+
// Clear compile error for this file.
switch (file.status) {
.success, .retryable_failure => {},
@@ -2726,7 +2924,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
const source = try gpa.allocSentinel(u8, stat.size, 0);
defer if (!file.source_loaded) gpa.free(source);
- const amt = try f.readAll(source);
+ const amt = try source_file.readAll(source);
if (amt != stat.size)
return error.UnexpectedEndOfFile;
@@ -2770,7 +2968,67 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
file.zir = try AstGen.generate(gpa, file);
file.zir_loaded = true;
+ file.status = .success;
+ log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
+
+ const safety_buffer = if (data_has_safety_tag)
+ try gpa.alloc([8]u8, file.zir.instructions.len)
+ else
+ undefined;
+ defer if (data_has_safety_tag) gpa.free(safety_buffer);
+ const data_ptr = if (data_has_safety_tag)
+ @ptrCast([*]const u8, safety_buffer.ptr)
+ else
+ @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr);
+ if (data_has_safety_tag) {
+ // The `Data` union has a safety tag but in the file format we store it without.
+ const tags = file.zir.instructions.items(.tag);
+ for (file.zir.instructions.items(.data)) |*data, i| {
+ const as_struct = @ptrCast(*const Stage1DataLayout, data);
+ safety_buffer[i] = as_struct.data;
+ }
+ }
+
+ const header: Zir.Header = .{
+ .instructions_len = @intCast(u32, file.zir.instructions.len),
+ .string_bytes_len = @intCast(u32, file.zir.string_bytes.len),
+ .extra_len = @intCast(u32, file.zir.extra.len),
+
+ .stat_size = stat.size,
+ .stat_inode = stat.inode,
+ .stat_mtime = stat.mtime,
+ };
+ var iovecs = [_]std.os.iovec_const{
+ .{
+ .iov_base = @ptrCast([*]const u8, &header),
+ .iov_len = @sizeOf(Zir.Header),
+ },
+ .{
+ .iov_base = @ptrCast([*]const u8, file.zir.instructions.items(.tag).ptr),
+ .iov_len = file.zir.instructions.len,
+ },
+ .{
+ .iov_base = data_ptr,
+ .iov_len = file.zir.instructions.len * 8,
+ },
+ .{
+ .iov_base = file.zir.string_bytes.ptr,
+ .iov_len = file.zir.string_bytes.len,
+ },
+ .{
+ .iov_base = @ptrCast([*]const u8, file.zir.extra.ptr),
+ .iov_len = file.zir.extra.len * 4,
+ },
+ };
+ cache_file.?.writevAll(&iovecs) catch |err| {
+ const pkg_path = file.pkg.root_src_directory.path orelse ".";
+ const cache_path = cache_directory.path orelse ".";
+ log.warn("unable to write cached ZIR code for {s}/{s} to {s}/z/{s}: {s}", .{
+ pkg_path, file.sub_file_path, cache_path, &digest, @errorName(err),
+ });
+ };
+ // TODO don't report compile errors until Sema @importFile
if (file.zir.hasCompileErrors()) {
{
const lock = comp.mutex.acquire();
@@ -2780,9 +3038,6 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
file.status = .astgen_failure;
return error.AnalysisFail;
}
-
- log.debug("AstGen success: {s}", .{file.sub_file_path});
- file.status = .success;
}
pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
src/Zir.zig
@@ -37,6 +37,17 @@ string_bytes: []u8,
/// The first few indexes are reserved. See `ExtraIndex` for the values.
extra: []u32,
+/// The data stored at byte offset 0 when ZIR is stored in a file.
+pub const Header = extern struct {
+ instructions_len: u32,
+ string_bytes_len: u32,
+ extra_len: u32,
+
+ stat_size: u64,
+ stat_inode: std.fs.File.INode,
+ stat_mtime: i128,
+};
+
pub const ExtraIndex = enum(u32) {
/// Ref. The main struct decl for this file.
main_struct,
@@ -139,6 +150,7 @@ pub const Inst = struct {
data: Data,
/// These names are used directly as the instruction names in the text format.
+ /// See `data_field_map` for a list of which `Data` fields are used by each `Tag`.
pub const Tag = enum(u8) {
/// Arithmetic addition, asserts no integer overflow.
/// Uses the `pl_node` union field. Payload is `Bin`.
@@ -932,6 +944,7 @@ pub const Inst = struct {
/// Uses the `un_node` field. The AST node is the var decl.
resolve_inferred_alloc,
+ /// Implements `resume` syntax. Uses `un_node` field.
@"resume",
@"await",
await_nosuspend,
@@ -1202,6 +1215,276 @@ pub const Inst = struct {
=> true,
};
}
+
+ /// Used by debug safety-checking code.
+ pub const data_tags = list: {
+ @setEvalBranchQuota(2000);
+ break :list std.enums.directEnumArray(Tag, Data.FieldEnum, 0, .{
+ .add = .pl_node,
+ .addwrap = .pl_node,
+ .array_cat = .pl_node,
+ .array_mul = .pl_node,
+ .array_type = .bin,
+ .array_type_sentinel = .array_type_sentinel,
+ .vector_type = .pl_node,
+ .elem_type = .un_node,
+ .indexable_ptr_len = .un_node,
+ .anyframe_type = .un_node,
+ .as = .bin,
+ .as_node = .pl_node,
+ .bit_and = .pl_node,
+ .bitcast = .pl_node,
+ .bitcast_result_ptr = .pl_node,
+ .bit_not = .un_node,
+ .bit_or = .pl_node,
+ .block = .pl_node,
+ .block_inline = .pl_node,
+ .block_inline_var = .pl_node,
+ .suspend_block = .pl_node,
+ .bool_and = .pl_node,
+ .bool_not = .un_node,
+ .bool_or = .pl_node,
+ .bool_br_and = .bool_br,
+ .bool_br_or = .bool_br,
+ .@"break" = .@"break",
+ .break_inline = .@"break",
+ .breakpoint = .node,
+ .call = .pl_node,
+ .call_chkused = .pl_node,
+ .call_compile_time = .pl_node,
+ .call_nosuspend = .pl_node,
+ .call_async = .pl_node,
+ .cmp_lt = .pl_node,
+ .cmp_lte = .pl_node,
+ .cmp_eq = .pl_node,
+ .cmp_gte = .pl_node,
+ .cmp_gt = .pl_node,
+ .cmp_neq = .pl_node,
+ .coerce_result_ptr = .bin,
+ .condbr = .pl_node,
+ .condbr_inline = .pl_node,
+ .struct_decl = .pl_node,
+ .struct_decl_packed = .pl_node,
+ .struct_decl_extern = .pl_node,
+ .union_decl = .pl_node,
+ .union_decl_packed = .pl_node,
+ .union_decl_extern = .pl_node,
+ .enum_decl = .pl_node,
+ .enum_decl_nonexhaustive = .pl_node,
+ .opaque_decl = .pl_node,
+ .error_set_decl = .pl_node,
+ .dbg_stmt_node = .node,
+ .decl_ref = .str_tok,
+ .decl_val = .str_tok,
+ .load = .un_node,
+ .div = .pl_node,
+ .elem_ptr = .bin,
+ .elem_ptr_node = .pl_node,
+ .elem_val = .bin,
+ .elem_val_node = .pl_node,
+ .ensure_result_used = .un_node,
+ .ensure_result_non_error = .un_node,
+ .error_union_type = .pl_node,
+ .error_value = .str_tok,
+ .@"export" = .pl_node,
+ .field_ptr = .pl_node,
+ .field_val = .pl_node,
+ .field_ptr_named = .pl_node,
+ .field_val_named = .pl_node,
+ .func = .pl_node,
+ .func_inferred = .pl_node,
+ .import = .str_tok,
+ .int = .int,
+ .int_big = .str,
+ .float = .float,
+ .float128 = .pl_node,
+ .int_type = .int_type,
+ .is_non_null = .un_node,
+ .is_null = .un_node,
+ .is_non_null_ptr = .un_node,
+ .is_null_ptr = .un_node,
+ .is_err = .un_node,
+ .is_err_ptr = .un_node,
+ .loop = .pl_node,
+ .repeat = .node,
+ .repeat_inline = .node,
+ .merge_error_sets = .pl_node,
+ .mod_rem = .pl_node,
+ .mul = .pl_node,
+ .mulwrap = .pl_node,
+ .param_type = .param_type,
+ .ref = .un_tok,
+ .ret_node = .un_node,
+ .ret_coerce = .un_tok,
+ .ptr_type_simple = .ptr_type_simple,
+ .ptr_type = .ptr_type,
+ .slice_start = .pl_node,
+ .slice_end = .pl_node,
+ .slice_sentinel = .pl_node,
+ .store = .bin,
+ .store_node = .pl_node,
+ .store_to_block_ptr = .bin,
+ .store_to_inferred_ptr = .bin,
+ .str = .str,
+ .sub = .pl_node,
+ .subwrap = .pl_node,
+ .negate = .un_node,
+ .negate_wrap = .un_node,
+ .typeof = .un_tok,
+ .typeof_elem = .un_node,
+ .typeof_log2_int_type = .un_node,
+ .log2_int_type = .un_node,
+ .@"unreachable" = .@"unreachable",
+ .xor = .pl_node,
+ .optional_type = .un_node,
+ .optional_payload_safe = .un_node,
+ .optional_payload_unsafe = .un_node,
+ .optional_payload_safe_ptr = .un_node,
+ .optional_payload_unsafe_ptr = .un_node,
+ .err_union_payload_safe = .un_node,
+ .err_union_payload_unsafe = .un_node,
+ .err_union_payload_safe_ptr = .un_node,
+ .err_union_payload_unsafe_ptr = .un_node,
+ .err_union_code = .un_node,
+ .err_union_code_ptr = .un_node,
+ .ensure_err_payload_void = .un_tok,
+ .enum_literal = .str_tok,
+ .switch_block = .pl_node,
+ .switch_block_multi = .pl_node,
+ .switch_block_else = .pl_node,
+ .switch_block_else_multi = .pl_node,
+ .switch_block_under = .pl_node,
+ .switch_block_under_multi = .pl_node,
+ .switch_block_ref = .pl_node,
+ .switch_block_ref_multi = .pl_node,
+ .switch_block_ref_else = .pl_node,
+ .switch_block_ref_else_multi = .pl_node,
+ .switch_block_ref_under = .pl_node,
+ .switch_block_ref_under_multi = .pl_node,
+ .switch_capture = .switch_capture,
+ .switch_capture_ref = .switch_capture,
+ .switch_capture_multi = .switch_capture,
+ .switch_capture_multi_ref = .switch_capture,
+ .switch_capture_else = .switch_capture,
+ .switch_capture_else_ref = .switch_capture,
+ .validate_struct_init_ptr = .pl_node,
+ .validate_array_init_ptr = .pl_node,
+ .struct_init_empty = .un_node,
+ .field_type = .pl_node,
+ .field_type_ref = .pl_node,
+ .struct_init = .pl_node,
+ .struct_init_ref = .pl_node,
+ .struct_init_anon = .pl_node,
+ .struct_init_anon_ref = .pl_node,
+ .array_init = .pl_node,
+ .array_init_anon = .pl_node,
+ .array_init_ref = .pl_node,
+ .array_init_anon_ref = .pl_node,
+ .union_init_ptr = .pl_node,
+ .type_info = .un_node,
+ .size_of = .un_node,
+ .bit_size_of = .un_node,
+ .fence = .node,
+
+ .ptr_to_int = .un_node,
+ .error_to_int = .un_node,
+ .int_to_error = .un_node,
+ .compile_error = .un_node,
+ .set_eval_branch_quota = .un_node,
+ .enum_to_int = .un_node,
+ .align_of = .un_node,
+ .bool_to_int = .un_node,
+ .embed_file = .un_node,
+ .error_name = .un_node,
+ .panic = .un_node,
+ .set_align_stack = .un_node,
+ .set_cold = .un_node,
+ .set_float_mode = .un_node,
+ .set_runtime_safety = .un_node,
+ .sqrt = .un_node,
+ .sin = .un_node,
+ .cos = .un_node,
+ .exp = .un_node,
+ .exp2 = .un_node,
+ .log = .un_node,
+ .log2 = .un_node,
+ .log10 = .un_node,
+ .fabs = .un_node,
+ .floor = .un_node,
+ .ceil = .un_node,
+ .trunc = .un_node,
+ .round = .un_node,
+ .tag_name = .un_node,
+ .reify = .un_node,
+ .type_name = .un_node,
+ .frame_type = .un_node,
+ .frame_size = .un_node,
+
+ .float_to_int = .pl_node,
+ .int_to_float = .pl_node,
+ .int_to_ptr = .pl_node,
+ .int_to_enum = .pl_node,
+ .float_cast = .pl_node,
+ .int_cast = .pl_node,
+ .err_set_cast = .pl_node,
+ .ptr_cast = .pl_node,
+ .truncate = .pl_node,
+ .align_cast = .pl_node,
+
+ .has_decl = .pl_node,
+ .has_field = .pl_node,
+
+ .clz = .un_node,
+ .ctz = .un_node,
+ .pop_count = .un_node,
+ .byte_swap = .un_node,
+ .bit_reverse = .un_node,
+
+ .div_exact = .pl_node,
+ .div_floor = .pl_node,
+ .div_trunc = .pl_node,
+ .mod = .pl_node,
+ .rem = .pl_node,
+
+ .shl = .pl_node,
+ .shl_exact = .pl_node,
+ .shr = .pl_node,
+ .shr_exact = .pl_node,
+
+ .bit_offset_of = .pl_node,
+ .byte_offset_of = .pl_node,
+ .cmpxchg_strong = .pl_node,
+ .cmpxchg_weak = .pl_node,
+ .splat = .pl_node,
+ .reduce = .pl_node,
+ .shuffle = .pl_node,
+ .atomic_load = .pl_node,
+ .atomic_rmw = .pl_node,
+ .atomic_store = .pl_node,
+ .mul_add = .pl_node,
+ .builtin_call = .pl_node,
+ .field_ptr_type = .bin,
+ .field_parent_ptr = .pl_node,
+ .memcpy = .pl_node,
+ .memset = .pl_node,
+ .builtin_async_call = .pl_node,
+ .c_import = .pl_node,
+
+ .alloc = .un_node,
+ .alloc_mut = .un_node,
+ .alloc_comptime = .un_node,
+ .alloc_inferred = .node,
+ .alloc_inferred_mut = .node,
+ .alloc_inferred_comptime = .node,
+ .resolve_inferred_alloc = .un_node,
+
+ .@"resume" = .un_node,
+ .@"await" = .un_node,
+ .await_nosuspend = .un_node,
+
+ .extended = .extended,
+ });
+ };
};
/// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
@@ -1842,6 +2125,33 @@ pub const Inst = struct {
assert(@sizeOf(Data) == 8);
}
}
+
+ /// TODO this has to be kept in sync with `Data` which we want to be an untagged
+ /// union. There is some kind of language awkwardness here and it has to do with
+ /// deserializing an untagged union (in this case `Data`) from a file, and trying
+ /// to preserve the hidden safety field.
+ pub const FieldEnum = enum {
+ extended,
+ un_node,
+ un_tok,
+ pl_node,
+ bin,
+ str,
+ str_tok,
+ tok,
+ node,
+ int,
+ float,
+ array_type_sentinel,
+ ptr_type_simple,
+ ptr_type,
+ int_type,
+ bool_br,
+ param_type,
+ @"unreachable",
+ @"break",
+ switch_capture,
+ };
};
/// Trailing:
BRANCH_TODO
@@ -1,15 +1,10 @@
- * nested function decl: how to refer to params?
- * look for cached zir code
- * save zir code to cache
* keep track of file dependencies/dependants
* unload files from memory when a dependency is dropped
- * implement zir error notes
* implement the new AstGen compile errors
* get rid of failed_root_src_file
* get rid of Scope.DeclRef
- * get rid of optional_type_from_ptr_elem
* handle decl collision with usingnamespace
* the decl doing the looking up needs to create a decl dependency
on each usingnamespace decl
@@ -38,6 +33,9 @@
AstGen can report more than one compile error.
* AstGen: add result location pointers to function calls
+ * nested function decl: how to refer to params?
+
+ * detect when to put cached ZIR into the local cache instead of the global one
const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
pkg.namespace_hash