Skip to content

Commit

Permalink
frontend: TrackedInst stores FileIndex instead of path digest
Browse files Browse the repository at this point in the history
The purpose of using path digest was to reference a file in a
serializable manner. Now that there is a stable index associated with
files, it is a superior way to accomplish that goal, since removes one
layer of indirection, and makes TrackedInst 8 bytes instead of 20.

The saved Zig Compiler State file for "hello world" goes from 1.3M to
1.2M with this change.
  • Loading branch information
andrewrk authored and ryoppippi committed Jul 5, 2024
1 parent 1e7cca8 commit deae1ff
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 70 deletions.
20 changes: 10 additions & 10 deletions src/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2649,7 +2649,7 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
.import => |import| try Module.ErrorMsg.init(
gpa,
.{
.base_node_inst = try ip.trackZir(gpa, zcu.filePathDigest(import.file), .main_struct_inst),
.base_node_inst = try ip.trackZir(gpa, import.file, .main_struct_inst),
.offset = .{ .token_abs = import.token },
},
"imported from module {s}",
Expand All @@ -2658,7 +2658,7 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
.root => |pkg| try Module.ErrorMsg.init(
gpa,
.{
.base_node_inst = try ip.trackZir(gpa, zcu.filePathDigest(file_index), .main_struct_inst),
.base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),
.offset = .entire_file,
},
"root of module {s}",
Expand All @@ -2672,7 +2672,7 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
notes[num_notes] = try Module.ErrorMsg.init(
gpa,
.{
.base_node_inst = try ip.trackZir(gpa, zcu.filePathDigest(file_index), .main_struct_inst),
.base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),
.offset = .entire_file,
},
"{} more references omitted",
Expand All @@ -2684,7 +2684,7 @@ fn reportMultiModuleErrors(zcu: *Zcu) !void {
const err = try Module.ErrorMsg.create(
gpa,
.{
.base_node_inst = try ip.trackZir(gpa, zcu.filePathDigest(file_index), .main_struct_inst),
.base_node_inst = try ip.trackZir(gpa, file_index, .main_struct_inst),
.offset = .entire_file,
},
"file exists in multiple modules",
Expand Down Expand Up @@ -2786,7 +2786,7 @@ pub fn saveState(comp: *Compilation) !void {
.first_dependency_len = @intCast(ip.first_dependency.count()),
.dep_entries_len = @intCast(ip.dep_entries.items.len),
.free_dep_entries_len = @intCast(ip.free_dep_entries.items.len),
.files_len = @intCast(zcu.files.entries.len),
.files_len = @intCast(ip.files.entries.len),
},
};
addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
Expand All @@ -2811,8 +2811,8 @@ pub fn saveState(comp: *Compilation) !void {
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items));

addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(zcu.files.keys()));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(zcu.files.values()));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.keys()));
addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.files.values()));

// TODO: compilation errors
// TODO: namespaces
Expand Down Expand Up @@ -4060,7 +4060,7 @@ fn workerAstGenFile(
defer child_prog_node.end();

const zcu = comp.module.?;
zcu.astGenFile(file, path_digest, root_decl) catch |err| switch (err) {
zcu.astGenFile(file, file_index, path_digest, root_decl) catch |err| switch (err) {
error.AnalysisFail => return,
else => {
file.status = .retryable_failure;
Expand Down Expand Up @@ -4477,11 +4477,11 @@ fn reportRetryableAstGenError(

const src_loc: Module.LazySrcLoc = switch (src) {
.root => .{
.base_node_inst = try zcu.intern_pool.trackZir(gpa, zcu.filePathDigest(file_index), .main_struct_inst),
.base_node_inst = try zcu.intern_pool.trackZir(gpa, file_index, .main_struct_inst),
.offset = .entire_file,
},
.import => |info| .{
.base_node_inst = try zcu.intern_pool.trackZir(gpa, zcu.filePathDigest(info.importing_file), .main_struct_inst),
.base_node_inst = try zcu.intern_pool.trackZir(gpa, info.importing_file, .main_struct_inst),
.offset = .{ .token_abs = info.import_tok },
},
};
Expand Down
25 changes: 21 additions & 4 deletions src/InternPool.zig
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,27 @@ dep_entries: std.ArrayListUnmanaged(DepEntry) = .{},
/// garbage collection pass.
free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},

/// Elements are ordered identically to the `import_table` field of `Zcu`.
///
/// Unlike `import_table`, this data is serialized as part of incremental
/// compilation state.
///
/// Key is the hash of the path to this file, used to store
/// `InternPool.TrackedInst`.
///
/// Value is the `Decl` of the struct that represents this `File`.
files: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, OptionalDeclIndex) = .{},

pub const FileIndex = enum(u32) {
_,
};

pub const TrackedInst = extern struct {
path_digest: Cache.BinDigest,
file: FileIndex,
inst: Zir.Inst.Index,
comptime {
// The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`.
assert(@sizeOf(@This()) == Cache.bin_digest_len + @sizeOf(Zir.Inst.Index));
assert(@sizeOf(@This()) == @sizeOf(FileIndex) + @sizeOf(Zir.Inst.Index));
}
pub const Index = enum(u32) {
_,
Expand Down Expand Up @@ -126,11 +141,11 @@ pub const TrackedInst = extern struct {
pub fn trackZir(
ip: *InternPool,
gpa: Allocator,
path_digest: Cache.BinDigest,
file: FileIndex,
inst: Zir.Inst.Index,
) Allocator.Error!TrackedInst.Index {
const key: TrackedInst = .{
.path_digest = path_digest,
.file = file,
.inst = inst,
};
const gop = try ip.tracked_insts.getOrPut(gpa, key);
Expand Down Expand Up @@ -4597,6 +4612,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
ip.dep_entries.deinit(gpa);
ip.free_dep_entries.deinit(gpa);

ip.files.deinit(gpa);

ip.* = undefined;
}

Expand Down
17 changes: 8 additions & 9 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -839,8 +839,7 @@ pub const Block = struct {
const zcu = sema.mod;
const ip = &zcu.intern_pool;
const file_index = block.getFileScopeIndex(zcu);
const path_digest = zcu.filePathDigest(file_index);
return ip.trackZir(gpa, path_digest, inst);
return ip.trackZir(gpa, file_index, inst);
}
};

Expand Down Expand Up @@ -993,7 +992,7 @@ fn analyzeBodyInner(

try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body);

const mod = sema.mod;
const zcu = sema.mod;
const map = &sema.inst_map;
const tags = sema.code.instructions.items(.tag);
const datas = sema.code.instructions.items(.data);
Expand All @@ -1013,9 +1012,9 @@ fn analyzeBodyInner(
// The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away.
if (build_options.enable_logging) {
std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: {
const path_digest = block.src_base_inst.resolveFull(&mod.intern_pool).path_digest;
const index = mod.files.getIndex(path_digest).?;
break :sub_file_path mod.import_table.values()[index].sub_file_path;
const file_index = block.src_base_inst.resolveFull(&zcu.intern_pool).file;
const file = zcu.fileByIndex(file_index);
break :sub_file_path file.sub_file_path;
}, inst });
}

Expand Down Expand Up @@ -1776,9 +1775,9 @@ fn analyzeBodyInner(
const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
const err_union = try sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
if (err_union_ty.zigTypeTag(zcu) != .ErrorUnion) {
return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
err_union_ty.fmt(mod),
err_union_ty.fmt(zcu),
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
Expand Down Expand Up @@ -6003,7 +6002,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr

const path_digest = zcu.filePathDigest(result.file_index);
const root_decl = zcu.fileRootDecl(result.file_index);
zcu.astGenFile(result.file, path_digest, root_decl) catch |err|
zcu.astGenFile(result.file, result.file_index, path_digest, root_decl) catch |err|
return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});

try zcu.ensureFileAnalyzed(result.file_index);
Expand Down
2 changes: 1 addition & 1 deletion src/Type.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3455,7 +3455,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *const Zcu) ?u32 {
else => return null,
};
const info = tracked.resolveFull(&zcu.intern_pool);
const file = zcu.import_table.values()[zcu.files.getIndex(info.path_digest).?];
const file = zcu.fileByIndex(info.file);
assert(file.zir_loaded);
const zir = file.zir;
const inst = zir.instructions.get(@intFromEnum(info.inst));
Expand Down
Loading

0 comments on commit deae1ff

Please sign in to comment.