main: add debug dump-zir command

This commit is contained in:
Jacob Young 2023-05-05 03:04:44 -04:00 committed by Andrew Kelley
parent a111130977
commit d70853ba39
2 changed files with 138 additions and 67 deletions

View File

@ -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

View File

@ -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,