authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 15:59:27+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-10-16 16:30:36+01:00
logc6842b58d488c236aca74dea82082eec365eb117
treec858fc6af4e0a3358c22e5b0f4411e54e003cb8b
parenta7dd34bfc57f4f84bb5290177f26e2d1f0bdc27e
signaturelock-open Commit is signed but in an unrecognized format.

Zcu: cache output of `resolveReferences` between calls

This not only simplifies the error bundling logic, but also improves efficiency by allowing the result to be cached between, for instance, multiple calls to `totalErrorCount`.

3 files changed, 52 insertions(+), 38 deletions(-)

src/Compilation.zig+25-35
...@@ -3076,15 +3076,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3076,15 +3076,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3076 });3076 });
3077 }3077 }
30783078
3079 var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null;
3080 defer if (all_references) |*a| a.deinit(gpa);
3081
3082 if (comp.zcu) |zcu| {3079 if (comp.zcu) |zcu| {
3083 const ip = &zcu.intern_pool;3080 const ip = &zcu.intern_pool;
30843081
3085 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {3082 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
3086 if (error_msg) |msg| {3083 if (error_msg) |msg| {
3087 try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references);3084 try addModuleErrorMsg(zcu, &bundle, msg.*);
3088 } else {3085 } else {
3089 // Must be ZIR errors. Note that this may include AST errors.3086 // Must be ZIR errors. Note that this may include AST errors.
3090 // addZirErrorMessages asserts that the tree is loaded.3087 // addZirErrorMessages asserts that the tree is loaded.
...@@ -3093,7 +3090,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3093,7 +3090,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3093 }3090 }
3094 }3091 }
3095 for (zcu.failed_embed_files.values()) |error_msg| {3092 for (zcu.failed_embed_files.values()) |error_msg| {
3096 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3093 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3097 }3094 }
3098 {3095 {
3099 const SortOrder = struct {3096 const SortOrder = struct {
...@@ -3136,10 +3133,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3136,10 +3133,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3136 }3133 }
3137 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {3134 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
3138 if (comp.incremental) {3135 if (comp.incremental) {
3139 if (all_references == null) {3136 const refs = try zcu.resolveReferences();
3140 all_references = try zcu.resolveReferences();3137 if (!refs.contains(anal_unit)) continue;
3141 }
3142 if (!all_references.?.contains(anal_unit)) continue;
3143 }3138 }
31443139
3145 const file_index = switch (anal_unit.unwrap()) {3140 const file_index = switch (anal_unit.unwrap()) {
...@@ -3151,7 +3146,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3151,7 +3146,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3151 // We'll try again once parsing succeeds.3146 // We'll try again once parsing succeeds.
3152 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;3147 if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
31533148
3154 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3149 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3155 if (zcu.cimport_errors.get(anal_unit)) |errors| {3150 if (zcu.cimport_errors.get(anal_unit)) |errors| {
3156 for (errors.getMessages()) |err_msg_index| {3151 for (errors.getMessages()) |err_msg_index| {
3157 const err_msg = errors.getErrorMessage(err_msg_index);3152 const err_msg = errors.getErrorMessage(err_msg_index);
...@@ -3175,10 +3170,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3175,10 +3170,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3175 }3170 }
3176 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {3171 for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
3177 if (!zcu.navFileScope(nav).okToReportErrors()) continue;3172 if (!zcu.navFileScope(nav).okToReportErrors()) continue;
3178 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);3173 try addModuleErrorMsg(zcu, &bundle, error_msg.*);
3179 }3174 }
3180 for (zcu.failed_exports.values()) |value| {3175 for (zcu.failed_exports.values()) |value| {
3181 try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);3176 try addModuleErrorMsg(zcu, &bundle, value.*);
3182 }3177 }
31833178
3184 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;3179 const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len;
...@@ -3252,17 +3247,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {...@@ -3252,17 +3247,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
3252 };3247 };
3253 }3248 }
32543249
3255 try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references);3250 try addModuleErrorMsg(zcu, &bundle, err_msg);
3256 }3251 }
3257 }3252 }
32583253
3259 if (comp.zcu) |zcu| {3254 if (comp.zcu) |zcu| {
3260 if (comp.incremental and bundle.root_list.items.len == 0) {3255 if (comp.incremental and bundle.root_list.items.len == 0) {
3261 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {3256 const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| {
3262 if (all_references == null) {3257 const refs = try zcu.resolveReferences();
3263 all_references = try zcu.resolveReferences();3258 if (refs.contains(failed_unit)) break true;
3264 }
3265 if (all_references.?.contains(failed_unit)) break true;
3266 } else false;3259 } else false;
3267 if (should_have_error) {3260 if (should_have_error) {
3268 @panic("referenced transitive analysis errors, but none actually emitted");3261 @panic("referenced transitive analysis errors, but none actually emitted");
...@@ -3331,14 +3324,13 @@ pub const ErrorNoteHashContext = struct {...@@ -3331,14 +3324,13 @@ pub const ErrorNoteHashContext = struct {
3331};3324};
33323325
3333pub fn addModuleErrorMsg(3326pub fn addModuleErrorMsg(
3334 mod: *Zcu,3327 zcu: *Zcu,
3335 eb: *ErrorBundle.Wip,3328 eb: *ErrorBundle.Wip,
3336 module_err_msg: Zcu.ErrorMsg,3329 module_err_msg: Zcu.ErrorMsg,
3337 all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference),
3338) !void {3330) !void {
3339 const gpa = eb.gpa;3331 const gpa = eb.gpa;
3340 const ip = &mod.intern_pool;3332 const ip = &zcu.intern_pool;
3341 const err_src_loc = module_err_msg.src_loc.upgrade(mod);3333 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
3342 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {3334 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
3343 const file_path = try err_src_loc.file_scope.fullPath(gpa);3335 const file_path = try err_src_loc.file_scope.fullPath(gpa);
3344 defer gpa.free(file_path);3336 defer gpa.free(file_path);
...@@ -3358,22 +3350,20 @@ pub fn addModuleErrorMsg(...@@ -3358,22 +3350,20 @@ pub fn addModuleErrorMsg(
3358 defer ref_traces.deinit(gpa);3350 defer ref_traces.deinit(gpa);
33593351
3360 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {3352 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {
3361 if (all_references.* == null) {3353 const all_references = try zcu.resolveReferences();
3362 all_references.* = try mod.resolveReferences();
3363 }
33643354
3365 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;3355 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
3366 defer seen.deinit(gpa);3356 defer seen.deinit(gpa);
33673357
3368 const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len;3358 const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len;
33693359
3370 var referenced_by = rt_root;3360 var referenced_by = rt_root;
3371 while (all_references.*.?.get(referenced_by)) |maybe_ref| {3361 while (all_references.get(referenced_by)) |maybe_ref| {
3372 const ref = maybe_ref orelse break;3362 const ref = maybe_ref orelse break;
3373 const gop = try seen.getOrPut(gpa, ref.referencer);3363 const gop = try seen.getOrPut(gpa, ref.referencer);
3374 if (gop.found_existing) break;3364 if (gop.found_existing) break;
3375 if (ref_traces.items.len < max_references) {3365 if (ref_traces.items.len < max_references) {
3376 const src = ref.src.upgrade(mod);3366 const src = ref.src.upgrade(zcu);
3377 const source = try src.file_scope.getSource(gpa);3367 const source = try src.file_scope.getSource(gpa);
3378 const span = try src.span(gpa);3368 const span = try src.span(gpa);
3379 const loc = std.zig.findLineColumn(source.bytes, span.main);3369 const loc = std.zig.findLineColumn(source.bytes, span.main);
...@@ -3385,7 +3375,7 @@ pub fn addModuleErrorMsg(...@@ -3385,7 +3375,7 @@ pub fn addModuleErrorMsg(
3385 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),3375 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
3386 .none => "comptime",3376 .none => "comptime",
3387 },3377 },
3388 .func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip),3378 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
3389 };3379 };
3390 try ref_traces.append(gpa, .{3380 try ref_traces.append(gpa, .{
3391 .decl_name = try eb.addString(name),3381 .decl_name = try eb.addString(name),
...@@ -3435,7 +3425,7 @@ pub fn addModuleErrorMsg(...@@ -3435,7 +3425,7 @@ pub fn addModuleErrorMsg(
3435 defer notes.deinit(gpa);3425 defer notes.deinit(gpa);
34363426
3437 for (module_err_msg.notes) |module_note| {3427 for (module_err_msg.notes) |module_note| {
3438 const note_src_loc = module_note.src_loc.upgrade(mod);3428 const note_src_loc = module_note.src_loc.upgrade(zcu);
3439 const source = try note_src_loc.file_scope.getSource(gpa);3429 const source = try note_src_loc.file_scope.getSource(gpa);
3440 const span = try note_src_loc.span(gpa);3430 const span = try note_src_loc.span(gpa);
3441 const loc = std.zig.findLineColumn(source.bytes, span.main);3431 const loc = std.zig.findLineColumn(source.bytes, span.main);
...@@ -3488,13 +3478,13 @@ pub fn performAllTheWork(...@@ -3488,13 +3478,13 @@ pub fn performAllTheWork(
3488 comp: *Compilation,3478 comp: *Compilation,
3489 main_progress_node: std.Progress.Node,3479 main_progress_node: std.Progress.Node,
3490) JobError!void {3480) JobError!void {
3491 defer if (comp.zcu) |mod| {3481 defer if (comp.zcu) |zcu| {
3492 mod.sema_prog_node.end();3482 zcu.sema_prog_node.end();
3493 mod.sema_prog_node = std.Progress.Node.none;3483 zcu.sema_prog_node = std.Progress.Node.none;
3494 mod.codegen_prog_node.end();3484 zcu.codegen_prog_node.end();
3495 mod.codegen_prog_node = std.Progress.Node.none;3485 zcu.codegen_prog_node = std.Progress.Node.none;
34963486
3497 mod.generation += 1;3487 zcu.generation += 1;
3498 };3488 };
3499 try comp.performAllTheWorkInner(main_progress_node);3489 try comp.performAllTheWorkInner(main_progress_node);
3500 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;3490 if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error;
src/Sema.zig+1-2
...@@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg...@@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg
2559 const zcu = sema.pt.zcu;2559 const zcu = sema.pt.zcu;
25602560
2561 if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {2561 if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) {
2562 var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null;
2563 var wip_errors: std.zig.ErrorBundle.Wip = undefined;2562 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2564 wip_errors.init(gpa) catch @panic("out of memory");2563 wip_errors.init(gpa) catch @panic("out of memory");
2565 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory");2564 Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory");
2566 std.debug.print("compile error during Sema:\n", .{});2565 std.debug.print("compile error during Sema:\n", .{});
2567 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");2566 var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory");
2568 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });2567 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
src/Zcu.zig+26-1
...@@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,...@@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty,
173/// These are the modules which we initially queue for analysis in `Compilation.update`.173/// These are the modules which we initially queue for analysis in `Compilation.update`.
174/// `resolveReferences` will use these as the root of its reachability traversal.174/// `resolveReferences` will use these as the root of its reachability traversal.
175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},175analysis_roots: std.BoundedArray(*Package.Module, 3) = .{},
176/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
177/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
178/// Allocated into `gpa`.
179resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null,
176180
177stage1_flags: packed struct {181stage1_flags: packed struct {
178 have_winmain: bool = false,182 have_winmain: bool = false,
...@@ -2192,6 +2196,8 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2192,6 +2196,8 @@ pub fn deinit(zcu: *Zcu) void {
2192 zcu.all_type_references.deinit(gpa);2196 zcu.all_type_references.deinit(gpa);
2193 zcu.free_type_references.deinit(gpa);2197 zcu.free_type_references.deinit(gpa);
21942198
2199 if (zcu.resolved_references) |*r| r.deinit(gpa);
2200
2195 zcu.intern_pool.deinit(gpa);2201 zcu.intern_pool.deinit(gpa);
2196}2202}
21972203
...@@ -2760,6 +2766,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2760,6 +2766,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
2760pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {2766pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2761 const gpa = zcu.gpa;2767 const gpa = zcu.gpa;
27622768
2769 zcu.clearCachedResolvedReferences();
2770
2763 unit_refs: {2771 unit_refs: {
2764 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;2772 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;
2765 var idx = kv.value;2773 var idx = kv.value;
...@@ -2792,6 +2800,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -2792,6 +2800,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
2792pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {2800pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
2793 const gpa = zcu.gpa;2801 const gpa = zcu.gpa;
27942802
2803 zcu.clearCachedResolvedReferences();
2804
2795 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);2805 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
27962806
2797 const ref_idx = zcu.free_references.popOrNull() orelse idx: {2807 const ref_idx = zcu.free_references.popOrNull() orelse idx: {
...@@ -2815,6 +2825,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -2815,6 +2825,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
2815pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {2825pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void {
2816 const gpa = zcu.gpa;2826 const gpa = zcu.gpa;
28172827
2828 zcu.clearCachedResolvedReferences();
2829
2818 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);2830 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1);
28192831
2820 const ref_idx = zcu.free_type_references.popOrNull() orelse idx: {2832 const ref_idx = zcu.free_type_references.popOrNull() orelse idx: {
...@@ -2835,6 +2847,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo...@@ -2835,6 +2847,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo
2835 gop.value_ptr.* = @intCast(ref_idx);2847 gop.value_ptr.* = @intCast(ref_idx);
2836}2848}
28372849
2850fn clearCachedResolvedReferences(zcu: *Zcu) void {
2851 if (zcu.resolved_references) |*r| r.deinit(zcu.gpa);
2852 zcu.resolved_references = null;
2853}
2854
2838pub fn errorSetBits(zcu: *const Zcu) u16 {2855pub fn errorSetBits(zcu: *const Zcu) u16 {
2839 if (zcu.error_limit == 0) return 0;2856 if (zcu.error_limit == 0) return 0;
2840 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;2857 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1;
...@@ -3138,7 +3155,15 @@ pub const ResolvedReference = struct {...@@ -3138,7 +3155,15 @@ pub const ResolvedReference = struct {
3138/// Returns a mapping from an `AnalUnit` to where it is referenced.3155/// Returns a mapping from an `AnalUnit` to where it is referenced.
3139/// If the value is `null`, the `AnalUnit` is a root of analysis.3156/// If the value is `null`, the `AnalUnit` is a root of analysis.
3140/// If an `AnalUnit` is not in the returned map, it is unreferenced.3157/// If an `AnalUnit` is not in the returned map, it is unreferenced.
3141pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {3158/// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller.
3159/// This hashmap is cached, so repeated calls to this function are cheap.
3160pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3161 if (zcu.resolved_references == null) {
3162 zcu.resolved_references = try zcu.resolveReferencesInner();
3163 }
3164 return &zcu.resolved_references.?;
3165}
3166fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) {
3142 const gpa = zcu.gpa;3167 const gpa = zcu.gpa;
3143 const comp = zcu.comp;3168 const comp = zcu.comp;
3144 const ip = &zcu.intern_pool;3169 const ip = &zcu.intern_pool;