authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-05-05 03:04:44-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-05 11:00:44-07:00
logd70853ba39cb1694d91a763ea8492f3aed1494a7
tree04aaf9ee98d152aa5423c8dc6c32da197d5e214d
parenta11113097730693fb915114cec79df9cb4adcc93

main: add debug dump-zir command


2 files changed, 137 insertions(+), 66 deletions(-)

src/Module.zig+75-66
...@@ -3671,74 +3671,13 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3671,74 +3671,13 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3671 file.sub_file_path, header.instructions_len,3671 file.sub_file_path, header.instructions_len,
3672 });3672 });
36733673
3674 var instructions: std.MultiArrayList(Zir.Inst) = .{};3674 file.zir = loadZirCacheBody(gpa, header, cache_file) catch |err| switch (err) {
3675 defer instructions.deinit(gpa);3675 error.UnexpectedFileSize => {
36763676 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
3677 try instructions.setCapacity(gpa, header.instructions_len);3677 break :update;
3678 instructions.len = header.instructions_len;
3679
3680 var zir: Zir = .{
3681 .instructions = instructions.toOwnedSlice(),
3682 .string_bytes = &.{},
3683 .extra = &.{},
3684 };
3685 var keep_zir = false;
3686 defer if (!keep_zir) zir.deinit(gpa);
3687
3688 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
3689 zir.extra = try gpa.alloc(u32, header.extra_len);
3690
3691 const safety_buffer = if (data_has_safety_tag)
3692 try gpa.alloc([8]u8, header.instructions_len)
3693 else
3694 undefined;
3695 defer if (data_has_safety_tag) gpa.free(safety_buffer);
3696
3697 const data_ptr = if (data_has_safety_tag)
3698 @ptrCast([*]u8, safety_buffer.ptr)
3699 else
3700 @ptrCast([*]u8, zir.instructions.items(.data).ptr);
3701
3702 var iovecs = [_]std.os.iovec{
3703 .{
3704 .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr),
3705 .iov_len = header.instructions_len,
3706 },
3707 .{
3708 .iov_base = data_ptr,
3709 .iov_len = header.instructions_len * 8,
3710 },
3711 .{
3712 .iov_base = zir.string_bytes.ptr,
3713 .iov_len = header.string_bytes_len,
3714 },
3715 .{
3716 .iov_base = @ptrCast([*]u8, zir.extra.ptr),
3717 .iov_len = header.extra_len * 4,
3718 },3678 },
3679 else => |e| return e,
3719 };3680 };
3720 const amt_read = try cache_file.readvAll(&iovecs);
3721 const amt_expected = zir.instructions.len * 9 +
3722 zir.string_bytes.len +
3723 zir.extra.len * 4;
3724 if (amt_read != amt_expected) {
3725 log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path});
3726 break :update;
3727 }
3728 if (data_has_safety_tag) {
3729 const tags = zir.instructions.items(.tag);
3730 for (zir.instructions.items(.data), 0..) |*data, i| {
3731 const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])];
3732 const as_struct = @ptrCast(*HackDataLayout, data);
3733 as_struct.* = .{
3734 .safety_tag = @enumToInt(union_tag),
3735 .data = safety_buffer[i],
3736 };
3737 }
3738 }
3739
3740 keep_zir = true;
3741 file.zir = zir;
3742 file.zir_loaded = true;3681 file.zir_loaded = true;
3743 file.stat = .{3682 file.stat = .{
3744 .size = header.stat_size,3683 .size = header.stat_size,
...@@ -3916,6 +3855,76 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3916,6 +3855,76 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3916 }3855 }
3917}3856}
39183857
3858pub fn loadZirCache(gpa: Allocator, cache_file: std.fs.File) !Zir {
3859 return loadZirCacheBody(gpa, try cache_file.reader().readStruct(Zir.Header), cache_file);
3860}
3861
3862fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) !Zir {
3863 var instructions: std.MultiArrayList(Zir.Inst) = .{};
3864 errdefer instructions.deinit(gpa);
3865
3866 try instructions.setCapacity(gpa, header.instructions_len);
3867 instructions.len = header.instructions_len;
3868
3869 var zir: Zir = .{
3870 .instructions = instructions.toOwnedSlice(),
3871 .string_bytes = &.{},
3872 .extra = &.{},
3873 };
3874 errdefer zir.deinit(gpa);
3875
3876 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len);
3877 zir.extra = try gpa.alloc(u32, header.extra_len);
3878
3879 const safety_buffer = if (data_has_safety_tag)
3880 try gpa.alloc([8]u8, header.instructions_len)
3881 else
3882 undefined;
3883 defer if (data_has_safety_tag) gpa.free(safety_buffer);
3884
3885 const data_ptr = if (data_has_safety_tag)
3886 @ptrCast([*]u8, safety_buffer.ptr)
3887 else
3888 @ptrCast([*]u8, zir.instructions.items(.data).ptr);
3889
3890 var iovecs = [_]std.os.iovec{
3891 .{
3892 .iov_base = @ptrCast([*]u8, zir.instructions.items(.tag).ptr),
3893 .iov_len = header.instructions_len,
3894 },
3895 .{
3896 .iov_base = data_ptr,
3897 .iov_len = header.instructions_len * 8,
3898 },
3899 .{
3900 .iov_base = zir.string_bytes.ptr,
3901 .iov_len = header.string_bytes_len,
3902 },
3903 .{
3904 .iov_base = @ptrCast([*]u8, zir.extra.ptr),
3905 .iov_len = header.extra_len * 4,
3906 },
3907 };
3908 const amt_read = try cache_file.readvAll(&iovecs);
3909 const amt_expected = zir.instructions.len * 9 +
3910 zir.string_bytes.len +
3911 zir.extra.len * 4;
3912 if (amt_read != amt_expected) return error.UnexpectedFileSize;
3913 if (data_has_safety_tag) {
3914 const tags = zir.instructions.items(.tag);
3915 for (zir.instructions.items(.data), 0..) |*data, i| {
3916 const union_tag = Zir.Inst.Tag.data_tags[@enumToInt(tags[i])];
3917 const as_struct = @ptrCast(*HackDataLayout, data);
3918 as_struct.* = .{
3919 .safety_tag = @enumToInt(union_tag),
3920 .data = safety_buffer[i],
3921 };
3922 }
3923 }
3924
3925 return zir;
3926}
3927
3919/// Patch ups:3928/// Patch ups:
3920/// * Struct.zir_index3929/// * Struct.zir_index
3921/// * Decl.zir_index3930/// * Decl.zir_index
src/main.zig+62
...@@ -122,6 +122,7 @@ const debug_usage = normal_usage ++...@@ -122,6 +122,7 @@ const debug_usage = normal_usage ++
122 \\Debug Commands:122 \\Debug Commands:
123 \\123 \\
124 \\ changelist Compute mappings from old ZIR to new ZIR124 \\ changelist Compute mappings from old ZIR to new ZIR
125 \\ dump-zir Dump a file containing cached ZIR
125 \\126 \\
126;127;
127128
...@@ -326,6 +327,8 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -326,6 +327,8 @@ pub fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
326 return cmdAstCheck(gpa, arena, cmd_args);327 return cmdAstCheck(gpa, arena, cmd_args);
327 } else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) {328 } else if (debug_extensions_enabled and mem.eql(u8, cmd, "changelist")) {
328 return cmdChangelist(gpa, arena, cmd_args);329 return cmdChangelist(gpa, arena, cmd_args);
330 } else if (debug_extensions_enabled and mem.eql(u8, cmd, "dump-zir")) {
331 return cmdDumpZir(gpa, arena, cmd_args);
329 } else {332 } else {
330 std.log.info("{s}", .{usage});333 std.log.info("{s}", .{usage});
331 fatal("unknown command: {s}", .{args[1]});334 fatal("unknown command: {s}", .{args[1]});
...@@ -5579,6 +5582,65 @@ pub fn cmdAstCheck(...@@ -5579,6 +5582,65 @@ pub fn cmdAstCheck(
5579 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());5582 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
5580}5583}
55815584
5585/// This is only enabled for debug builds.
5586pub fn cmdDumpZir(
5587 gpa: Allocator,
5588 arena: Allocator,
5589 args: []const []const u8,
5590) !void {
5591 _ = arena;
5592 const Zir = @import("Zir.zig");
5593
5594 const cache_file = args[0];
5595
5596 var f = fs.cwd().openFile(cache_file, .{}) catch |err| {
5597 fatal("unable to open zir cache file for dumping '{s}': {s}", .{ cache_file, @errorName(err) });
5598 };
5599 defer f.close();
5600
5601 var file: Module.File = .{
5602 .status = .never_loaded,
5603 .source_loaded = false,
5604 .tree_loaded = false,
5605 .zir_loaded = true,
5606 .sub_file_path = undefined,
5607 .source = undefined,
5608 .stat = undefined,
5609 .tree = undefined,
5610 .zir = try Module.loadZirCache(gpa, f),
5611 .pkg = undefined,
5612 .root_decl = .none,
5613 };
5614
5615 {
5616 const instruction_bytes = file.zir.instructions.len *
5617 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
5618 // the debug safety tag but we want to measure release size.
5619 (@sizeOf(Zir.Inst.Tag) + 8);
5620 const extra_bytes = file.zir.extra.len * @sizeOf(u32);
5621 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
5622 file.zir.string_bytes.len * @sizeOf(u8);
5623 const stdout = io.getStdOut();
5624 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
5625 // zig fmt: off
5626 try stdout.writer().print(
5627 \\# Total ZIR bytes: {}
5628 \\# Instructions: {d} ({})
5629 \\# String Table Bytes: {}
5630 \\# Extra Data Items: {d} ({})
5631 \\
5632 , .{
5633 fmtIntSizeBin(total_bytes),
5634 file.zir.instructions.len, fmtIntSizeBin(instruction_bytes),
5635 fmtIntSizeBin(file.zir.string_bytes.len),
5636 file.zir.extra.len, fmtIntSizeBin(extra_bytes),
5637 });
5638 // zig fmt: on
5639 }
5640
5641 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
5642}
5643
5582/// This is only enabled for debug builds.5644/// This is only enabled for debug builds.
5583pub fn cmdChangelist(5645pub fn cmdChangelist(
5584 gpa: Allocator,5646 gpa: Allocator,