commit bcb1a6bdf3ef1f39784298deaf2adfb91ea5c5c1 (tree)
parent 7170e0f02043d157cb4e10c6333e125c10395a63
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Wed, 11 Feb 2026 15:05:33 +0000
compiler: make Dwarf and self-hosted x86_64 happy
Introduces a small abstraction, `link.DebugConstPool`, to deal with
lowering type/value information into debug info when it may not be known
until type resolution (which in some cases will *never* happen). It is
currently only used by self-hosted DWARF logic, but it will also be of
use to the LLVM backend (which is my next focus).
Diffstat:
8 files changed, 1033 insertions(+), 1468 deletions(-)
diff --git a/src/Compilation.zig b/src/Compilation.zig
@@ -956,8 +956,7 @@ pub const RcSourceFile = struct {
const Job = union(enum) {
/// Given the generated AIR for a function, put it onto the code generation queue.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
+ /// MLUGG TODO: because type resolution is no longer necessary, we can remove this now
/// If the backend does not support `Zcu.Feature.separate_thread`, codegen and linking happen immediately.
/// Before queueing this `Job`, increase the estimated total item count for both
/// `comp.zcu.?.codegen_prog_node` and `comp.link_prog_node`.
@@ -967,17 +966,10 @@ const Job = union(enum) {
air: Air,
},
/// Queue a `link.ZcuTask` to emit this non-function `Nav` into the output binary.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
+ /// MLUGG TODO: because type resolution is no longer necessary, we can remove this now
/// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately.
/// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
link_nav: InternPool.Nav.Index,
- /// Queue a `link.ZcuTask` to emit debug information for this container type.
- /// This `Job` exists (instead of the `link.ZcuTask` being directly queued) to ensure that
- /// all types are resolved before the linker task is queued.
- /// If the backend does not support `Zcu.Feature.separate_thread`, the task is run immediately.
- /// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
- link_type: InternPool.Index,
/// Before queueing this `Job`, increase the estimated total item count for `comp.link_prog_node`.
update_line_number: InternPool.TrackedInst.Index,
/// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
@@ -5058,26 +5050,6 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
var owned_air: ?Air = func.air;
defer if (owned_air) |*air| air.deinit(gpa);
- {
- const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
- defer pt.deactivate();
- pt.resolveAirTypesForCodegen(&owned_air.?) catch |err| switch (err) {
- error.OutOfMemory,
- error.Canceled,
- => |e| return e,
-
- error.AnalysisFail => {
- // Type resolution failed, making codegen of this function impossible. This
- // is a transitive failure, but it doesn't need recording, because this
- // function semantically depends on the failed type, so when it is changed
- // the function will be updated.
- zcu.codegen_prog_node.completeOne();
- comp.link_prog_node.completeOne();
- return;
- },
- };
- }
-
// Some linkers need to refer to the AIR. In that case, the linker is not running
// concurrently, so we'll just keep ownership of the AIR for ourselves instead of
// letting the codegen job destroy it.
@@ -5101,51 +5073,10 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
}
}
assert(nav.status == .fully_resolved);
- {
- const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
- defer pt.deactivate();
- pt.resolveValueTypesForCodegen(zcu.navValue(nav_index)) catch |err| switch (err) {
- error.OutOfMemory,
- error.Canceled,
- => |e| return e,
-
- error.AnalysisFail => {
- // Type resolution failed, making codegen of this `Nav` impossible. This is
- // a transitive failure, but it doesn't need recording, because this `Nav`
- // semantically depends on the failed type, so when it is changed the value
- // of the `Nav` will be updated.
- comp.link_prog_node.completeOne();
- return;
- },
- };
- }
try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index });
},
- .link_type => |ty| {
- const zcu = comp.zcu.?;
- if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
- {
- const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
- defer pt.deactivate();
- pt.resolveTypeForCodegen(.fromInterned(ty)) catch |err| switch (err) {
- error.OutOfMemory,
- error.Canceled,
- => |e| return e,
-
- error.AnalysisFail => {
- // Type resolution failed, making codegen of this type impossible. This is
- // a transitive failure, but it doesn't need recording, because this type
- // semantically depends on the failed type, so when it is changed the type
- // will be updated appropriately.
- comp.link_prog_node.completeOne();
- return;
- },
- };
- }
- try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty });
- },
.update_line_number => |tracked_inst| {
- try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst });
+ try comp.link_queue.enqueueZcu(comp, tid, .{ .debug_update_line_number = tracked_inst });
},
.analyze_unit => |unit| {
const tracy_trace = traceNamed(@src(), "analyze_unit");
diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig
@@ -998,10 +998,10 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
try sema.flushExports();
}
-/// Ensures that the layout of the given `struct` or `union` type is fully up-to-date, performing
-/// re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or union. Returns
-/// `error.AnalysisFail` if an analysis error is encountered during type resolution; the caller is
-/// free to ignore this, since the error is already registered.
+/// Ensures that the layout of the given `struct`, `union`, or `enum` type is fully up-to-date,
+/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!), union, or
+/// enum type. Returns `error.AnalysisFail` if an analysis error is encountered during type
+/// resolution; the caller is free to ignore this, since the error is already registered.
pub fn ensureTypeLayoutUpToDate(
pt: Zcu.PerThread,
ty: Type,
@@ -1012,7 +1012,8 @@ pub fn ensureTypeLayoutUpToDate(
defer tracy.end();
const zcu = pt.zcu;
- const gpa = zcu.gpa;
+ const comp = zcu.comp;
+ const gpa = comp.gpa;
const anal_unit: AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
@@ -1021,7 +1022,7 @@ pub fn ensureTypeLayoutUpToDate(
assert(!zcu.analysis_in_progress.contains(anal_unit));
const was_outdated = zcu.clearOutdatedState(anal_unit) or
- zcu.intern_pool.setWantTypeLayout(zcu.comp.io, ty.toIntern());
+ zcu.intern_pool.setWantTypeLayout(comp.io, ty.toIntern());
if (was_outdated) {
// `was_outdated` is true in the initial update, so this isn't a `dev.check`.
@@ -1038,7 +1039,7 @@ pub fn ensureTypeLayoutUpToDate(
return;
}
- if (zcu.comp.debugIncremental()) {
+ if (comp.debugIncremental()) {
const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
info.last_update_gen = zcu.generation;
info.deps.clearRetainingCapacity();
@@ -1078,15 +1079,17 @@ pub fn ensureTypeLayoutUpToDate(
.@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
else => unreachable,
};
- result catch |err| switch (err) {
- error.AnalysisFail => {
+ const new_success: bool = if (result) s: {
+ break :s true;
+ } else |err| switch (err) {
+ error.AnalysisFail => success: {
if (!zcu.failed_analysis.contains(anal_unit)) {
// If this unit caused the error, it would have an entry in `failed_analysis`.
// Since it does not, this must be a transitive failure.
try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
}
- return error.AnalysisFail;
+ break :success false;
},
error.OutOfMemory,
error.Canceled,
@@ -1098,6 +1101,15 @@ pub fn ensureTypeLayoutUpToDate(
sema.flushExports() catch |err| switch (err) {
error.OutOfMemory => |e| return e,
};
+
+ // We don't need to `markDependeeOutdated`/`markPoDependeeUpToDate` here, because we already
+ // marked the layout as outdated at the top of this function. However, we do need to tell the
+ // debug info logic in the backend about this type.
+ comp.link_prog_node.increaseEstimatedTotalItems(1);
+ try comp.link_queue.enqueueZcu(comp, pt.tid, .{ .debug_update_container_type = .{
+ .ty = ty.toIntern(),
+ .success = new_success,
+ } });
}
/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
@@ -4102,463 +4114,3 @@ fn printVerboseAir(
try air.write(w, pt, liveness);
try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});
}
-
-// MLUGG TODO: these functions are all blatant hacks. See if I can remove them!
-pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- if (ty.isGenericPoison()) return;
- switch (ty.zigTypeTag(zcu)) {
- .type,
- .void,
- .bool,
- .noreturn,
- .int,
- .float,
- .error_set,
- .@"opaque",
- .comptime_float,
- .comptime_int,
- .undefined,
- .null,
- .enum_literal,
- => {},
-
- .frame, .@"anyframe" => @panic("TODO resolveTypeForCodegen async frames"),
-
- .optional => try pt.resolveTypeForCodegen(ty.childType(zcu)),
- .error_union => try pt.resolveTypeForCodegen(ty.errorUnionPayload(zcu)),
- .pointer => try pt.resolveTypeForCodegen(ty.childType(zcu)),
- .array => try pt.resolveTypeForCodegen(ty.childType(zcu)),
- .vector => try pt.resolveTypeForCodegen(ty.childType(zcu)),
-
- .@"fn" => {
- const info = zcu.typeToFunc(ty).?;
- for (0..info.param_types.len) |i| {
- const param_ty = info.param_types.get(ip)[i];
- try pt.resolveTypeForCodegen(.fromInterned(param_ty));
- }
- try pt.resolveTypeForCodegen(.fromInterned(info.return_type));
- },
-
- .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
- .struct_type => try pt.ensureTypeLayoutUpToDate(ty, null),
- .tuple_type => |tuple| for (0..tuple.types.len) |i| {
- const field_is_comptime = tuple.values.get(ip)[i] != .none;
- if (field_is_comptime) continue;
- const field_ty = tuple.types.get(ip)[i];
- try pt.resolveTypeForCodegen(.fromInterned(field_ty));
- },
- else => unreachable,
- },
-
- .@"union" => try pt.ensureTypeLayoutUpToDate(ty, null),
- .@"enum" => try pt.ensureTypeLayoutUpToDate(ty, null),
- }
-}
-pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {
- const zcu = pt.zcu;
- const ty: Type = switch (val.typeOf(zcu).toIntern()) {
- .type_type => if (val.isUndef(zcu)) {
- return;
- } else val.toType(),
- else => |ty| .fromInterned(ty),
- };
- return pt.resolveTypeForCodegen(ty);
-}
-pub fn resolveAirTypesForCodegen(pt: Zcu.PerThread, air: *const Air) Zcu.SemaError!void {
- return pt.resolveBodyTypesForCodegen(air, air.getMainBody());
-}
-fn resolveBodyTypesForCodegen(pt: Zcu.PerThread, air: *const Air, body: []const Air.Inst.Index) Zcu.SemaError!void {
- const zcu = pt.zcu;
- const tags = air.instructions.items(.tag);
- const datas = air.instructions.items(.data);
- for (body) |inst| {
- const data = datas[@intFromEnum(inst)];
- switch (tags[@intFromEnum(inst)]) {
- .inferred_alloc, .inferred_alloc_comptime => unreachable,
-
- .arg => try pt.resolveTypeForCodegen(data.arg.ty.toType()),
-
- .add,
- .add_safe,
- .add_optimized,
- .add_wrap,
- .add_sat,
- .sub,
- .sub_safe,
- .sub_optimized,
- .sub_wrap,
- .sub_sat,
- .mul,
- .mul_safe,
- .mul_optimized,
- .mul_wrap,
- .mul_sat,
- .div_float,
- .div_float_optimized,
- .div_trunc,
- .div_trunc_optimized,
- .div_floor,
- .div_floor_optimized,
- .div_exact,
- .div_exact_optimized,
- .rem,
- .rem_optimized,
- .mod,
- .mod_optimized,
- .max,
- .min,
- .bit_and,
- .bit_or,
- .shr,
- .shr_exact,
- .shl,
- .shl_exact,
- .shl_sat,
- .xor,
- .cmp_lt,
- .cmp_lt_optimized,
- .cmp_lte,
- .cmp_lte_optimized,
- .cmp_eq,
- .cmp_eq_optimized,
- .cmp_gte,
- .cmp_gte_optimized,
- .cmp_gt,
- .cmp_gt_optimized,
- .cmp_neq,
- .cmp_neq_optimized,
- .bool_and,
- .bool_or,
- .store,
- .store_safe,
- .set_union_tag,
- .array_elem_val,
- .slice_elem_val,
- .ptr_elem_val,
- .memset,
- .memset_safe,
- .memcpy,
- .memmove,
- .atomic_store_unordered,
- .atomic_store_monotonic,
- .atomic_store_release,
- .atomic_store_seq_cst,
- .legalize_vec_elem_val,
- => {
- try pt.resolveRefTypesForCodegen(data.bin_op.lhs);
- try pt.resolveRefTypesForCodegen(data.bin_op.rhs);
- },
-
- .not,
- .bitcast,
- .clz,
- .ctz,
- .popcount,
- .byte_swap,
- .bit_reverse,
- .abs,
- .load,
- .fptrunc,
- .fpext,
- .intcast,
- .intcast_safe,
- .trunc,
- .optional_payload,
- .optional_payload_ptr,
- .optional_payload_ptr_set,
- .wrap_optional,
- .unwrap_errunion_payload,
- .unwrap_errunion_err,
- .unwrap_errunion_payload_ptr,
- .unwrap_errunion_err_ptr,
- .errunion_payload_ptr_set,
- .wrap_errunion_payload,
- .wrap_errunion_err,
- .struct_field_ptr_index_0,
- .struct_field_ptr_index_1,
- .struct_field_ptr_index_2,
- .struct_field_ptr_index_3,
- .get_union_tag,
- .slice_len,
- .slice_ptr,
- .ptr_slice_len_ptr,
- .ptr_slice_ptr_ptr,
- .array_to_slice,
- .int_from_float,
- .int_from_float_optimized,
- .int_from_float_safe,
- .int_from_float_optimized_safe,
- .float_from_int,
- .splat,
- .error_set_has_value,
- .addrspace_cast,
- .c_va_arg,
- .c_va_copy,
- => {
- try pt.resolveTypeForCodegen(data.ty_op.ty.toType());
- try pt.resolveRefTypesForCodegen(data.ty_op.operand);
- },
-
- .alloc,
- .ret_ptr,
- .c_va_start,
- => try pt.resolveTypeForCodegen(data.ty),
-
- .ptr_add,
- .ptr_sub,
- .add_with_overflow,
- .sub_with_overflow,
- .mul_with_overflow,
- .shl_with_overflow,
- .slice,
- .slice_elem_ptr,
- .ptr_elem_ptr,
- => {
- const bin = air.extraData(Air.Bin, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(bin.lhs);
- try pt.resolveRefTypesForCodegen(bin.rhs);
- },
-
- .block,
- .loop,
- => {
- const block = air.unwrapBlock(inst);
- try pt.resolveTypeForCodegen(block.ty);
- try pt.resolveBodyTypesForCodegen(air, block.body);
- },
-
- .dbg_inline_block => {
- const block = air.unwrapDbgBlock(inst);
- try pt.resolveTypeForCodegen(block.ty);
- try pt.resolveBodyTypesForCodegen(air, block.body);
- },
-
- .sqrt,
- .sin,
- .cos,
- .tan,
- .exp,
- .exp2,
- .log,
- .log2,
- .log10,
- .floor,
- .ceil,
- .round,
- .trunc_float,
- .neg,
- .neg_optimized,
- .is_null,
- .is_non_null,
- .is_null_ptr,
- .is_non_null_ptr,
- .is_err,
- .is_non_err,
- .is_err_ptr,
- .is_non_err_ptr,
- .ret,
- .ret_safe,
- .ret_load,
- .is_named_enum_value,
- .tag_name,
- .error_name,
- .cmp_lt_errors_len,
- .c_va_end,
- .set_err_return_trace,
- => try pt.resolveRefTypesForCodegen(data.un_op),
-
- .br, .switch_dispatch => try pt.resolveRefTypesForCodegen(data.br.operand),
-
- .cmp_vector,
- .cmp_vector_optimized,
- => {
- const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(extra.lhs);
- try pt.resolveRefTypesForCodegen(extra.rhs);
- },
-
- .reduce,
- .reduce_optimized,
- => try pt.resolveRefTypesForCodegen(data.reduce.operand),
-
- .struct_field_ptr,
- .struct_field_val,
- => {
- const extra = air.extraData(Air.StructField, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(extra.struct_operand);
- },
-
- .shuffle_one => {
- const unwrapped = air.unwrapShuffleOne(zcu, inst);
- try pt.resolveTypeForCodegen(unwrapped.result_ty);
- try pt.resolveRefTypesForCodegen(unwrapped.operand);
- for (unwrapped.mask) |m| switch (m.unwrap()) {
- .elem => {},
- .value => |val| try pt.resolveValueTypesForCodegen(.fromInterned(val)),
- };
- },
-
- .shuffle_two => {
- const unwrapped = air.unwrapShuffleTwo(zcu, inst);
- try pt.resolveTypeForCodegen(unwrapped.result_ty);
- try pt.resolveRefTypesForCodegen(unwrapped.operand_a);
- try pt.resolveRefTypesForCodegen(unwrapped.operand_b);
- // No values to check because there are no comptime-known values other than undef
- },
-
- .cmpxchg_weak,
- .cmpxchg_strong,
- => {
- const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(extra.ptr);
- try pt.resolveRefTypesForCodegen(extra.expected_value);
- try pt.resolveRefTypesForCodegen(extra.new_value);
- },
-
- .aggregate_init => {
- const ty = data.ty_pl.ty.toType();
- const elems_len: usize = @intCast(ty.arrayLen(zcu));
- const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]);
- try pt.resolveTypeForCodegen(ty);
- if (ty.zigTypeTag(zcu) == .@"struct") {
- for (elems, 0..) |elem, elem_idx| {
- if (ty.structFieldIsComptime(elem_idx, zcu)) continue;
- try pt.resolveRefTypesForCodegen(elem);
- }
- } else {
- for (elems) |elem| {
- try pt.resolveRefTypesForCodegen(elem);
- }
- }
- },
-
- .union_init => {
- const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(extra.init);
- },
-
- .field_parent_ptr => {
- const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data;
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- try pt.resolveRefTypesForCodegen(extra.field_ptr);
- },
-
- .atomic_load => try pt.resolveRefTypesForCodegen(data.atomic_load.ptr),
-
- .prefetch => try pt.resolveRefTypesForCodegen(data.prefetch.ptr),
-
- .runtime_nav_ptr => try pt.resolveTypeForCodegen(.fromInterned(data.ty_nav.ty)),
-
- .select,
- .mul_add,
- .legalize_vec_store_elem,
- => {
- const bin = air.extraData(Air.Bin, data.pl_op.payload).data;
- try pt.resolveRefTypesForCodegen(data.pl_op.operand);
- try pt.resolveRefTypesForCodegen(bin.lhs);
- try pt.resolveRefTypesForCodegen(bin.rhs);
- },
-
- .atomic_rmw => {
- const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data;
- try pt.resolveRefTypesForCodegen(data.pl_op.operand);
- try pt.resolveRefTypesForCodegen(extra.operand);
- },
-
- .call,
- .call_always_tail,
- .call_never_tail,
- .call_never_inline,
- => {
- const call = air.unwrapCall(inst);
- try pt.resolveRefTypesForCodegen(call.callee);
- for (call.args) |arg| try pt.resolveRefTypesForCodegen(arg);
- },
-
- .dbg_var_ptr,
- .dbg_var_val,
- .dbg_arg_inline,
- => try pt.resolveRefTypesForCodegen(data.pl_op.operand),
-
- .@"try", .try_cold => {
- const @"try" = air.unwrapTry(inst);
- try pt.resolveRefTypesForCodegen(@"try".error_union);
- try pt.resolveBodyTypesForCodegen(air, @"try".else_body);
- },
-
- .try_ptr, .try_ptr_cold => {
- const try_ptr = air.unwrapTryPtr(inst);
- try pt.resolveTypeForCodegen(try_ptr.error_union_payload_ptr_ty.toType());
- try pt.resolveRefTypesForCodegen(try_ptr.error_union_ptr);
- try pt.resolveBodyTypesForCodegen(air, try_ptr.else_body);
- },
-
- .cond_br => {
- const cond_br = air.unwrapCondBr(inst);
- try pt.resolveRefTypesForCodegen(cond_br.condition);
- try pt.resolveBodyTypesForCodegen(air, cond_br.then_body);
- try pt.resolveBodyTypesForCodegen(air, cond_br.else_body);
- },
-
- .switch_br, .loop_switch_br => {
- const switch_br = air.unwrapSwitch(inst);
- try pt.resolveRefTypesForCodegen(switch_br.operand);
- var it = switch_br.iterateCases();
- while (it.next()) |case| {
- for (case.items) |item| {
- try pt.resolveRefTypesForCodegen(item);
- }
- for (case.ranges) |range| {
- try pt.resolveRefTypesForCodegen(range[0]);
- try pt.resolveRefTypesForCodegen(range[1]);
- }
- try pt.resolveBodyTypesForCodegen(air, case.body);
- }
- try pt.resolveBodyTypesForCodegen(air, it.elseBody());
- },
-
- .assembly => {
- const @"asm" = air.unwrapAsm(inst);
- try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
- for (@"asm".outputs) |output| if (output != .none) try pt.resolveRefTypesForCodegen(output);
- for (@"asm".inputs) |input| if (input != .none) try pt.resolveRefTypesForCodegen(input);
- },
-
- .legalize_compiler_rt_call => {
- const compiler_rt_call = air.unwrapCompilerRtCall(inst);
- for (compiler_rt_call.args) |arg| try pt.resolveRefTypesForCodegen(arg);
- },
-
- .trap,
- .breakpoint,
- .ret_addr,
- .frame_addr,
- .unreach,
- .wasm_memory_size,
- .wasm_memory_grow,
- .work_item_id,
- .work_group_size,
- .work_group_id,
- .dbg_stmt,
- .dbg_empty_stmt,
- .err_return_trace,
- .save_err_return_trace_index,
- .repeat,
- => {},
- }
- }
-}
-fn resolveRefTypesForCodegen(pt: Zcu.PerThread, ref: Air.Inst.Ref) Zcu.SemaError!void {
- const ip_index = ref.toInterned() orelse {
- // `ref` refers to a prior instruction, which we already did the resolution for.
- return;
- };
- return pt.resolveValueTypesForCodegen(.fromInterned(ip_index));
-}
diff --git a/src/codegen.zig b/src/codegen.zig
@@ -700,7 +700,14 @@ fn lowerPtr(
};
return lowerPtr(bin_file, pt, src_loc, field.base, w, reloc_parent, offset + field_off);
},
- .arr_elem, .comptime_field, .comptime_alloc => unreachable,
+ .arr_elem => |arr_elem| {
+ const base_ptr_ty = Value.fromInterned(arr_elem.base).typeOf(zcu);
+ assert(base_ptr_ty.ptrSize(zcu) == .many);
+ const elem_size = base_ptr_ty.childType(zcu).abiSize(zcu);
+ return lowerPtr(bin_file, pt, src_loc, arr_elem.base, w, reloc_parent, offset + elem_size * arr_elem.index);
+ },
+ .comptime_alloc => unreachable,
+ .comptime_field => unreachable,
};
}
@@ -781,9 +788,8 @@ fn lowerNavRef(
const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
const is_obj = lf.comp.config.output_mode == .Obj;
const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
- const is_fn_body = nav_ty.zigTypeTag(zcu) == .@"fn";
- if (!is_fn_body and !nav_ty.hasRuntimeBits(zcu)) {
+ if (!nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) and ip.getNav(nav_index).getExtern(ip) == null) {
try w.splatByteAll(0xaa, ptr_width_bytes);
return;
}
@@ -795,7 +801,7 @@ fn lowerNavRef(
dev.check(link.File.Tag.wasm.devFeature());
const wasm = lf.cast(.wasm).?;
assert(reloc_parent == .none);
- if (is_fn_body) {
+ if (nav_ty.zigTypeTag(zcu) == .@"fn") {
const gop = try wasm.zcu_indirect_function_set.getOrPut(gpa, nav_index);
if (!gop.found_existing) gop.value_ptr.* = {};
if (is_obj) {
@@ -1025,23 +1031,26 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
.pointer => switch (ty.ptrSize(zcu)) {
.slice => {},
.one, .many, .c => {
- const elem_ty = ty.childType(zcu);
const ptr = ip.indexToKey(val.toIntern()).ptr;
if (ptr.base_addr == .int) return .{ .immediate = ptr.byte_offset };
if (ptr.byte_offset == 0) switch (ptr.base_addr) {
.int => unreachable, // handled above
- .nav => |nav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
- return .{ .lea_nav = nav };
- } else {
- // Create the 0xaa bit pattern...
- const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
- // ...but align the pointer
- const alignment = zcu.navAlignment(nav);
- return .{ .immediate = alignment.forward(undef_ptr_bits) };
+ .nav => |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const nav_ty: Type = .fromInterned(nav.typeOf(ip));
+ if (nav_ty.isRuntimeFnOrHasRuntimeBits(zcu) or nav.getExtern(ip) != null) {
+ return .{ .lea_nav = nav_index };
+ } else {
+ // Create the 0xaa bit pattern...
+ const undef_ptr_bits: u64 = @intCast((@as(u66, 1) << @intCast(target.ptrBitWidth() + 1)) / 3);
+ // ...but align the pointer
+ const alignment = zcu.navAlignment(nav_index);
+ return .{ .immediate = alignment.forward(undef_ptr_bits) };
+ }
},
- .uav => |uav| if (elem_ty.isRuntimeFnOrHasRuntimeBits(zcu)) {
+ .uav => |uav| if (Value.fromInterned(uav.val).typeOf(zcu).isRuntimeFnOrHasRuntimeBits(zcu)) {
return .{ .lea_uav = uav };
} else {
// Create the 0xaa bit pattern...
diff --git a/src/link.zig b/src/link.zig
@@ -798,14 +798,27 @@ pub const File = struct {
};
/// Never called when LLVM is codegenning the ZCU.
- fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
+ fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index, success: bool) UpdateContainerTypeError!void {
assert(base.comp.zcu.?.llvm_object == null);
switch (base.tag) {
.lld => unreachable,
else => {},
inline .elf => |tag| {
dev.check(tag.devFeature());
- return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty);
+ return @as(*tag.Type(), @fieldParentPtr("base", base)).updateContainerType(pt, ty, success);
+ },
+ }
+ }
+
+ /// Never called when LLVM is codegenning the ZCU.
+ fn clearContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
+ assert(base.comp.zcu.?.llvm_object == null);
+ switch (base.tag) {
+ .lld => unreachable,
+ else => {},
+ inline .elf => |tag| {
+ dev.check(tag.devFeature());
+ return @as(*tag.Type(), @fieldParentPtr("base", base)).clearContainerType(pt, ty);
},
}
}
@@ -1375,8 +1388,14 @@ pub const ZcuTask = union(enum) {
link_nav: InternPool.Nav.Index,
/// Write the machine code for a function to the output file.
link_func: Zcu.CodegenTaskPool.Index,
- link_type: InternPool.Index,
- update_line_number: InternPool.TrackedInst.Index,
+ /// This struct/union/enum type has finished type resolution (successfully or otherwise), so the
+ /// linker can now lower debug information for this type (and any structural types which depend
+ /// on it, such as `?T`, `struct { T }`, `[2]T`, etc).
+ debug_update_container_type: struct {
+ ty: InternPool.Index,
+ success: bool,
+ },
+ debug_update_line_number: InternPool.TrackedInst.Index,
};
pub fn doPrelinkTask(comp: *Compilation, task: PrelinkTask) void {
@@ -1563,21 +1582,24 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
}
break :nav ip.indexToKey(func).func.owner_nav;
},
- .link_type => |ty| nav: {
- const name = Type.fromInterned(ty).containerTypeName(ip).toSlice(ip);
- const nav_prog_node = comp.link_prog_node.start(name, 0);
- defer nav_prog_node.end();
- if (zcu.llvm_object == null) {
+ .debug_update_container_type => |container_update| nav: {
+ const name = Type.fromInterned(container_update.ty).containerTypeName(ip).toSlice(ip);
+ const ty_prog_node = comp.link_prog_node.start(name, 0);
+ defer ty_prog_node.end();
+ if (zcu.llvm_object) |llvm_object| {
+ _ = llvm_object;
+ @compileError("MLUGG TODO");
+ } else {
if (comp.bin_file) |lf| {
- lf.updateContainerType(pt, ty) catch |err| switch (err) {
+ lf.updateContainerType(pt, container_update.ty, container_update.success) catch |err| switch (err) {
error.OutOfMemory => diags.setAllocFailure(),
- error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
+ error.TypeFailureReported => assert(zcu.failed_types.contains(container_update.ty)),
};
}
}
break :nav null;
},
- .update_line_number => |ti| nav: {
+ .debug_update_line_number => |ti| nav: {
const nav_prog_node = comp.link_prog_node.start("Update line number", 0);
defer nav_prog_node.end();
if (pt.zcu.llvm_object == null) {
diff --git a/src/link/DebugConstPool.zig b/src/link/DebugConstPool.zig
@@ -0,0 +1,287 @@
+/// Helper type for debug information implementations (such as `link.Dwarf`) to help them emit
+/// information about comptime-known values (constants), including types.
+///
+/// Every constant with associated debug information is assigned an `Index` by calling `get`. The
+/// pool will track which container types do and do not have a resolved layout, as well as which
+/// constants in the pool depend on which types, and call into the implementation to emit debug
+/// information for a constant only when all information is available.
+///
+/// Indices into the pool are dense, and constants are never removed from the pool, so the debug
+/// info implementation can store information for each one with a simple `ArrayList`.
+///
+/// To use `DebugConstPool`, the debug info implementation is required to:
+/// * forward `updateContainerType` calls to its `DebugConstPool`
+/// * expose some callback functions---see functions in `DebugInfo`
+/// * ensure that any `get` call is eventually followed by a `flushPending` call
+const DebugConstPool = @This();
+
+values: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+pending: std.ArrayList(Index),
+complete_containers: std.AutoArrayHashMapUnmanaged(InternPool.Index, void),
+container_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, ContainerDepEntry.Index),
+container_dep_entries: std.ArrayList(ContainerDepEntry),
+
+pub const empty: DebugConstPool = .{
+ .values = .empty,
+ .pending = .empty,
+ .complete_containers = .empty,
+ .container_deps = .empty,
+ .container_dep_entries = .empty,
+};
+
+pub fn deinit(pool: *DebugConstPool, gpa: Allocator) void {
+ pool.values.deinit(gpa);
+ pool.pending.deinit(gpa);
+ pool.complete_containers.deinit(gpa);
+ pool.container_deps.deinit(gpa);
+ pool.container_dep_entries.deinit(gpa);
+}
+
+pub const Index = enum(u32) {
+ _,
+ pub fn val(i: Index, pool: *const DebugConstPool) InternPool.Index {
+ return pool.values.keys()[@intFromEnum(i)];
+ }
+};
+
+pub const DebugInfo = union(enum) {
+ dwarf: *@import("Dwarf.zig"),
+ llvm: @import("../codegen/llvm.zig").Object.Ptr,
+
+ /// Inform the debug info implementation that the new constant `val` was added to the pool at
+ /// the given index (which equals the current pool length) due to a `get` call. It is guaranteed
+ /// that there will eventually be a call to either `updateConst` or `updateConstIncomplete`
+ /// following the `addConst` call, to actually populate the constant's debug info.
+ fn addConst(
+ di: DebugInfo,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) !void {
+ switch (di) {
+ inline else => |impl| return impl.addConst(pt, index, val),
+ }
+ }
+
+ /// Tell the debug info implementation to emit information for the constant `val`, which is in
+ /// the pool at the given index. `val` is "complete", which means:
+ /// * If it is a type, its layout is known.
+ /// * Otherwise, the layout of its type is known.
+ fn updateConst(
+ di: DebugInfo,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) !void {
+ switch (di) {
+ inline else => |impl| return impl.updateConst(pt, index, val),
+ }
+ }
+
+ /// Tell the debug info implementation to emit information for the constant `val`, which is in
+ /// the pool at the given index. `val` is "incomplete", meaning the implementation cannot emit
+ /// full information for it (for instance, perhaps it is a struct type which was never actually
+ /// initialized so never had its layout resolved). Instead, the implementation must emit some
+ /// form of placeholder entry representing an incomplete/unknown constant.
+ fn updateConstIncomplete(
+ di: DebugInfo,
+ pt: Zcu.PerThread,
+ index: Index,
+ val: InternPool.Index,
+ ) !void {
+ switch (di) {
+ inline else => |impl| return impl.updateConstIncomplete(pt, index, val),
+ }
+ }
+};
+
+const ContainerDepEntry = extern struct {
+ next: ContainerDepEntry.Index.Optional,
+ depender: DebugConstPool.Index,
+ const Index = enum(u32) {
+ _,
+ const Optional = enum(u32) {
+ none = std.math.maxInt(u32),
+ _,
+ fn unwrap(o: Optional) ?ContainerDepEntry.Index {
+ return switch (o) {
+ .none => null,
+ else => @enumFromInt(@intFromEnum(o)),
+ };
+ }
+ };
+ fn toOptional(i: ContainerDepEntry.Index) Optional {
+ return @enumFromInt(@intFromEnum(i));
+ }
+ fn ptr(i: ContainerDepEntry.Index, pool: *DebugConstPool) *ContainerDepEntry {
+ return &pool.container_dep_entries.items[@intFromEnum(i)];
+ }
+ };
+};
+
+/// Calls to `link.File.updateContainerType` must be forwarded to this function so that the debug
+/// constant pool has up-to-date information about the resolution status of types.
+pub fn updateContainerType(
+ pool: *DebugConstPool,
+ pt: Zcu.PerThread,
+ di: DebugInfo,
+ container_ty: InternPool.Index,
+ success: bool,
+) !void {
+ if (success) {
+ const gpa = pt.zcu.comp.gpa;
+ try pool.complete_containers.put(gpa, container_ty, {});
+ } else {
+ _ = pool.complete_containers.fetchSwapRemove(container_ty);
+ }
+ var opt_dep = pool.container_deps.get(container_ty);
+ while (opt_dep) |dep| : (opt_dep = dep.ptr(pool).next.unwrap()) {
+ try pool.update(pt, di, dep.ptr(pool).depender);
+ }
+}
+
+/// After this is called, there may be a constant for which debug information (complete or not) has
+/// not yet been emitted, so the user must call `flushPending` at some point after this call.
+pub fn get(pool: *DebugConstPool, pt: Zcu.PerThread, di: DebugInfo, val: InternPool.Index) !DebugConstPool.Index {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.comp.gpa;
+ const gop = try pool.values.getOrPut(gpa, val);
+ const index: DebugConstPool.Index = @enumFromInt(gop.index);
+ if (!gop.found_existing) {
+ const ty: Type = switch (ip.typeOf(val)) {
+ .type_type => if (ip.isUndef(val)) .type else .fromInterned(val),
+ else => |ty| .fromInterned(ty),
+ };
+ try pool.registerTypeDeps(index, ty, zcu);
+ try pool.pending.append(gpa, index);
+ try di.addConst(pt, index, val);
+ }
+ return index;
+}
+pub fn flushPending(pool: *DebugConstPool, pt: Zcu.PerThread, di: DebugInfo) !void {
+ while (pool.pending.pop()) |pending_ty| {
+ try pool.update(pt, di, pending_ty);
+ }
+}
+
+fn update(pool: *DebugConstPool, pt: Zcu.PerThread, di: DebugInfo, index: DebugConstPool.Index) !void {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const val = index.val(pool);
+ const ty: Type = switch (ip.typeOf(val)) {
+ .type_type => if (ip.isUndef(val)) .type else .fromInterned(val),
+ else => |ty| .fromInterned(ty),
+ };
+ if (pool.checkType(ty, zcu)) {
+ try di.updateConst(pt, index, val);
+ } else {
+ try di.updateConstIncomplete(pt, index, val);
+ }
+}
+fn checkType(pool: *const DebugConstPool, ty: Type, zcu: *const Zcu) bool {
+ if (ty.isGenericPoison()) return true;
+ return switch (ty.zigTypeTag(zcu)) {
+ .type,
+ .void,
+ .bool,
+ .noreturn,
+ .int,
+ .float,
+ .pointer,
+ .comptime_float,
+ .comptime_int,
+ .undefined,
+ .null,
+ .error_set,
+ .@"opaque",
+ .frame,
+ .@"anyframe",
+ .enum_literal,
+ => true,
+
+ .array, .vector => pool.checkType(ty.childType(zcu), zcu),
+ .optional => pool.checkType(ty.optionalChild(zcu), zcu),
+ .error_union => pool.checkType(ty.errorUnionPayload(zcu), zcu),
+ .@"fn" => {
+ const ip = &zcu.intern_pool;
+ const func = ip.indexToKey(ty.toIntern()).func_type;
+ for (func.param_types.get(ip)) |param_ty_ip| {
+ if (!pool.checkType(.fromInterned(param_ty_ip), zcu)) return false;
+ }
+ return pool.checkType(.fromInterned(func.return_type), zcu);
+ },
+ .@"struct" => if (ty.isTuple(zcu)) {
+ for (0..ty.structFieldCount(zcu)) |field_index| {
+ if (!pool.checkType(ty.fieldType(field_index, zcu), zcu)) return false;
+ }
+ return true;
+ } else {
+ return pool.complete_containers.contains(ty.toIntern());
+ },
+ .@"union", .@"enum" => {
+ return pool.complete_containers.contains(ty.toIntern());
+ },
+ };
+}
+fn registerTypeDeps(pool: *DebugConstPool, root: Index, ty: Type, zcu: *const Zcu) Allocator.Error!void {
+ if (ty.isGenericPoison()) return;
+ switch (ty.zigTypeTag(zcu)) {
+ .type,
+ .void,
+ .bool,
+ .noreturn,
+ .int,
+ .float,
+ .pointer,
+ .comptime_float,
+ .comptime_int,
+ .undefined,
+ .null,
+ .error_set,
+ .@"opaque",
+ .frame,
+ .@"anyframe",
+ .enum_literal,
+ => {},
+
+ .array, .vector => try pool.registerTypeDeps(root, ty.childType(zcu), zcu),
+ .optional => try pool.registerTypeDeps(root, ty.optionalChild(zcu), zcu),
+ .error_union => try pool.registerTypeDeps(root, ty.errorUnionPayload(zcu), zcu),
+ .@"fn" => {
+ const ip = &zcu.intern_pool;
+ const func = ip.indexToKey(ty.toIntern()).func_type;
+ for (func.param_types.get(ip)) |param_ty_ip| {
+ try pool.registerTypeDeps(root, .fromInterned(param_ty_ip), zcu);
+ }
+ try pool.registerTypeDeps(root, .fromInterned(func.return_type), zcu);
+ },
+ .@"struct", .@"union", .@"enum" => if (ty.isTuple(zcu)) {
+ for (0..ty.structFieldCount(zcu)) |field_index| {
+ try pool.registerTypeDeps(root, ty.fieldType(field_index, zcu), zcu);
+ }
+ } else {
+ // `ty` is a container; register the dependency.
+
+ const gpa = zcu.comp.gpa;
+ try pool.container_deps.ensureUnusedCapacity(gpa, 1);
+ try pool.container_dep_entries.ensureUnusedCapacity(gpa, 1);
+ errdefer comptime unreachable;
+
+ const gop = pool.container_deps.getOrPutAssumeCapacity(ty.toIntern());
+ const entry: ContainerDepEntry.Index = @enumFromInt(pool.container_dep_entries.items.len);
+ pool.container_dep_entries.appendAssumeCapacity(.{
+ .next = if (gop.found_existing) gop.value_ptr.toOptional() else .none,
+ .depender = root,
+ });
+ gop.value_ptr.* = entry;
+ },
+ }
+}
+
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+
+const InternPool = @import("../InternPool.zig");
+const Type = @import("../Type.zig");
+const Zcu = @import("../Zcu.zig");
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
@@ -18,6 +18,7 @@ const codegen = @import("../codegen.zig");
const dev = @import("../dev.zig");
const link = @import("../link.zig");
const target_info = @import("../target.zig");
+const DebugConstPool = @import("DebugConstPool.zig");
gpa: Allocator,
bin_file: *link.File,
@@ -25,9 +26,11 @@ format: DW.Format,
endian: std.builtin.Endian,
address_size: AddressSize,
+const_pool: DebugConstPool,
+
mods: std.AutoArrayHashMapUnmanaged(*Module, ModInfo),
-types: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
-values: std.AutoArrayHashMapUnmanaged(InternPool.Index, Entry.Index),
+/// Indices are `DebugConstPool.Index`.
+values: std.ArrayList(struct { Unit.Index, Entry.Index }),
navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Entry.Index),
decls: std.AutoArrayHashMapUnmanaged(InternPool.TrackedInst.Index, Entry.Index),
@@ -1034,15 +1037,14 @@ const Entry = struct {
});
const zcu = dwarf.bin_file.comp.zcu.?;
const ip = &zcu.intern_pool;
- for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
- const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
- dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?) catch unreachable
- else
- .main;
- if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
- log.err("missing Type({f}({d}))", .{
- Type.fromInterned(ty).fmt(.{ .tid = .main, .zcu = zcu }),
- @intFromEnum(ty),
+ for (0.., dwarf.values.items) |raw_index, unit_and_entry| {
+ const index: DebugConstPool.Index = @enumFromInt(raw_index);
+ const val = index.val(&dwarf.const_pool);
+ const val_unit, const val_entry = unit_and_entry;
+ if (sec.getUnit(val_unit) == unit and unit.getEntry(val_entry) == entry)
+ log.err("missing Value({f}({d}))", .{
+ Value.fromInterned(val).fmtValue(.{ .tid = .main, .zcu = zcu }),
+ @intFromEnum(val),
});
}
for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
@@ -1520,7 +1522,6 @@ pub const WipNav = struct {
debug_info: Writer.Allocating,
debug_line: Writer.Allocating,
debug_loclists: Writer.Allocating,
- pending_lazy: PendingLazy,
pub fn deinit(wip_nav: *WipNav) void {
const gpa = wip_nav.dwarf.gpa;
@@ -1529,8 +1530,6 @@ pub const WipNav = struct {
wip_nav.debug_info.deinit();
wip_nav.debug_line.deinit();
wip_nav.debug_loclists.deinit();
- wip_nav.pending_lazy.types.deinit(gpa);
- wip_nav.pending_lazy.values.deinit(gpa);
}
pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void {
@@ -1945,6 +1944,12 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_str, StringSection.unit, try wip_nav.dwarf.debug_str.addString(wip_nav.dwarf, str), 0);
}
+ fn strpFmt(wip_nav: *WipNav, comptime fmt: []const u8, args: anytype) (UpdateError || Writer.Error)!void {
+ const str = try std.fmt.allocPrint(wip_nav.dwarf.gpa, fmt, args);
+ defer wip_nav.dwarf.gpa.free(str);
+ return wip_nav.strp(str);
+ }
+
const ExprLocCounter = struct {
dw: Writer.Discarding,
section_offset_bytes: u32,
@@ -2054,74 +2059,16 @@ pub const WipNav = struct {
try dfw.splatByteAll(0, @intFromEnum(wip_nav.dwarf.address_size));
}
- fn getNavEntry(
- wip_nav: *WipNav,
- nav_index: InternPool.Nav.Index,
- ) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const nav = ip.getNav(nav_index);
- const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
- const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- return .{ unit, entry };
- }
-
fn refNav(
wip_nav: *WipNav,
nav_index: InternPool.Nav.Index,
) (UpdateError || Writer.Error)!void {
- const unit, const entry = try wip_nav.getNavEntry(nav_index);
+ const unit, const entry = try wip_nav.dwarf.getNavEntry(nav_index);
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
- fn getTypeEntry(wip_nav: *WipNav, ty: Type) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const maybe_inst_index = ty.typeDeclInst(zcu);
- const unit = if (maybe_inst_index) |inst_index| switch (switch (ip.indexToKey(ty.toIntern())) {
- else => unreachable,
- .struct_type => ip.loadStructType(ty.toIntern()).name_nav,
- .union_type => ip.loadUnionType(ty.toIntern()).name_nav,
- .enum_type => ip.loadEnumType(ty.toIntern()).name_nav,
- .opaque_type => ip.loadOpaqueType(ty.toIntern()).name_nav,
- }) {
- .none => try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?),
- else => |name_nav| return wip_nav.getNavEntry(name_nav.unwrap().?),
- } else .main;
- const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- if (maybe_inst_index == null) try wip_nav.pending_lazy.types.append(wip_nav.dwarf.gpa, ty.toIntern());
- return .{ unit, entry };
- }
-
fn refType(wip_nav: *WipNav, ty: Type) (UpdateError || Writer.Error)!void {
- const unit, const entry = try wip_nav.getTypeEntry(ty);
- try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
- }
-
- fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
- const zcu = wip_nav.pt.zcu;
- const ip = &zcu.intern_pool;
- const ty = value.typeOf(zcu);
- if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu));
- if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
- if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
- else => unreachable,
- .func => |func| func.owner_nav,
- .@"extern" => |@"extern"| @"extern".owner_nav,
- });
- const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());
- const unit: Unit.Index = .main;
- if (gop.found_existing) return .{ unit, gop.value_ptr.* };
- const entry = try wip_nav.dwarf.addCommonEntry(unit);
- gop.value_ptr.* = entry;
- try wip_nav.pending_lazy.values.append(wip_nav.dwarf.gpa, value.toIntern());
- return .{ unit, entry };
+ return wip_nav.refValue(ty.toValue());
}
fn refValue(wip_nav: *WipNav, value: Value) (UpdateError || Writer.Error)!void {
@@ -2129,6 +2076,15 @@ pub const WipNav = struct {
try wip_nav.infoSectionOffset(.debug_info, unit, entry, 0);
}
+ fn getValueEntry(wip_nav: *WipNav, value: Value) UpdateError!struct { Unit.Index, Entry.Index } {
+ if (value.typeOf(wip_nav.pt.zcu).toIntern() != .type_type) {
+ assert(value.typeOf(wip_nav.pt.zcu).comptimeOnly(wip_nav.pt.zcu));
+ }
+ const dwarf = wip_nav.dwarf;
+ const index = try dwarf.const_pool.get(wip_nav.pt, .{ .dwarf = dwarf }, value.toIntern());
+ return dwarf.values.items[@intFromEnum(index)];
+ }
+
fn refForward(wip_nav: *WipNav) (Allocator.Error || Writer.Error)!u32 {
const dwarf = wip_nav.dwarf;
const diw = &wip_nav.debug_info.writer;
@@ -2156,7 +2112,7 @@ pub const WipNav = struct {
) (UpdateError || Writer.Error)!void {
const ty = val.typeOf(wip_nav.pt.zcu);
const diw = &wip_nav.debug_info.writer;
- const size = if (ty.hasRuntimeBits(wip_nav.pt.zcu)) ty.abiSize(wip_nav.pt.zcu) else 0;
+ const size = ty.abiSize(wip_nav.pt.zcu);
try diw.writeUleb128(size);
if (size == 0) return;
const old_end = wip_nav.debug_info.writer.end;
@@ -2331,22 +2287,6 @@ pub const WipNav = struct {
try wip_nav.refType(parent_type.?);
try wip_nav.infoSectionOffset(.debug_info, wip_nav.unit, generic_decl_entry, 0);
}
-
- const PendingLazy = struct {
- types: std.ArrayList(InternPool.Index),
- values: std.ArrayList(InternPool.Index),
-
- const empty: PendingLazy = .{ .types = .empty, .values = .empty };
- };
-
- fn updateLazy(wip_nav: *WipNav, src_loc: Zcu.LazySrcLoc) (UpdateError || Writer.Error)!void {
- while (true) if (wip_nav.pending_lazy.types.pop()) |pending_ty|
- try wip_nav.dwarf.updateLazyType(wip_nav.pt, src_loc, pending_ty, &wip_nav.pending_lazy)
- else if (wip_nav.pending_lazy.values.pop()) |pending_val|
- try wip_nav.dwarf.updateLazyValue(wip_nav.pt, src_loc, pending_val, &wip_nav.pending_lazy)
- else
- break;
- }
};
/// When allocating, the ideal_capacity is calculated by
@@ -2372,8 +2312,9 @@ pub fn init(lf: *link.File, format: DW.Format) Dwarf {
},
.endian = target.cpu.arch.endian(),
+ .const_pool = .empty,
+
.mods = .empty,
- .types = .empty,
.values = .empty,
.navs = .empty,
.decls = .empty,
@@ -2544,9 +2485,9 @@ pub fn initMetadata(dwarf: *Dwarf) UpdateError!void {
pub fn deinit(dwarf: *Dwarf) void {
const gpa = dwarf.gpa;
+ dwarf.const_pool.deinit(gpa);
for (dwarf.mods.values()) |*mod_info| mod_info.deinit(gpa);
dwarf.mods.deinit(gpa);
- dwarf.types.deinit(gpa);
dwarf.values.deinit(gpa);
dwarf.navs.deinit(gpa);
dwarf.decls.deinit(gpa);
@@ -2562,6 +2503,21 @@ pub fn deinit(dwarf: *Dwarf) void {
dwarf.* = undefined;
}
+fn getNavEntry(
+ dwarf: *Dwarf,
+ nav_index: InternPool.Nav.Index,
+) UpdateError!struct { Unit.Index, Entry.Index } {
+ const zcu = dwarf.bin_file.comp.zcu.?;
+ const ip = &zcu.intern_pool;
+ const nav = ip.getNav(nav_index);
+ const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?);
+ const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
+ if (gop.found_existing) return .{ unit, gop.value_ptr.* };
+ const entry = try dwarf.addCommonEntry(unit);
+ gop.value_ptr.* = entry;
+ return .{ unit, entry };
+}
+
fn getUnit(dwarf: *Dwarf, mod: *Module) !Unit.Index {
const mod_gop = try dwarf.mods.getOrPut(dwarf.gpa, mod);
const unit: Unit.Index = @enumFromInt(mod_gop.index);
@@ -2622,6 +2578,10 @@ fn getModInfo(dwarf: *Dwarf, unit: Unit.Index) *ModInfo {
return &dwarf.mods.values()[@intFromEnum(unit)];
}
+fn getUnitModule(dwarf: *Dwarf, unit: Unit.Index) *Module {
+ return dwarf.mods.keys()[@intFromEnum(unit)];
+}
+
pub fn initWipNav(
dwarf: *Dwarf,
pt: Zcu.PerThread,
@@ -2683,7 +2643,6 @@ fn initWipNavInner(
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
};
errdefer wip_nav.deinit();
@@ -3050,7 +3009,7 @@ fn finishWipNavWriterError(
}
try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
- try wip_nav.updateLazy(zcu.navSrcLoc(nav_index));
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
pub fn updateComptimeNav(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{ OutOfMemory, CodegenFail }!void {
@@ -3087,34 +3046,12 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
return;
}
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = try dwarf.getUnit(file.mod.?),
- .entry = undefined,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
-
- const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
- errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
-
const tag: union(enum) {
- done,
- decl_alias,
- decl_var,
- decl_const,
- decl_func_alias: InternPool.Nav.Index,
+ alias,
+ @"var",
+ @"const",
+ func: Type,
+ func_alias: InternPool.Nav.Index,
} = switch (ip.indexToKey(nav_val.toIntern())) {
.int_type,
.ptr_type,
@@ -3128,242 +3065,49 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.func_type,
.error_set_type,
.inferred_error_set_type,
- => .decl_alias,
+ => .alias,
+
.struct_type => tag: {
const loaded_struct = ip.loadStructType(nav_val.toIntern());
- if (loaded_struct.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
- }
- wip_nav.entry = nav_gop.value_ptr.*;
-
- const diw = &wip_nav.debug_info.writer;
-
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
- .decl = .decl_namespace_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_namespace_struct,
- } else .{
- .decl = .decl_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_struct,
- }, &nav, inst_info.file, &decl);
- if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
- try diw.writeUleb128(nav_val.toType().abiSize(zcu));
- try diw.writeUleb128(nav_val.toType().abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
- const field_init = loaded_struct.field_defaults.getOrNone(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu),
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(nav_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- },
- .@"packed" => {
- try wip_nav.declCommon(.{
- .decl = .decl_packed_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_packed_struct,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
- var field_bit_offset: u16 = 0;
- for (0..loaded_struct.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.packed_struct_field);
- try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(field_bit_offset);
- field_bit_offset += @intCast(field_type.bitSize(zcu));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
+ if (nav_index.toOptional() == loaded_struct.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- break :tag .done;
+ break :tag .alias;
},
.enum_type => tag: {
const loaded_enum = ip.loadEnumType(nav_val.toIntern());
- const type_zir_index = loaded_enum.zir_index.unwrap() orelse break :tag .decl_alias;
- if (type_zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
- }
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
- .decl = .decl_enum,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_enum,
- } else .{
- .decl = .decl_empty_enum,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_empty_enum,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
- for (0..loaded_enum.field_names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ if (nav_index.toOptional() == loaded_enum.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- break :tag .done;
+ break :tag .alias;
},
.union_type => tag: {
const loaded_union = ip.loadUnionType(nav_val.toIntern());
- if (loaded_union.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
- }
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(.{
- .decl = .decl_union,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_union,
- }, &nav, inst_info.file, &decl);
- const union_layout = Type.getUnionLayout(loaded_union, zcu);
- try diw.writeUleb128(union_layout.abi_size);
- try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
- const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
- if (loaded_union.has_runtime_tag) {
- try wip_nav.abbrevCode(.tagged_union);
- try wip_nav.infoSectionOffset(
- .debug_info,
- wip_nav.unit,
- wip_nav.entry,
- @intCast(diw.end + dwarf.sectionOffsetBytes()),
- );
- {
- try wip_nav.abbrevCode(.generated_field);
- try wip_nav.strp("tag");
- try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
- try diw.writeUleb128(union_layout.tagOffset());
-
- for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.enumConstValue(loaded_tag, .{
- .sdata = .signed_tagged_union_field,
- .udata = .unsigned_tagged_union_field,
- .block = .big_tagged_union_field,
- }, field_index);
- {
- try wip_nav.abbrevCode(.struct_field);
- try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(union_layout.payloadOffset());
- try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- } else for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.untagged_union_field);
- try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
+ if (nav_index.toOptional() == loaded_union.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- break :tag .done;
+ break :tag .alias;
},
.opaque_type => tag: {
const loaded_opaque = ip.loadOpaqueType(nav_val.toIntern());
- if (loaded_opaque.zir_index.resolveFile(ip) != inst_info.file) break :tag .decl_alias;
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, nav_val.toIntern());
- if (type_gop.found_existing) {
- if (dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(type_gop.value_ptr.*).len > 0) break :tag .decl_alias;
- assert(!nav_gop.found_existing);
- nav_gop.value_ptr.* = type_gop.value_ptr.*;
- } else {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- type_gop.value_ptr.* = nav_gop.value_ptr.*;
+ if (nav_index.toOptional() == loaded_opaque.name_nav) {
+ // This Nav's entry is populated by the type, not the actual Nav.
+ _ = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, nav_val.toIntern());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
+ return;
}
- wip_nav.entry = nav_gop.value_ptr.*;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(.{
- .decl = .decl_namespace_struct,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_namespace_struct,
- }, &nav, inst_info.file, &decl);
- try diw.writeByte(@intFromBool(true));
- break :tag .done;
+ break :tag .alias;
},
+
.undef,
.simple_value,
.int,
@@ -3378,72 +3122,77 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
.aggregate,
.un,
.bitpack,
- => .decl_const,
- .variable => .decl_var,
+ => .@"const",
+
+ .variable => .@"var",
+
.@"extern" => unreachable,
- .func => |func| tag: {
- if (func.owner_nav != nav_index) break :tag .{ .decl_func_alias = func.owner_nav };
- if (nav_gop.found_existing) switch (try dwarf.debug_info.declAbbrevCode(wip_nav.unit, nav_gop.value_ptr.*)) {
- .null => {},
- else => unreachable,
- .decl_nullary_func, .decl_func, .decl_instance_nullary_func, .decl_instance_func => return,
- .decl_nullary_func_generic,
- .decl_func_generic,
- .decl_instance_nullary_func_generic,
- .decl_instance_func_generic,
- => dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear(),
- } else nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- wip_nav.entry = nav_gop.value_ptr.*;
- const func_type = ip.indexToKey(func.ty).func_type;
- const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
- if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
- } else true;
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.declCommon(if (is_nullary) .{
- .decl = .decl_nullary_func_generic,
- .generic_decl = .generic_decl_func,
- .decl_instance = .decl_instance_nullary_func_generic,
- } else .{
- .decl = .decl_func_generic,
- .generic_decl = .generic_decl_func,
- .decl_instance = .decl_instance_func_generic,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(.fromInterned(func_type.return_type));
- if (!is_nullary) {
- for (0..func_type.param_types.len) |param_index| {
- if (std.math.cast(u5, param_index)) |small_param_index|
- if (func_type.paramIsComptime(small_param_index)) continue;
- try wip_nav.abbrevCode(.func_type_param);
- try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
- }
- if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- break :tag .done;
+ .func => |func| tag: {
+ if (func.owner_nav != nav_index) break :tag .{ .func_alias = func.owner_nav };
+ break :tag .{ .func = .fromInterned(func.ty) };
},
+
// memoization, not types
.memoized_call => unreachable,
};
- if (tag != .done) {
- if (nav_gop.found_existing)
- dwarf.debug_info.section.getUnit(wip_nav.unit).getEntry(nav_gop.value_ptr.*).clear()
- else
- nav_gop.value_ptr.* = try dwarf.addCommonEntry(wip_nav.unit);
- wip_nav.entry = nav_gop.value_ptr.*;
+
+ const unit = try dwarf.getUnit(file.mod.?);
+
+ const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
+ errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
+
+ if (nav_gop.found_existing) {
+ if (tag == .func) switch (try dwarf.debug_info.declAbbrevCode(unit, nav_gop.value_ptr.*)) {
+ else => unreachable,
+
+ .decl_nullary_func,
+ .decl_func,
+ .decl_instance_nullary_func,
+ .decl_instance_func,
+ => return,
+
+ .null,
+ .decl_nullary_func_generic,
+ .decl_func_generic,
+ .decl_instance_nullary_func_generic,
+ .decl_instance_func_generic,
+ => {},
+ };
+ dwarf.debug_info.section.getUnit(unit).getEntry(nav_gop.value_ptr.*).clear();
+ } else {
+ nav_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
}
- switch (tag) {
- .done => {},
- .decl_alias => {
- try wip_nav.declCommon(.{
- .decl = .decl_alias,
- .generic_decl = .generic_decl_const,
- .decl_instance = .decl_instance_alias,
- }, &nav, inst_info.file, &decl);
- try wip_nav.refType(nav_val.toType());
- },
- .decl_var => {
- const diw = &wip_nav.debug_info.writer;
+
+ var wip_nav: WipNav = .{
+ .dwarf = dwarf,
+ .pt = pt,
+ .unit = unit,
+ .entry = nav_gop.value_ptr.*,
+ .any_children = false,
+ .func = .none,
+ .func_sym_index = undefined,
+ .func_high_pc = undefined,
+ .blocks = undefined,
+ .cfi = undefined,
+ .debug_frame = .init(dwarf.gpa),
+ .debug_info = .init(dwarf.gpa),
+ .debug_line = .init(dwarf.gpa),
+ .debug_loclists = .init(dwarf.gpa),
+ };
+ defer wip_nav.deinit();
+ const diw = &wip_nav.debug_info.writer;
+
+ switch (tag) {
+ .alias => {
+ try wip_nav.declCommon(.{
+ .decl = .decl_alias,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_alias,
+ }, &nav, inst_info.file, &decl);
+ try wip_nav.refType(nav_val.toType());
+ },
+ .@"var" => {
try wip_nav.declCommon(.{
.decl = .decl_var,
.generic_decl = .generic_decl_var,
@@ -3460,8 +3209,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
nav_ty.abiAlignment(zcu).toByteUnits().?);
try diw.writeByte(@intFromBool(decl.linkage != .normal));
},
- .decl_const => {
- const diw = &wip_nav.debug_info.writer;
+ .@"const" => {
const nav_ty = nav_val.typeOf(zcu);
const has_runtime_bits = nav_ty.hasRuntimeBits(zcu);
const has_comptime_state = nav_ty.comptimeOnly(zcu);
@@ -3496,7 +3244,33 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
try wip_nav.abbrevCode(.is_const);
try wip_nav.refType(nav_ty);
},
- .decl_func_alias => |owner_nav| {
+ .func => |func_ty| {
+ const func_type = ip.indexToKey(func_ty.toIntern()).func_type;
+ const is_nullary = !func_type.is_var_args and for (0..func_type.param_types.len) |param_index| {
+ if (!func_type.paramIsComptime(std.math.cast(u5, param_index) orelse break false)) break false;
+ } else true;
+ try wip_nav.declCommon(if (is_nullary) .{
+ .decl = .decl_nullary_func_generic,
+ .generic_decl = .generic_decl_func,
+ .decl_instance = .decl_instance_nullary_func_generic,
+ } else .{
+ .decl = .decl_func_generic,
+ .generic_decl = .generic_decl_func,
+ .decl_instance = .decl_instance_func_generic,
+ }, &nav, inst_info.file, &decl);
+ try wip_nav.refType(.fromInterned(func_type.return_type));
+ if (!is_nullary) {
+ for (0..func_type.param_types.len) |param_index| {
+ if (std.math.cast(u5, param_index)) |small_param_index|
+ if (func_type.paramIsComptime(small_param_index)) continue;
+ try wip_nav.abbrevCode(.func_type_param);
+ try wip_nav.refType(.fromInterned(func_type.param_types.get(ip)[param_index]));
+ }
+ if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ },
+ .func_alias => |owner_nav| {
try wip_nav.declCommon(.{
.decl = .decl_alias,
.generic_decl = .generic_decl_const,
@@ -3505,31 +3279,81 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
try wip_nav.refNav(owner_nav);
},
}
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(nav_src_loc);
+ try dwarf.debug_info.section.replaceEntry(unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
-fn updateLazyType(
+pub fn updateContainerType(
dwarf: *Dwarf,
pt: Zcu.PerThread,
- src_loc: Zcu.LazySrcLoc,
- type_index: InternPool.Index,
- pending_lazy: *WipNav.PendingLazy,
-) (UpdateError || Writer.Error)!void {
+ ty: InternPool.Index,
+ success: bool,
+) !void {
+ try dwarf.const_pool.updateContainerType(pt, .{ .dwarf = dwarf }, ty, success);
+}
+/// Should only be called by the `DebugConstPool` implementation.
+pub fn addConst(dwarf: *Dwarf, pt: Zcu.PerThread, index: DebugConstPool.Index, val: InternPool.Index) !void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- assert(ip.typeOf(type_index) == .type_type);
- const ty: Type = .fromInterned(type_index);
- switch (type_index) {
- .generic_poison_type => log.debug("updateLazyType({s})", .{"anytype"}),
- else => log.debug("updateLazyType({f})", .{ty.fmt(pt)}),
+
+ const unit: Unit.Index, const entry: Entry.Index = switch (ip.indexToKey(val)) {
+ else => .{ .main, try dwarf.addCommonEntry(.main) },
+ .func => |func| try dwarf.getNavEntry(func.owner_nav),
+ .@"extern" => |@"extern"| try dwarf.getNavEntry(@"extern".owner_nav),
+ .struct_type, .union_type, .enum_type, .opaque_type => |_, tag| entry: {
+ const name_nav = switch (tag) {
+ .struct_type => ip.loadStructType(val).name_nav,
+ .union_type => ip.loadUnionType(val).name_nav,
+ .enum_type => ip.loadEnumType(val).name_nav,
+ .opaque_type => ip.loadOpaqueType(val).name_nav,
+ else => unreachable,
+ };
+ if (name_nav.unwrap()) |nav| {
+ break :entry try dwarf.getNavEntry(nav);
+ } else {
+ const zir_index = Type.fromInterned(val).typeDeclInstAllowGeneratedTag(zcu).?;
+ const unit = try dwarf.getUnit(zcu.fileByIndex(zir_index.resolveFile(ip)).mod.?);
+ break :entry .{ unit, try dwarf.addCommonEntry(unit) };
+ }
+ },
+ };
+
+ assert(@intFromEnum(index) == dwarf.values.items.len);
+ try dwarf.values.append(dwarf.gpa, .{ unit, entry });
+}
+/// Should only be called by the `DebugConstPool` implementation.
+///
+/// Emits a "dummy" DIE for the given comptime-only value (which may be a type). For types, this is
+/// an opaque type. Otherwise, it is an undefined value of the value's type.
+pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: DebugConstPool.Index, value_index: InternPool.Index) !void {
+ const zcu = pt.zcu;
+
+ const val: Value = .fromInterned(value_index);
+
+ switch (value_index) {
+ .generic_poison_type => log.debug("updateValueIncomplete(anytype)", .{}),
+ else => log.debug("updateValueIncomplete(@as({f}, {f}))", .{
+ val.typeOf(zcu).fmt(pt),
+ val.fmtValue(pt),
+ }),
}
+ const unit, const entry = dwarf.values.items[@intFromEnum(debug_const_index)];
+
+ for ([_]*Section{
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_info.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sec| sec.getUnit(unit).getEntry(entry).clear();
+
var wip_nav: WipNav = .{
.dwarf = dwarf,
.pt = pt,
- .unit = .main,
- .entry = dwarf.types.get(type_index).?,
+ .unit = unit,
+ .entry = entry,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
@@ -3540,43 +3364,119 @@ fn updateLazyType(
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = pending_lazy.*,
};
- defer {
- pending_lazy.* = wip_nav.pending_lazy;
- wip_nav.pending_lazy = .empty;
- wip_nav.deinit();
+ defer wip_nav.deinit();
+ switch (val.typeOf(zcu).toIntern()) {
+ .type_type => {
+ try wip_nav.abbrevCode(.generated_empty_struct_type);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
+ },
+ else => |ty| {
+ try wip_nav.abbrevCode(.undefined_comptime_value);
+ try wip_nav.refType(.fromInterned(ty));
+ },
}
- const diw = &wip_nav.debug_info.writer;
- const name = switch (type_index) {
- .generic_poison_type => "",
- else => try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)}),
+ try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
+}
+/// Should only be called by the `DebugConstPool` implementation.
+///
+/// Emits a DIE for the given comptime-only value (which may be a type).
+pub fn updateConst(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: DebugConstPool.Index, value_index: InternPool.Index) !void {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+
+ const val: Value = .fromInterned(value_index);
+
+ if (val.typeOf(zcu).toIntern() == .type_type and !val.isUndef(zcu)) {
+ val.toType().assertHasLayout(zcu);
+ } else {
+ val.typeOf(zcu).assertHasLayout(zcu);
+ }
+
+ const value_ip_key = ip.indexToKey(value_index);
+ switch (value_ip_key) {
+ .func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`)
+ .@"extern" => return, // populated by the Nav instead (`initWipNav`)
+ else => {},
+ }
+
+ switch (value_index) {
+ .generic_poison_type => log.debug("updateValue(anytype)", .{}),
+ else => log.debug("updateValue(@as({f}, {f}))", .{
+ val.typeOf(zcu).fmt(pt),
+ val.fmtValue(pt),
+ }),
+ }
+
+ const unit, const entry = dwarf.values.items[@intFromEnum(debug_const_index)];
+
+ for ([_]*Section{
+ &dwarf.debug_aranges.section,
+ &dwarf.debug_info.section,
+ &dwarf.debug_line.section,
+ &dwarf.debug_loclists.section,
+ &dwarf.debug_rnglists.section,
+ }) |sec| sec.getUnit(unit).getEntry(entry).clear();
+
+ var wip_nav: WipNav = .{
+ .dwarf = dwarf,
+ .pt = pt,
+ .unit = unit,
+ .entry = entry,
+ .any_children = false,
+ .func = .none,
+ .func_sym_index = undefined,
+ .func_high_pc = undefined,
+ .blocks = undefined,
+ .cfi = undefined,
+ .debug_frame = .init(dwarf.gpa),
+ .debug_info = .init(dwarf.gpa),
+ .debug_line = .init(dwarf.gpa),
+ .debug_loclists = .init(dwarf.gpa),
};
- defer dwarf.gpa.free(name);
+ defer wip_nav.deinit();
+
+ // TODO: we really shouldn't need source locations at this point in the pipeline: we've lost
+ // that information by now. If the linker fundamentally cannot lower certain values, that needs
+ // to be caught in the frontend; if it can only hit transient failures, they should be reported
+ // without trying to tie them to a bogus source location.
+ const src_loc: Zcu.LazySrcLoc = .{
+ .base_node_inst = inst: {
+ const mod_root_file_index = zcu.module_roots.get(dwarf.getUnitModule(unit)).?.unwrap().?;
+ const mod_root_type_index = zcu.fileRootType(mod_root_file_index);
+ break :inst ip.loadStructType(mod_root_type_index).zir_index;
+ },
+ .offset = .{ .byte_abs = 0 },
+ };
+
+ const diw = &wip_nav.debug_info.writer;
+ var big_int_space: Value.BigIntSpace = undefined;
+ switch (value_ip_key) {
+ .func => unreachable, // handled above
+ .@"extern" => unreachable, // handled above
- switch (ip.indexToKey(type_index)) {
- .undef => {
- try wip_nav.abbrevCode(.undefined_comptime_value);
- try wip_nav.refType(.type);
- },
.int_type => |int_type| {
try wip_nav.abbrevCode(.numeric_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try diw.writeByte(switch (int_type.signedness) {
inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
});
try diw.writeUleb128(int_type.bits);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
},
.ptr_type => |ptr_type| switch (ptr_type.flags.size) {
.one, .many, .c => {
const ptr_child_type: Type = .fromInterned(ptr_type.child);
- try wip_nav.abbrevCode(if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type);
- try wip_nav.strp(name);
+ try wip_nav.abbrevCode(switch (ptr_type.flags.alignment) {
+ .none => if (ptr_type.sentinel == .none) .ptr_type else .ptr_sentinel_type,
+ else => if (ptr_type.sentinel == .none) .ptr_aligned_type else .ptr_aligned_sentinel_type,
+ });
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (ptr_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(ptr_type.sentinel));
- try diw.writeUleb128(ptr_type.flags.alignment.toByteUnits() orelse
- ptr_child_type.abiAlignment(zcu).toByteUnits().?);
+ if (ptr_type.flags.alignment.toByteUnits()) |a| try diw.writeUleb128(a);
try diw.writeByte(@intFromEnum(ptr_type.flags.address_space));
if (ptr_type.flags.is_const or ptr_type.flags.is_volatile) try wip_nav.infoSectionOffset(
.debug_info,
@@ -3600,12 +3500,12 @@ fn updateLazyType(
},
.slice => {
try wip_nav.abbrevCode(.generated_struct_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
try wip_nav.abbrevCode(.generated_field);
try wip_nav.strp("ptr");
- const ptr_field_type = ty.slicePtrFieldType(zcu);
+ const ptr_field_type = val.toType().slicePtrFieldType(zcu);
try wip_nav.refType(ptr_field_type);
try diw.writeUleb128(0);
try wip_nav.abbrevCode(.generated_field);
@@ -3619,7 +3519,7 @@ fn updateLazyType(
.array_type => |array_type| {
const array_child_type: Type = .fromInterned(array_type.child);
try wip_nav.abbrevCode(if (array_type.sentinel == .none) .array_type else .array_sentinel_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (array_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(array_type.sentinel));
try wip_nav.refType(array_child_type);
try wip_nav.abbrevCode(.array_len);
@@ -3629,7 +3529,7 @@ fn updateLazyType(
},
.vector_type => |vector_type| {
try wip_nav.abbrevCode(.vector_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(vector_type.child));
try wip_nav.abbrevCode(.array_len);
try wip_nav.refType(.usize);
@@ -3640,9 +3540,9 @@ fn updateLazyType(
const opt_child_type: Type = .fromInterned(opt_child_type_index);
const opt_repr = optRepr(opt_child_type, zcu);
try wip_nav.abbrevCode(.generated_union_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
switch (opt_repr) {
.opv_null => {
try wip_nav.abbrevCode(.generated_field);
@@ -3720,12 +3620,12 @@ fn updateLazyType(
};
try wip_nav.abbrevCode(.generated_union_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
if (error_union_type.error_set_type != .generic_poison_type and
error_union_type.payload_type != .generic_poison_type)
{
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
} else {
try diw.writeUleb128(0);
try diw.writeUleb128(1);
@@ -3791,20 +3691,24 @@ fn updateLazyType(
.bool,
=> {
try wip_nav.abbrevCode(.numeric_type);
- try wip_nav.strp(name);
- try diw.writeByte(if (type_index == .bool_type)
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeByte(if (value_index == .bool_type)
DW.ATE.boolean
- else if (ty.isRuntimeFloat())
+ else if (val.toType().isRuntimeFloat())
DW.ATE.float
- else if (ty.isSignedInt(zcu))
+ else if (val.toType().isSignedInt(zcu))
DW.ATE.signed
- else if (ty.isUnsignedInt(zcu))
+ else if (val.toType().isUnsignedInt(zcu))
DW.ATE.unsigned
else
unreachable);
- try diw.writeUleb128(ty.bitSize(zcu));
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try diw.writeUleb128(val.toType().bitSize(zcu));
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
+ },
+ .generic_poison => {
+ try wip_nav.abbrevCode(.void_type);
+ try wip_nav.strp("anytype");
},
.anyopaque,
.void,
@@ -3815,37 +3719,29 @@ fn updateLazyType(
.null,
.undefined,
.enum_literal,
- .generic_poison,
=> {
try wip_nav.abbrevCode(.void_type);
- try wip_nav.strp(if (type_index == .generic_poison_type) "anytype" else name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
},
.anyerror => return, // delay until flush
.adhoc_inferred_error_set => unreachable,
},
- .struct_type,
- .union_type,
- .opaque_type,
- => unreachable,
.tuple_type => |tuple_type| if (tuple_type.types.len == 0) {
try wip_nav.abbrevCode(.generated_empty_struct_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try diw.writeByte(@intFromBool(false));
} else {
try wip_nav.abbrevCode(.generated_struct_type);
- try wip_nav.strp(name);
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
+ try diw.writeUleb128(val.toType().abiSize(zcu));
+ try diw.writeUleb128(val.toType().abiAlignment(zcu).toByteUnits().?);
var field_byte_offset: u64 = 0;
for (0..tuple_type.types.len) |field_index| {
const comptime_value = tuple_type.values.get(ip)[field_index];
const field_type: Type = .fromInterned(tuple_type.types.get(ip)[field_index]);
const has_runtime_bits, const has_comptime_state = switch (comptime_value) {
.none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu),
- },
+ else => .{ field_type.hasRuntimeBits(zcu), field_type.comptimeOnly(zcu) },
};
try wip_nav.abbrevCode(if (has_comptime_state)
.struct_field_comptime_comptime_state
@@ -3875,25 +3771,259 @@ fn updateLazyType(
}
try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
},
+ .struct_type => {
+ const loaded_struct = ip.loadStructType(value_index);
+ const ty = val.toType();
+ const file = loaded_struct.zir_index.resolveFile(ip);
+ switch (loaded_struct.layout) {
+ .auto, .@"extern" => {
+ const struct_is_file: bool = if (loaded_struct.zir_index.resolve(ip)) |inst| f: {
+ break :f inst == .main_struct_inst;
+ } else false;
+ if (loaded_struct.name_nav.unwrap()) |nav_index| {
+ assert(!struct_is_file);
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(if (loaded_struct.field_types.len == 0) .{
+ .decl = .decl_namespace_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_namespace_struct,
+ } else .{
+ .decl = .decl_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_struct,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(switch (loaded_struct.field_types.len) {
+ 0 => if (struct_is_file) .empty_file else .empty_struct_type,
+ else => if (struct_is_file) .file else .struct_type,
+ });
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_struct.name.toSlice(ip));
+ }
+ if (loaded_struct.field_types.len == 0) {
+ if (!struct_is_file) try diw.writeByte(@intFromBool(false));
+ } else {
+ try diw.writeUleb128(ty.abiSize(zcu));
+ try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
+ for (0..loaded_struct.field_types.len) |field_index| {
+ const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
+ const field_init = loaded_struct.field_defaults.getOrNone(ip, field_index);
+ assert(!(is_comptime and field_init == .none));
+ const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ const has_runtime_bits, const has_comptime_state = switch (field_init) {
+ .none => .{ false, false },
+ else => .{
+ field_type.hasRuntimeBits(zcu),
+ field_type.comptimeOnly(zcu),
+ },
+ };
+ try wip_nav.abbrevCode(if (is_comptime)
+ if (has_comptime_state)
+ .struct_field_comptime_comptime_state
+ else if (has_runtime_bits)
+ .struct_field_comptime_runtime_bits
+ else
+ .struct_field_comptime
+ else if (field_init != .none)
+ if (has_comptime_state)
+ .struct_field_default_comptime_state
+ else if (has_runtime_bits)
+ .struct_field_default_runtime_bits
+ else
+ .struct_field
+ else
+ .struct_field);
+ try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
+ try wip_nav.refType(field_type);
+ if (!is_comptime) {
+ try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
+ try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ if (has_comptime_state)
+ try wip_nav.refValue(.fromInterned(field_init))
+ else if (has_runtime_bits)
+ try wip_nav.blockValue(ty.srcLoc(zcu), .fromInterned(field_init));
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ },
+ .@"packed" => {
+ const need_terminator: bool = if (loaded_struct.name_nav.unwrap()) |nav_index| t: {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_packed_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_packed_struct,
+ }, &nav, file, &decl);
+ break :t true;
+ } else t: {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_struct.name.toSlice(ip));
+ break :t loaded_struct.field_types.len > 0;
+ };
+ try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
+ var field_bit_offset: u16 = 0;
+ for (0..loaded_struct.field_types.len) |field_index| {
+ try wip_nav.abbrevCode(.packed_struct_field);
+ try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(field_bit_offset);
+ field_bit_offset += @intCast(field_type.bitSize(zcu));
+ }
+ if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ },
+ }
+ },
+ .union_type => {
+ const loaded_union = ip.loadUnionType(value_index);
+ const file = loaded_union.zir_index.resolveFile(ip);
+ const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_union,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_union,
+ }, &nav, file, &decl);
+ break :t true;
+ } else t: {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_union.name.toSlice(ip));
+ break :t loaded_union.field_types.len > 0;
+ };
+ const union_layout = Type.getUnionLayout(loaded_union, zcu);
+ try diw.writeUleb128(union_layout.abi_size);
+ try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
+ const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
+ if (loaded_union.has_runtime_tag) {
+ try wip_nav.abbrevCode(.tagged_union);
+ try wip_nav.infoSectionOffset(
+ .debug_info,
+ wip_nav.unit,
+ wip_nav.entry,
+ @intCast(diw.end + dwarf.sectionOffsetBytes()),
+ );
+ {
+ try wip_nav.abbrevCode(.generated_field);
+ try wip_nav.strp("tag");
+ try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
+ try diw.writeUleb128(union_layout.tagOffset());
+
+ for (0..loaded_union.field_types.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_tag, .{
+ .sdata = .signed_tagged_union_field,
+ .udata = .unsigned_tagged_union_field,
+ .block = .big_tagged_union_field,
+ }, field_index);
+ {
+ try wip_nav.abbrevCode(.struct_field);
+ try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(union_layout.payloadOffset());
+ try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ }
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ } else for (0..loaded_union.field_types.len) |field_index| {
+ try wip_nav.abbrevCode(.untagged_union_field);
+ try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
+ const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
+ try wip_nav.refType(field_type);
+ try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
+ if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
+ }
+ if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ },
.enum_type => {
- const loaded_enum = ip.loadEnumType(type_index);
- try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
- for (0..loaded_enum.field_names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ const loaded_enum = ip.loadEnumType(value_index);
+ if (loaded_enum.zir_index.unwrap()) |zir_index| {
+ assert(loaded_enum.owner_union == .none);
+ const file = zir_index.resolveFile(ip);
+ if (loaded_enum.name_nav.unwrap()) |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(if (loaded_enum.field_names.len > 0) .{
+ .decl = .decl_enum,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_enum,
+ } else .{
+ .decl = .decl_empty_enum,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_empty_enum,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_enum.name.toSlice(ip));
+ }
+ try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
+ for (0..loaded_enum.field_names.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_enum, .{
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
+ }, field_index);
+ try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ }
+ if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ } else {
+ assert(loaded_enum.owner_union != .none);
+ try wip_nav.abbrevCode(if (loaded_enum.field_names.len == 0) .generated_empty_enum_type else .generated_enum_type);
+ try wip_nav.strp(loaded_enum.name.toSlice(ip));
+ try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
+ for (0..loaded_enum.field_names.len) |field_index| {
+ try wip_nav.enumConstValue(loaded_enum, .{
+ .sdata = .signed_enum_field,
+ .udata = .unsigned_enum_field,
+ .block = .big_enum_field,
+ }, field_index);
+ try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
+ }
+ if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
+ },
+ .opaque_type => {
+ const loaded_opaque = ip.loadOpaqueType(value_index);
+ const file = loaded_opaque.zir_index.resolveFile(ip);
+ if (loaded_opaque.name_nav.unwrap()) |nav_index| {
+ const nav = ip.getNav(nav_index);
+ const decl_inst = nav.srcInst(ip).resolve(ip).?;
+ const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
+ try wip_nav.declCommon(.{
+ .decl = .decl_namespace_struct,
+ .generic_decl = .generic_decl_const,
+ .decl_instance = .decl_instance_namespace_struct,
+ }, &nav, file, &decl);
+ } else {
+ const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
+ try wip_nav.abbrevCode(.empty_struct_type);
+ try diw.writeUleb128(file_gop.index);
+ try wip_nav.strp(loaded_opaque.name.toSlice(ip));
}
- if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ try diw.writeByte(@intFromBool(true));
},
.func_type => |func_type| {
const is_nullary = func_type.param_types.len == 0 and !func_type.is_var_args;
try wip_nav.abbrevCode(if (is_nullary) .nullary_func_type else .func_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
const cc: DW.CC = cc: {
if (zcu.getTarget().cCallingConvention()) |cc| {
if (@as(std.builtin.CallingConvention.Tag, cc) == func_type.cc) {
@@ -3975,7 +4105,7 @@ fn updateLazyType(
},
.error_set_type => |error_set_type| {
try wip_nav.abbrevCode(if (error_set_type.names.len == 0) .generated_empty_enum_type else .generated_enum_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(try pt.intern(.{ .int_type = .{
.signedness = .unsigned,
.bits = zcu.errorSetBits(),
@@ -3990,100 +4120,28 @@ fn updateLazyType(
},
.inferred_error_set_type => |func| {
try wip_nav.abbrevCode(.inferred_error_set_type);
- try wip_nav.strp(name);
+ try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.refType(.fromInterned(switch (ip.funcIesResolvedUnordered(func)) {
.none => .anyerror_type,
else => |ies| ies,
}));
},
- // values, not types
- .simple_value,
- .variable,
- .@"extern",
- .func,
- .int,
- .err,
- .error_union,
- .enum_literal,
- .enum_tag,
- .float,
- .ptr,
- .slice,
- .opt,
- .aggregate,
- .un,
- .bitpack,
- // memoization, not types
- .memoized_call,
- => unreachable,
- }
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
-}
-
-fn updateLazyValue(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- src_loc: Zcu.LazySrcLoc,
- value_index: InternPool.Index,
- pending_lazy: *WipNav.PendingLazy,
-) (UpdateError || Writer.Error)!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- assert(ip.typeOf(value_index) != .type_type);
- log.debug("updateLazyValue(@as({f}, {f}))", .{
- Value.fromInterned(value_index).typeOf(zcu).fmt(pt),
- Value.fromInterned(value_index).fmtValue(pt),
- });
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = .main,
- .entry = dwarf.values.get(value_index).?,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = pending_lazy.*,
- };
- defer {
- pending_lazy.* = wip_nav.pending_lazy;
- wip_nav.pending_lazy = .empty;
- wip_nav.deinit();
- }
- const diw = &wip_nav.debug_info.writer;
- var big_int_space: Value.BigIntSpace = undefined;
- switch (ip.indexToKey(value_index)) {
- .int_type,
- .ptr_type,
- .array_type,
- .vector_type,
- .opt_type,
- .anyframe_type,
- .error_union_type,
- .simple_type,
- .struct_type,
- .tuple_type,
- .union_type,
- .opaque_type,
- .enum_type,
- .func_type,
- .error_set_type,
- .inferred_error_set_type,
- => unreachable, // already handled
.undef => |ty| {
try wip_nav.abbrevCode(.undefined_comptime_value);
try wip_nav.refType(.fromInterned(ty));
},
- .simple_value => unreachable, // opv state
- .variable, .@"extern" => unreachable, // not a value
- .func => unreachable, // already handled
+ .simple_value => |simple_value| switch (simple_value) {
+ .void => unreachable, // opv state
+ .true, .false => unreachable, // runtime bits
+ .@"unreachable" => unreachable, // not a value
+ .null => {
+ // TODO: proper representation for this
+ try wip_nav.abbrevCode(.undefined_comptime_value);
+ try wip_nav.refType(.null);
+ },
+ },
+ .variable => unreachable, // not a value
.int => |int| {
try wip_nav.bigIntConstValue(.{
.sdata = .sdata_comptime_value,
@@ -4202,7 +4260,7 @@ fn updateLazyValue(
var byte_offset = ptr.byte_offset;
const base_unit, const base_entry = while (true) {
const base_ptr, const access: Access = base_ptr_access: switch (base_addr) {
- .nav => |nav_index| break try wip_nav.getNavEntry(nav_index),
+ .nav => |nav_index| break try dwarf.getNavEntry(nav_index),
.comptime_alloc, .comptime_field => unreachable,
.uav => |uav| {
const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
@@ -4319,17 +4377,7 @@ fn updateLazyValue(
switch (optRepr(opt_child_type, zcu)) {
.opv_null => try diw.writeUleb128(0),
.unpacked => try wip_nav.blockValue(src_loc, .makeBool(opt.val != .none)),
- .error_set => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
- .pointer => if (opt_child_type.comptimeOnly(zcu)) {
- var buf: [8]u8 = undefined;
- const bytes = buf[0..@divExact(zcu.getTarget().ptrBitWidth(), 8)];
- dwarf.writeInt(bytes, switch (opt.val) {
- .none => 0,
- else => opt_child_type.ptrAlignment(zcu).toByteUnits().?,
- });
- try diw.writeUleb128(bytes.len);
- try diw.writeAll(bytes);
- } else try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
+ .error_set, .pointer => try wip_nav.blockValue(src_loc, .fromInterned(value_index)),
}
}
if (opt.val != .none) child_field: {
@@ -4457,7 +4505,8 @@ fn updateLazyValue(
},
.memoized_call => unreachable, // not a value
}
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
+ try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
}
fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
@@ -4472,312 +4521,6 @@ fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, err
};
}
-pub fn updateContainerType(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- type_index: InternPool.Index,
-) UpdateError!void {
- return dwarf.updateContainerTypeWriterError(pt, type_index) catch |err| switch (err) {
- error.WriteFailed => error.OutOfMemory,
- else => |e| e,
- };
-}
-fn updateContainerTypeWriterError(
- dwarf: *Dwarf,
- pt: Zcu.PerThread,
- type_index: InternPool.Index,
-) (UpdateError || Writer.Error)!void {
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const ty: Type = .fromInterned(type_index);
- const ty_src_loc = ty.srcLoc(zcu);
- log.debug("updateContainerType({f})", .{ty.fmt(pt)});
-
- const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
- const file = zcu.fileByIndex(inst_info.file);
- const unit = try dwarf.getUnit(file.mod.?);
- const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
- if (inst_info.inst == .main_struct_inst) {
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = unit,
- .entry = type_gop.value_ptr.*,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
-
- const loaded_struct = ip.loadStructType(type_index);
-
- const diw = &wip_nav.debug_info.writer;
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_file else .file);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(loaded_struct.name.toSlice(ip));
- if (loaded_struct.field_types.len > 0) {
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
- const field_init = loaded_struct.field_defaults.getOrNone(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu),
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
-
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(ty_src_loc);
- } else {
- {
- // Note that changes to ZIR instruction tracking only need to update this code
- // if a newly-tracked instruction can be a type's owner `zir_index`.
- comptime assert(Zir.inst_tracking_version == 0);
-
- const decl_inst = file.zir.?.instructions.get(@intFromEnum(inst_info.inst));
- const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
- .struct_init, .struct_init_ref, .struct_init_anon => .anon,
- .extended => switch (decl_inst.data.extended.opcode) {
- .struct_decl => file.zir.?.getStructDecl(inst_info.inst).name_strategy,
- .union_decl => file.zir.?.getUnionDecl(inst_info.inst).name_strategy,
- .enum_decl => file.zir.?.getEnumDecl(inst_info.inst).name_strategy,
- .opaque_decl => file.zir.?.getOpaqueDecl(inst_info.inst).name_strategy,
-
- .reify_enum,
- .reify_struct,
- .reify_union,
- => @enumFromInt(decl_inst.data.extended.small),
-
- else => unreachable,
- },
- else => unreachable,
- };
- if (name_strat == .parent) return;
- }
-
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(unit);
- var wip_nav: WipNav = .{
- .dwarf = dwarf,
- .pt = pt,
- .unit = unit,
- .entry = type_gop.value_ptr.*,
- .any_children = false,
- .func = .none,
- .func_sym_index = undefined,
- .func_high_pc = undefined,
- .blocks = undefined,
- .cfi = undefined,
- .debug_frame = .init(dwarf.gpa),
- .debug_info = .init(dwarf.gpa),
- .debug_line = .init(dwarf.gpa),
- .debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
- };
- defer wip_nav.deinit();
- const diw = &wip_nav.debug_info.writer;
- const name = try std.fmt.allocPrint(dwarf.gpa, "{f}", .{ty.fmt(pt)});
- defer dwarf.gpa.free(name);
-
- switch (ip.indexToKey(type_index)) {
- .struct_type => {
- const loaded_struct = ip.loadStructType(type_index);
- switch (loaded_struct.layout) {
- .auto, .@"extern" => {
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len == 0) .empty_struct_type else .struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- if (loaded_struct.field_types.len == 0) try diw.writeByte(@intFromBool(false)) else {
- try diw.writeUleb128(ty.abiSize(zcu));
- try diw.writeUleb128(ty.abiAlignment(zcu).toByteUnits().?);
- for (0..loaded_struct.field_types.len) |field_index| {
- const is_comptime = loaded_struct.field_is_comptime_bits.get(ip, field_index);
- const field_init = loaded_struct.field_defaults.getOrNone(ip, field_index);
- assert(!(is_comptime and field_init == .none));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- const has_runtime_bits, const has_comptime_state = switch (field_init) {
- .none => .{ false, false },
- else => .{
- field_type.hasRuntimeBits(zcu),
- field_type.comptimeOnly(zcu),
- },
- };
- try wip_nav.abbrevCode(if (is_comptime)
- if (has_comptime_state)
- .struct_field_comptime_comptime_state
- else if (has_runtime_bits)
- .struct_field_comptime_runtime_bits
- else
- .struct_field_comptime
- else if (field_init != .none)
- if (has_comptime_state)
- .struct_field_default_comptime_state
- else if (has_runtime_bits)
- .struct_field_default_runtime_bits
- else
- .struct_field
- else
- .struct_field);
- try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
- try wip_nav.refType(field_type);
- if (!is_comptime) {
- try diw.writeUleb128(loaded_struct.field_offsets.get(ip)[field_index]);
- try diw.writeUleb128(loaded_struct.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (has_comptime_state)
- try wip_nav.refValue(.fromInterned(field_init))
- else if (has_runtime_bits)
- try wip_nav.blockValue(ty_src_loc, .fromInterned(field_init));
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- },
- .@"packed" => {
- try wip_nav.abbrevCode(if (loaded_struct.field_types.len > 0) .packed_struct_type else .empty_packed_struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_struct.packed_backing_int_type));
- var field_bit_offset: u16 = 0;
- for (0..loaded_struct.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.packed_struct_field);
- try wip_nav.strp(loaded_struct.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_struct.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(field_bit_offset);
- field_bit_offset += @intCast(field_type.bitSize(zcu));
- }
- if (loaded_struct.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- }
- },
- .enum_type => {
- const loaded_enum = ip.loadEnumType(type_index);
- try wip_nav.abbrevCode(if (loaded_enum.field_names.len > 0) .enum_type else .empty_enum_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try wip_nav.refType(.fromInterned(loaded_enum.int_tag_type));
- for (0..loaded_enum.field_names.len) |field_index| {
- try wip_nav.enumConstValue(loaded_enum, .{
- .sdata = .signed_enum_field,
- .udata = .unsigned_enum_field,
- .block = .big_enum_field,
- }, field_index);
- try wip_nav.strp(loaded_enum.field_names.get(ip)[field_index].toSlice(ip));
- }
- if (loaded_enum.field_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- .union_type => {
- const loaded_union = ip.loadUnionType(type_index);
- try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- const union_layout = Type.getUnionLayout(loaded_union, zcu);
- try diw.writeUleb128(union_layout.abi_size);
- try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
- const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
- if (loaded_union.has_runtime_tag) {
- try wip_nav.abbrevCode(.tagged_union);
- try wip_nav.infoSectionOffset(
- .debug_info,
- wip_nav.unit,
- wip_nav.entry,
- @intCast(diw.end + dwarf.sectionOffsetBytes()),
- );
- {
- try wip_nav.abbrevCode(.generated_field);
- try wip_nav.strp("tag");
- try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
- try diw.writeUleb128(union_layout.tagOffset());
-
- for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.enumConstValue(loaded_tag, .{
- .sdata = .signed_tagged_union_field,
- .udata = .unsigned_tagged_union_field,
- .block = .big_tagged_union_field,
- }, field_index);
- {
- try wip_nav.abbrevCode(.struct_field);
- try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(union_layout.payloadOffset());
- try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- }
- }
- try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- } else for (0..loaded_union.field_types.len) |field_index| {
- try wip_nav.abbrevCode(.untagged_union_field);
- try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
- const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
- try wip_nav.refType(field_type);
- try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
- if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
- }
- if (loaded_union.field_types.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
- },
- .opaque_type => {
- try wip_nav.abbrevCode(.empty_struct_type);
- try diw.writeUleb128(file_gop.index);
- try wip_nav.strp(name);
- try diw.writeByte(@intFromBool(true));
- },
- else => unreachable,
- }
- try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try dwarf.debug_loclists.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_loclists.written());
- try wip_nav.updateLazy(ty_src_loc);
- }
-}
-
pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedInst.Index) UpdateError!void {
const comp = dwarf.bin_file.comp;
const io = comp.io;
@@ -4840,14 +4583,15 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
const comp = dwarf.bin_file.comp;
const io = comp.io;
+ // Update `anyerror` based on the finished global error set.
{
- const type_gop = try dwarf.types.getOrPut(dwarf.gpa, .anyerror_type);
- if (!type_gop.found_existing) type_gop.value_ptr.* = try dwarf.addCommonEntry(.main);
+ const index = try dwarf.const_pool.get(pt, .{ .dwarf = dwarf }, .anyerror_type);
+ const unit, const entry = dwarf.values.items[@intFromEnum(index)];
var wip_nav: WipNav = .{
.dwarf = dwarf,
.pt = pt,
- .unit = .main,
- .entry = type_gop.value_ptr.*,
+ .unit = unit,
+ .entry = entry,
.any_children = false,
.func = .none,
.func_sym_index = undefined,
@@ -4858,7 +4602,6 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
.debug_info = .init(dwarf.gpa),
.debug_line = .init(dwarf.gpa),
.debug_loclists = .init(dwarf.gpa),
- .pending_lazy = .empty,
};
defer wip_nav.deinit();
const diw = &wip_nav.debug_info.writer;
@@ -4876,7 +4619,7 @@ fn flushWriterError(dwarf: *Dwarf, pt: Zcu.PerThread) (FlushError || Writer.Erro
}
if (global_error_set_names.len > 0) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
- try wip_nav.updateLazy(.unneeded);
+ try dwarf.const_pool.flushPending(pt, .{ .dwarf = dwarf });
}
for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
@@ -5324,6 +5067,8 @@ const AbbrevCode = enum {
inferred_error_set_type,
ptr_type,
ptr_sentinel_type,
+ ptr_aligned_type,
+ ptr_aligned_sentinel_type,
is_const,
is_volatile,
array_type,
@@ -5960,7 +5705,6 @@ const AbbrevCode = enum {
.tag = .pointer_type,
.attrs = &.{
.{ .name, .strp },
- .{ .alignment, .udata },
.{ .address_class, .data1 },
.{ .type, .ref_addr },
},
@@ -5970,6 +5714,24 @@ const AbbrevCode = enum {
.attrs = &.{
.{ .name, .strp },
.{ .ZIG_sentinel, .block },
+ .{ .address_class, .data1 },
+ .{ .type, .ref_addr },
+ },
+ },
+ .ptr_aligned_type = .{
+ .tag = .pointer_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .alignment, .udata },
+ .{ .address_class, .data1 },
+ .{ .type, .ref_addr },
+ },
+ },
+ .ptr_aligned_sentinel_type = .{
+ .tag = .pointer_type,
+ .attrs = &.{
+ .{ .name, .strp },
+ .{ .ZIG_sentinel, .block },
.{ .alignment, .udata },
.{ .address_class, .data1 },
.{ .type, .ref_addr },
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
@@ -1711,13 +1711,14 @@ pub fn updateContainerType(
self: *Elf,
pt: Zcu.PerThread,
ty: InternPool.Index,
+ success: bool,
) link.File.UpdateContainerTypeError!void {
if (build_options.skip_non_native and builtin.object_format != .elf) {
@panic("Attempted to compile for object format that was disabled by build configuration");
}
const zcu = pt.zcu;
const gpa = zcu.gpa;
- return self.zigObjectPtr().?.updateContainerType(pt, ty) catch |err| switch (err) {
+ return self.zigObjectPtr().?.updateContainerType(pt, ty, success) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |e| {
try zcu.failed_types.putNoClobber(gpa, ty, try Zcu.ErrorMsg.create(
diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig
@@ -1719,11 +1719,12 @@ pub fn updateContainerType(
self: *ZigObject,
pt: Zcu.PerThread,
ty: InternPool.Index,
+ success: bool,
) !void {
const tracy = trace(@src());
defer tracy.end();
- if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty);
+ if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty, success);
}
fn updateLazySymbol(