From d70853ba39cb1694d91a763ea8492f3aed1494a7 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Fri, 5 May 2023 03:04:44 -0400 Subject: [PATCH] main: add debug dump-zir command --- src/Module.zig | 143 ++++++++++++++++++++++++++----------------------- src/main.zig | 62 +++++++++++++++++++++ 2 files changed, 138 insertions(+), 67 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index 93e247f7a3..538c716bc3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3671,74 +3671,13 @@ pub fn astGenFile(mod: *Module, file: *File) !void { file.sub_file_path, header.instructions_len, }); - var instructions: std.MultiArrayList(Zir.Inst) = .{}; - defer instructions.deinit(gpa); - - try instructions.setCapacity(gpa, header.instructions_len); - instructions.len = header.instructions_len; - - var zir: Zir = .{ - .instructions = instructions.toOwnedSlice(), - .string_bytes = &.{}, - .extra = &.{}, + file.zir = loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) { + error.UnexpectedFileSize => { + log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}); + break :update; + }, + else => |e| return e, }; - 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}); - break :update; - } - if (data_has_safety_tag) { - const tags = zir.instructions.items(.tag); - for (zir.instructions.items(.data), 0..) |*data, i| { - const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; - const as_struct = @ptrCast(*HackDataLayout, 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, @@ -3916,6 +3855,76 @@ pub fn astGenFile(mod: *Module, file: *File) !void { } } +pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir { + return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file); +} + +fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir { + var instructions: std.MultiArrayList(Zir.Inst) = .{}; + errdefer instructions.deinit(gpa); + + try instructions.setCapacity(gpa, header.instructions_len); + instructions.len = header.instructions_len; + + var zir: Zir = .{ + .instructions = instructions.toOwnedSlice(), + .string_bytes = &.{}, + .extra = &.{}, + }; + errdefer 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) return error.UnexpectedFileSize; + if (data_has_safety_tag) { + const tags = zir.instructions.items(.tag); + for (zir.instructions.items(.data), 0..) |*data, i| { + const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])]; + const as_struct = @ptrCast(*HackDataLayout, data); + as_struct.* = .{ + .safety_tag = @enumToInt(union_tag), + .data = safety_buffer[i], + }; + } + } + + return zir; +} + /// Patch ups: /// * Struct.zir_index /// * Decl.zir_index diff --git a/src/main.zig b/src/main.zig index 45b0cf30b8..a680a5d89e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -122,6 +122,7 @@ const debug_usage = normal_usage ++ \\Debug Commands: \\ \\ changelist Compute mappings from old ZIR to new ZIR + \\ dump-zir Dump a file containing cached ZIR \\ ; @@ -326,6 +327,8 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi return cmdAstCheck(gpa, arena, cmd_args); } else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) { return cmdChangelist(gpa, arena, cmd_args); + } else if (debug_extensions_enabled and mem.eql(u8, cmd, "dump-zir")) { + return cmdDumpZir(gpa, arena, cmd_args); } else { std.log.info("{s}", .{usage}); fatal("unknown command: {s}", .{args[1]}); @@ -5579,6 +5582,65 @@ pub fn cmdAstCheck( return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut()); } +/// This is only enabled for debug builds. +pub fn cmdDumpZir( + gpa: Allocator, + arena: Allocator, + args: []const []const u8, +) !void { + _ = arena; + const Zir = @import("Zir.zig"); + + const cache_file = args[0]; + + var f = fs.cwd().openFile(cache_file, .{}) catch |err| { + fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) }); + }; + defer f.close(); + + var file: Module.File = .{ + .status = .never_loaded, + .source_loaded = false, + .tree_loaded = false, + .zir_loaded = true, + .sub_file_path = undefined, + .source = undefined, + .stat = undefined, + .tree = undefined, + .zir = try Module.loadZirCache(gpa, f), + .pkg = undefined, + .root_decl = .none, + }; + + { + const instruction_bytes = file.zir.instructions.len * + // Here we don't use @sizeOf(Zir.Inst.Data) because it would include + // the debug safety tag but we want to measure release size. + (@sizeOf(Zir.Inst.Tag) + 8); + const extra_bytes = file.zir.extra.len * @sizeOf(u32); + const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes + + file.zir.string_bytes.len * @sizeOf(u8); + const stdout = io.getStdOut(); + const fmtIntSizeBin = std.fmt.fmtIntSizeBin; + // zig fmt: off + try stdout.writer().print( + \\# Total ZIR bytes: {} + \\# Instructions: {d} ({}) + \\# String Table Bytes: {} + \\# Extra Data Items: {d} ({}) + \\ + , .{ + fmtIntSizeBin(total_bytes), + file.zir.instructions.len, fmtIntSizeBin(instruction_bytes), + fmtIntSizeBin(file.zir.string_bytes.len), + file.zir.extra.len, fmtIntSizeBin(extra_bytes), + }); + // zig fmt: on + } + + return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut()); +} + /// This is only enabled for debug builds. pub fn cmdChangelist( gpa: Allocator,