diff --git a/lib/std/debug.zig b/lib/std/debug.zig index bc7023eae2..6780e17e1e 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -2459,13 +2459,24 @@ pub const ModuleDebugInfo = switch (native_os) { module, relocated_address - coff_section.virtual_address, ) orelse "???"; + // While DWARF gets us just the function's own name, the PDB + // stores it qualified with its namespace by the C++ `::` + // operator. We can strip that for consistency; the + // SymbolInfo will contain the line number, which is a more + // language-neutral way of distinguishing same-named symbols + // anyway. + const symbol_simple_name = if (mem.indexOf(u8, symbol_name, "::")) |cpp_namespace| + symbol_name[cpp_namespace + 2 ..] + else + symbol_name; + const opt_line_info = try self.pdb.?.getLineNumberInfo( module, relocated_address - coff_section.virtual_address, ); return SymbolInfo{ - .symbol_name = symbol_name, + .symbol_name = symbol_simple_name, .compile_unit_name = obj_basename, .line_info = opt_line_info, }; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 25d7d08f08..48bf335311 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -805,14 +805,17 @@ pub const Object = struct { debug_enums_fwd_ref: Builder.Metadata, debug_globals_fwd_ref: Builder.Metadata, + debug_imports_fwd_ref: Builder.Metadata, debug_enums: std.ArrayListUnmanaged(Builder.Metadata), debug_globals: std.ArrayListUnmanaged(Builder.Metadata), + debug_imports: std.ArrayListUnmanaged(Builder.Metadata), debug_file_map: std.AutoHashMapUnmanaged(*const Zcu.File, Builder.Metadata), debug_type_map: std.AutoHashMapUnmanaged(Type, Builder.Metadata), - debug_unresolved_namespace_scopes: std.AutoArrayHashMapUnmanaged(InternPool.NamespaceIndex, Builder.Metadata), + // The value says whether this namespace's type is runtime-required. + debug_unresolved_namespace_scopes: std.AutoArrayHashMapUnmanaged(Type, bool), target: std.Target, /// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function, @@ -877,7 +880,7 @@ pub const Object = struct { builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }}); - const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref = + const debug_compile_unit, const debug_enums_fwd_ref, const debug_globals_fwd_ref, const debug_imports_fwd_ref = if (!builder.strip) debug_info: { // We fully resolve all paths at this point to avoid lack of @@ -909,6 +912,7 @@ pub const Object = struct { const debug_enums_fwd_ref = try builder.debugForwardReference(); const debug_globals_fwd_ref = try builder.debugForwardReference(); + const debug_imports_fwd_ref = try builder.debugForwardReference(); const debug_compile_unit = try builder.debugCompileUnit( debug_file, @@ -921,6 +925,7 @@ pub const Object = struct { }), debug_enums_fwd_ref, debug_globals_fwd_ref, + debug_imports_fwd_ref, .{ .optimized = comp.root_mod.optimize_mode != .Debug }, ); @@ -976,8 +981,8 @@ pub const Object = struct { } try builder.debugNamed(try builder.metadataString("llvm.dbg.cu"), &.{debug_compile_unit}); - break :debug_info .{ debug_compile_unit, debug_enums_fwd_ref, debug_globals_fwd_ref }; - } else .{.none} ** 3; + break :debug_info .{ debug_compile_unit, debug_enums_fwd_ref, debug_globals_fwd_ref, debug_imports_fwd_ref }; + } else .{.none} ** 4; const obj = try arena.create(Object); obj.* = .{ @@ -990,8 +995,10 @@ pub const Object = struct { .debug_compile_unit = debug_compile_unit, .debug_enums_fwd_ref = debug_enums_fwd_ref, .debug_globals_fwd_ref = debug_globals_fwd_ref, + .debug_imports_fwd_ref = debug_imports_fwd_ref, .debug_enums = .{}, .debug_globals = .{}, + .debug_imports = .{}, .debug_file_map = .{}, .debug_type_map = .{}, .debug_unresolved_namespace_scopes = .{}, @@ -1133,18 +1140,7 @@ pub const Object = struct { try self.genModuleLevelAssembly(); if (!self.builder.strip) { - { - var i: usize = 0; - while (i < self.debug_unresolved_namespace_scopes.count()) : (i += 1) { - const namespace_index = self.debug_unresolved_namespace_scopes.keys()[i]; - const fwd_ref = self.debug_unresolved_namespace_scopes.values()[i]; - - const namespace = zcu.namespacePtr(namespace_index); - const debug_type = try self.lowerDebugType(namespace.getType(zcu)); - - self.builder.debugForwardReferenceSetType(fwd_ref, debug_type); - } - } + try self.genNamespaces(); self.builder.debugForwardReferenceSetType( self.debug_enums_fwd_ref, @@ -1155,6 +1151,11 @@ pub const Object = struct { self.debug_globals_fwd_ref, try self.builder.debugTuple(self.debug_globals.items), ); + + self.builder.debugForwardReferenceSetType( + self.debug_imports_fwd_ref, + try self.builder.debugTuple(self.debug_imports.items), + ); } } @@ -1634,15 +1635,19 @@ pub const Object = struct { const file, const subprogram = if (!wip.strip) debug_info: { const file = try o.getDebugFile(file_scope); + const scope = try o.lowerDebugType(zcu.declPtr(namespace.decl_index).val.toType(), false); const line_number = decl.navSrcLine(zcu) + 1; const is_internal_linkage = decl.val.getExternFunc(zcu) == null; - const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu)); + const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu), true); + const decl_name = try o.builder.metadataString(decl.name.toSlice(ip)); + const link_name = try o.builder.metadataStringFromStrtabString(function_index.name(&o.builder)); const subprogram = try o.builder.debugSubprogram( file, - try o.builder.metadataString(decl.name.toSlice(ip)), - try o.builder.metadataStringFromStrtabString(function_index.name(&o.builder)), + scope, + decl_name, + link_name, line_number, line_number + func.lbrace_line, debug_decl_type, @@ -1659,6 +1664,7 @@ pub const Object = struct { }, o.debug_compile_unit, ); + function_index.setSubprogram(subprogram, &o.builder); break :debug_info .{ file, subprogram }; } else .{.none} ** 2; @@ -1906,6 +1912,7 @@ pub const Object = struct { pub fn lowerDebugType( o: *Object, ty: Type, + required_by_runtime: bool, ) Allocator.Error!Builder.Metadata { assert(!o.builder.strip); @@ -1915,7 +1922,13 @@ pub const Object = struct { const zcu = pt.zcu; const ip = &zcu.intern_pool; - if (o.debug_type_map.get(ty)) |debug_type| return debug_type; + if (o.debug_type_map.get(ty)) |debug_type| { + if (required_by_runtime) { + if (o.debug_unresolved_namespace_scopes.getEntry(ty)) |entry| + entry.value_ptr.* = true; + } + return debug_type; + } switch (ty.zigTypeTag(zcu)) { .Void, @@ -1930,10 +1943,9 @@ pub const Object = struct { }, .Int => { const info = ty.intInfo(zcu); - assert(info.bits != 0); - const name = try o.allocTypeName(ty); - defer gpa.free(name); - const builder_name = try o.builder.metadataString(name); + const int_name = try o.allocTypeName(ty); + defer gpa.free(int_name); + const builder_name = try o.builder.metadataString(int_name); const debug_bits = ty.abiSize(pt) * 8; // lldb cannot handle non-byte sized types const debug_int_type = switch (info.signedness) { .signed => try o.builder.debugSignedType(builder_name, debug_bits), @@ -1942,68 +1954,12 @@ pub const Object = struct { try o.debug_type_map.put(gpa, ty, debug_int_type); return debug_int_type; }, - .Enum => { - const owner_decl_index = ty.getOwnerDecl(zcu); - const owner_decl = zcu.declPtr(owner_decl_index); - - if (!ty.hasRuntimeBitsIgnoreComptime(pt)) { - const debug_enum_type = try o.makeEmptyNamespaceDebugType(owner_decl_index); - try o.debug_type_map.put(gpa, ty, debug_enum_type); - return debug_enum_type; - } - - const enum_type = ip.loadEnumType(ty.toIntern()); - - const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len); - defer gpa.free(enumerators); - - const int_ty = Type.fromInterned(enum_type.tag_ty); - const int_info = ty.intInfo(zcu); - assert(int_info.bits != 0); - - for (enum_type.names.get(ip), 0..) |field_name_ip, i| { - var bigint_space: Value.BigIntSpace = undefined; - const bigint = if (enum_type.values.len != 0) - Value.fromInterned(enum_type.values.get(ip)[i]).toBigInt(&bigint_space, pt) - else - std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst(); - - enumerators[i] = try o.builder.debugEnumerator( - try o.builder.metadataString(field_name_ip.toSlice(ip)), - int_info.signedness == .unsigned, - int_info.bits, - bigint, - ); - } - - const file_scope = zcu.namespacePtr(owner_decl.src_namespace).fileScope(zcu); - const file = try o.getDebugFile(file_scope); - const scope = try o.namespaceToDebugScope(owner_decl.src_namespace); - - const name = try o.allocTypeName(ty); - defer gpa.free(name); - - const debug_enum_type = try o.builder.debugEnumerationType( - try o.builder.metadataString(name), - file, - scope, - owner_decl.typeSrcLine(zcu) + 1, // Line - try o.lowerDebugType(int_ty), - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple(enumerators), - ); - - try o.debug_type_map.put(gpa, ty, debug_enum_type); - try o.debug_enums.append(gpa, debug_enum_type); - return debug_enum_type; - }, .Float => { const bits = ty.floatBits(target); - const name = try o.allocTypeName(ty); - defer gpa.free(name); + const float_name = try o.allocTypeName(ty); + defer gpa.free(float_name); const debug_float_type = try o.builder.debugFloatType( - try o.builder.metadataString(name), + try o.builder.metadataString(float_name), bits, ); try o.debug_type_map.put(gpa, ty, debug_float_type); @@ -2045,7 +2001,7 @@ pub const Object = struct { }, }, }); - const debug_ptr_type = try o.lowerDebugType(bland_ptr_ty); + const debug_ptr_type = try o.lowerDebugType(bland_ptr_ty, required_by_runtime); try o.debug_type_map.put(gpa, ty, debug_ptr_type); return debug_ptr_type; } @@ -2061,6 +2017,7 @@ pub const Object = struct { const name = try o.allocTypeName(ty); defer gpa.free(name); + const line = 0; const ptr_size = ptr_ty.abiSize(pt); @@ -2075,7 +2032,7 @@ pub const Object = struct { .none, // File debug_fwd_ref, 0, // Line - try o.lowerDebugType(ptr_ty), + try o.lowerDebugType(ptr_ty, required_by_runtime), ptr_size * 8, (ptr_align.toByteUnits() orelse 0) * 8, 0, // Offset @@ -2086,7 +2043,7 @@ pub const Object = struct { .none, // File debug_fwd_ref, 0, // Line - try o.lowerDebugType(len_ty), + try o.lowerDebugType(len_ty, required_by_runtime), len_size * 8, (len_align.toByteUnits() orelse 0) * 8, len_offset * 8, @@ -2104,6 +2061,7 @@ pub const Object = struct { debug_ptr_type, debug_len_type, }), + isByRef(ty, pt), ); o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_slice_type); @@ -2115,7 +2073,7 @@ pub const Object = struct { return debug_slice_type; } - const debug_elem_ty = try o.lowerDebugType(Type.fromInterned(ptr_info.child)); + const debug_elem_ty = try o.lowerDebugType(Type.fromInterned(ptr_info.child), required_by_runtime); const name = try o.allocTypeName(ty); defer gpa.free(name); @@ -2139,41 +2097,13 @@ pub const Object = struct { return debug_ptr_type; }, - .Opaque => { - if (ty.toIntern() == .anyopaque_type) { - const debug_opaque_type = try o.builder.debugSignedType( - try o.builder.metadataString("anyopaque"), - 0, - ); - try o.debug_type_map.put(gpa, ty, debug_opaque_type); - return debug_opaque_type; - } - - const name = try o.allocTypeName(ty); - defer gpa.free(name); - const owner_decl_index = ty.getOwnerDecl(zcu); - const owner_decl = zcu.declPtr(owner_decl_index); - const file_scope = zcu.namespacePtr(owner_decl.src_namespace).fileScope(zcu); - const debug_opaque_type = try o.builder.debugStructType( - try o.builder.metadataString(name), - try o.getDebugFile(file_scope), - try o.namespaceToDebugScope(owner_decl.src_namespace), - owner_decl.typeSrcLine(zcu) + 1, // Line - .none, // Underlying type - 0, // Size - 0, // Align - .none, // Fields - ); - try o.debug_type_map.put(gpa, ty, debug_opaque_type); - return debug_opaque_type; - }, .Array => { const debug_array_type = try o.builder.debugArrayType( .none, // Name .none, // File .none, // Scope 0, // Line - try o.lowerDebugType(ty.childType(zcu)), + try o.lowerDebugType(ty.childType(zcu), required_by_runtime), ty.abiSize(pt) * 8, (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, try o.builder.debugTuple(&.{ @@ -2195,10 +2125,9 @@ pub const Object = struct { const debug_elem_type = switch (elem_ty.zigTypeTag(zcu)) { .Int => blk: { const info = elem_ty.intInfo(zcu); - assert(info.bits != 0); - const name = try o.allocTypeName(ty); - defer gpa.free(name); - const builder_name = try o.builder.metadataString(name); + const vec_name = try o.allocTypeName(ty); + defer gpa.free(vec_name); + const builder_name = try o.builder.metadataString(vec_name); break :blk switch (info.signedness) { .signed => try o.builder.debugSignedType(builder_name, info.bits), .unsigned => try o.builder.debugUnsignedType(builder_name, info.bits), @@ -2208,7 +2137,7 @@ pub const Object = struct { try o.builder.metadataString("bool"), 1, ), - else => try o.lowerDebugType(ty.childType(zcu)), + else => try o.lowerDebugType(ty.childType(zcu), required_by_runtime), }; const debug_vector_type = try o.builder.debugVectorType( @@ -2233,6 +2162,7 @@ pub const Object = struct { .Optional => { const name = try o.allocTypeName(ty); defer gpa.free(name); + const child_ty = ty.optionalChild(zcu); if (!child_ty.hasRuntimeBitsIgnoreComptime(pt)) { const debug_bool_type = try o.builder.debugBoolType( @@ -2249,7 +2179,7 @@ pub const Object = struct { try o.debug_type_map.put(gpa, ty, debug_fwd_ref); if (ty.optionalReprIsPayload(zcu)) { - const debug_optional_type = try o.lowerDebugType(child_ty); + const debug_optional_type = try o.lowerDebugType(child_ty, required_by_runtime); o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_optional_type); @@ -2272,7 +2202,7 @@ pub const Object = struct { .none, // File debug_fwd_ref, 0, // Line - try o.lowerDebugType(child_ty), + try o.lowerDebugType(child_ty, required_by_runtime), payload_size * 8, (payload_align.toByteUnits() orelse 0) * 8, 0, // Offset @@ -2283,7 +2213,7 @@ pub const Object = struct { .none, debug_fwd_ref, 0, - try o.lowerDebugType(non_null_ty), + try o.lowerDebugType(non_null_ty, required_by_runtime), non_null_size * 8, (non_null_align.toByteUnits() orelse 0) * 8, non_null_offset * 8, @@ -2301,6 +2231,7 @@ pub const Object = struct { debug_data_type, debug_some_type, }), + isByRef(ty, pt), ); o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_optional_type); @@ -2315,7 +2246,7 @@ pub const Object = struct { const payload_ty = ty.errorUnionPayload(zcu); if (!payload_ty.hasRuntimeBitsIgnoreComptime(pt)) { // TODO: Maybe remove? - const debug_error_union_type = try o.lowerDebugType(Type.anyerror); + const debug_error_union_type = try o.lowerDebugType(Type.anyerror, required_by_runtime); try o.debug_type_map.put(gpa, ty, debug_error_union_type); return debug_error_union_type; } @@ -2352,7 +2283,7 @@ pub const Object = struct { .none, // File debug_fwd_ref, 0, // Line - try o.lowerDebugType(Type.anyerror), + try o.lowerDebugType(Type.anyerror, required_by_runtime), error_size * 8, (error_align.toByteUnits() orelse 0) * 8, error_offset * 8, @@ -2362,7 +2293,7 @@ pub const Object = struct { .none, // File debug_fwd_ref, 0, // Line - try o.lowerDebugType(payload_ty), + try o.lowerDebugType(payload_ty, required_by_runtime), payload_size * 8, (payload_align.toByteUnits() orelse 0) * 8, payload_offset * 8, @@ -2377,6 +2308,7 @@ pub const Object = struct { ty.abiSize(pt) * 8, (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, try o.builder.debugTuple(&fields), + isByRef(ty, pt), ); o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_error_union_type); @@ -2392,326 +2324,6 @@ pub const Object = struct { try o.debug_type_map.put(gpa, ty, debug_error_set); return debug_error_set; }, - .Struct => { - const name = try o.allocTypeName(ty); - defer gpa.free(name); - - if (zcu.typeToPackedStruct(ty)) |struct_type| { - const backing_int_ty = struct_type.backingIntTypeUnordered(ip); - if (backing_int_ty != .none) { - const info = Type.fromInterned(backing_int_ty).intInfo(zcu); - const builder_name = try o.builder.metadataString(name); - const debug_int_type = switch (info.signedness) { - .signed => try o.builder.debugSignedType(builder_name, ty.abiSize(pt) * 8), - .unsigned => try o.builder.debugUnsignedType(builder_name, ty.abiSize(pt) * 8), - }; - try o.debug_type_map.put(gpa, ty, debug_int_type); - return debug_int_type; - } - } - - switch (ip.indexToKey(ty.toIntern())) { - .anon_struct_type => |tuple| { - var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{}; - defer fields.deinit(gpa); - - try fields.ensureUnusedCapacity(gpa, tuple.types.len); - - comptime assert(struct_layout_version == 2); - var offset: u64 = 0; - - const debug_fwd_ref = try o.builder.debugForwardReference(); - - for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { - if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue; - - const field_size = Type.fromInterned(field_ty).abiSize(pt); - const field_align = Type.fromInterned(field_ty).abiAlignment(pt); - const field_offset = field_align.forward(offset); - offset = field_offset + field_size; - - const field_name = if (tuple.names.len != 0) - tuple.names.get(ip)[i].toSlice(ip) - else - try std.fmt.allocPrintZ(gpa, "{d}", .{i}); - defer if (tuple.names.len == 0) gpa.free(field_name); - - fields.appendAssumeCapacity(try o.builder.debugMemberType( - try o.builder.metadataString(field_name), - .none, // File - debug_fwd_ref, - 0, - try o.lowerDebugType(Type.fromInterned(field_ty)), - field_size * 8, - (field_align.toByteUnits() orelse 0) * 8, - field_offset * 8, - )); - } - - const debug_struct_type = try o.builder.debugStructType( - try o.builder.metadataString(name), - .none, // File - o.debug_compile_unit, // Scope - 0, // Line - .none, // Underlying type - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple(fields.items), - ); - - o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type); - - try o.debug_type_map.put(gpa, ty, debug_struct_type); - return debug_struct_type; - }, - .struct_type => { - if (!ip.loadStructType(ty.toIntern()).haveFieldTypes(ip)) { - // This can happen if a struct type makes it all the way to - // flush() without ever being instantiated or referenced (even - // via pointer). The only reason we are hearing about it now is - // that it is being used as a namespace to put other debug types - // into. Therefore we can satisfy this by making an empty namespace, - // rather than changing the frontend to unnecessarily resolve the - // struct field types. - const owner_decl_index = ty.getOwnerDecl(zcu); - const debug_struct_type = try o.makeEmptyNamespaceDebugType(owner_decl_index); - try o.debug_type_map.put(gpa, ty, debug_struct_type); - return debug_struct_type; - } - }, - else => {}, - } - - if (!ty.hasRuntimeBitsIgnoreComptime(pt)) { - const owner_decl_index = ty.getOwnerDecl(zcu); - const debug_struct_type = try o.makeEmptyNamespaceDebugType(owner_decl_index); - try o.debug_type_map.put(gpa, ty, debug_struct_type); - return debug_struct_type; - } - - const struct_type = zcu.typeToStruct(ty).?; - - var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{}; - defer fields.deinit(gpa); - - try fields.ensureUnusedCapacity(gpa, struct_type.field_types.len); - - const debug_fwd_ref = try o.builder.debugForwardReference(); - - // Set as forward reference while the type is lowered in case it references itself - try o.debug_type_map.put(gpa, ty, debug_fwd_ref); - - comptime assert(struct_layout_version == 2); - var it = struct_type.iterateRuntimeOrder(ip); - while (it.next()) |field_index| { - const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]); - if (!field_ty.hasRuntimeBitsIgnoreComptime(pt)) continue; - const field_size = field_ty.abiSize(pt); - const field_align = pt.structFieldAlignment( - struct_type.fieldAlign(ip, field_index), - field_ty, - struct_type.layout, - ); - const field_offset = ty.structFieldOffset(field_index, pt); - - const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse - try ip.getOrPutStringFmt(gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls); - - fields.appendAssumeCapacity(try o.builder.debugMemberType( - try o.builder.metadataString(field_name.toSlice(ip)), - .none, // File - debug_fwd_ref, - 0, // Line - try o.lowerDebugType(field_ty), - field_size * 8, - (field_align.toByteUnits() orelse 0) * 8, - field_offset * 8, - )); - } - - const debug_struct_type = try o.builder.debugStructType( - try o.builder.metadataString(name), - .none, // File - o.debug_compile_unit, // Scope - 0, // Line - .none, // Underlying type - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple(fields.items), - ); - - o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type); - - // Set to real type now that it has been lowered fully - const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable; - map_ptr.* = debug_struct_type; - - return debug_struct_type; - }, - .Union => { - const owner_decl_index = ty.getOwnerDecl(zcu); - - const name = try o.allocTypeName(ty); - defer gpa.free(name); - - const union_type = ip.loadUnionType(ty.toIntern()); - if (!union_type.haveFieldTypes(ip) or - !ty.hasRuntimeBitsIgnoreComptime(pt) or - !union_type.haveLayout(ip)) - { - const debug_union_type = try o.makeEmptyNamespaceDebugType(owner_decl_index); - try o.debug_type_map.put(gpa, ty, debug_union_type); - return debug_union_type; - } - - const layout = pt.getUnionLayout(union_type); - - const debug_fwd_ref = try o.builder.debugForwardReference(); - - // Set as forward reference while the type is lowered in case it references itself - try o.debug_type_map.put(gpa, ty, debug_fwd_ref); - - if (layout.payload_size == 0) { - const debug_union_type = try o.builder.debugStructType( - try o.builder.metadataString(name), - .none, // File - o.debug_compile_unit, // Scope - 0, // Line - .none, // Underlying type - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple( - &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))}, - ), - ); - - // Set to real type now that it has been lowered fully - const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable; - map_ptr.* = debug_union_type; - - return debug_union_type; - } - - var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{}; - defer fields.deinit(gpa); - - try fields.ensureUnusedCapacity(gpa, union_type.loadTagType(ip).names.len); - - const debug_union_fwd_ref = if (layout.tag_size == 0) - debug_fwd_ref - else - try o.builder.debugForwardReference(); - - const tag_type = union_type.loadTagType(ip); - - for (0..tag_type.names.len) |field_index| { - const field_ty = union_type.field_types.get(ip)[field_index]; - if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(pt)) continue; - - const field_size = Type.fromInterned(field_ty).abiSize(pt); - const field_align: InternPool.Alignment = switch (union_type.flagsUnordered(ip).layout) { - .@"packed" => .none, - .auto, .@"extern" => pt.unionFieldNormalAlignment(union_type, @intCast(field_index)), - }; - - const field_name = tag_type.names.get(ip)[field_index]; - fields.appendAssumeCapacity(try o.builder.debugMemberType( - try o.builder.metadataString(field_name.toSlice(ip)), - .none, // File - debug_union_fwd_ref, - 0, // Line - try o.lowerDebugType(Type.fromInterned(field_ty)), - field_size * 8, - (field_align.toByteUnits() orelse 0) * 8, - 0, // Offset - )); - } - - var union_name_buf: ?[:0]const u8 = null; - defer if (union_name_buf) |buf| gpa.free(buf); - const union_name = if (layout.tag_size == 0) name else name: { - union_name_buf = try std.fmt.allocPrintZ(gpa, "{s}:Payload", .{name}); - break :name union_name_buf.?; - }; - - const debug_union_type = try o.builder.debugUnionType( - try o.builder.metadataString(union_name), - .none, // File - o.debug_compile_unit, // Scope - 0, // Line - .none, // Underlying type - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple(fields.items), - ); - - o.builder.debugForwardReferenceSetType(debug_union_fwd_ref, debug_union_type); - - if (layout.tag_size == 0) { - // Set to real type now that it has been lowered fully - const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable; - map_ptr.* = debug_union_type; - - return debug_union_type; - } - - var tag_offset: u64 = undefined; - var payload_offset: u64 = undefined; - if (layout.tag_align.compare(.gte, layout.payload_align)) { - tag_offset = 0; - payload_offset = layout.payload_align.forward(layout.tag_size); - } else { - payload_offset = 0; - tag_offset = layout.tag_align.forward(layout.payload_size); - } - - const debug_tag_type = try o.builder.debugMemberType( - try o.builder.metadataString("tag"), - .none, // File - debug_fwd_ref, - 0, // Line - try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty)), - layout.tag_size * 8, - (layout.tag_align.toByteUnits() orelse 0) * 8, - tag_offset * 8, - ); - - const debug_payload_type = try o.builder.debugMemberType( - try o.builder.metadataString("payload"), - .none, // File - debug_fwd_ref, - 0, // Line - debug_union_type, - layout.payload_size * 8, - (layout.payload_align.toByteUnits() orelse 0) * 8, - payload_offset * 8, - ); - - const full_fields: [2]Builder.Metadata = - if (layout.tag_align.compare(.gte, layout.payload_align)) - .{ debug_tag_type, debug_payload_type } - else - .{ debug_payload_type, debug_tag_type }; - - const debug_tagged_union_type = try o.builder.debugStructType( - try o.builder.metadataString(name), - .none, // File - o.debug_compile_unit, // Scope - 0, // Line - .none, // Underlying type - ty.abiSize(pt) * 8, - (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, - try o.builder.debugTuple(&full_fields), - ); - - o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_tagged_union_type); - - // Set to real type now that it has been lowered fully - const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable; - map_ptr.* = debug_tagged_union_type; - - return debug_tagged_union_type; - }, .Fn => { const fn_info = zcu.typeToFunc(ty).?; @@ -2724,21 +2336,21 @@ pub const Object = struct { if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(pt)) { const sret = firstParamSRet(fn_info, pt, target); const ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type); - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ret_ty)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ret_ty, required_by_runtime)); if (sret) { const ptr_ty = try pt.singleMutPtrType(Type.fromInterned(fn_info.return_type)); - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty, required_by_runtime)); } } else { - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void, required_by_runtime)); } if (Type.fromInterned(fn_info.return_type).isError(zcu) and zcu.comp.config.any_error_tracing) { const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType()); - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty, required_by_runtime)); } for (0..fn_info.param_types.len) |i| { @@ -2747,9 +2359,9 @@ pub const Object = struct { if (isByRef(param_ty, pt)) { const ptr_ty = try pt.singleMutPtrType(param_ty); - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty, required_by_runtime)); } else { - debug_param_types.appendAssumeCapacity(try o.lowerDebugType(param_ty)); + debug_param_types.appendAssumeCapacity(try o.lowerDebugType(param_ty, required_by_runtime)); } } @@ -2769,6 +2381,426 @@ pub const Object = struct { .Frame => @panic("TODO implement lowerDebugType for Frame types"), .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"), + // These are the types that need a correct scope. + .Enum, .Struct, .Union, .Opaque => {}, + } + const fwd_ref = try o.builder.debugForwardReference(); + try o.debug_type_map.put(gpa, ty, fwd_ref); + try o.debug_unresolved_namespace_scopes.put(gpa, ty, required_by_runtime); + + return fwd_ref; + } + + fn genNamespaces(o: *Object) !void { + const gpa = o.gpa; + const pt = o.pt; + const zcu = pt.zcu; + const ip = &zcu.intern_pool; + + var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{}; + defer fields.deinit(gpa); + + const unresolved = &o.debug_unresolved_namespace_scopes; + var unresolved_i: usize = 0; + while (unresolved_i < unresolved.count()) : (unresolved_i += 1) { + const ty = unresolved.keys()[unresolved_i]; + const required_by_runtime = unresolved.values()[unresolved_i]; + + const owner_decl_index = ty.getOwnerDeclOrNull(zcu); + const owner_decl: ?*Zcu.Decl = + if (owner_decl_index) |owner| ip.declPtr(owner) else null; + + const file = if (owner_decl) |owner| + try o.getDebugFile(zcu.namespacePtr(owner.src_namespace).fileScope(zcu)) + else + .none; + const scope = if (owner_decl) |owner| + try o.namespaceToDebugScope(owner.src_namespace) + else + o.debug_compile_unit; + const line = if (owner_decl) |owner| owner.typeSrcLine(zcu) + 1 else 0; + + const name = if (owner_decl) |owner| owner.name.toSlice(ip) else try o.allocTypeName(ty); + defer if (owner_decl == null) gpa.free(name); + + const fwd_ref = o.debug_type_map.get(ty).?; + + fields.clearRetainingCapacity(); + + const ns = if (ty.getNamespace(zcu)) |n| n.unwrap() else null; + if (ns) |ns_id| { + const namespace = ip.namespacePtr(ns_id); + try fields.ensureUnusedCapacity(gpa, namespace.decls.keys().len); + + for (namespace.decls.keys()) |decl_id| { + const decl = ip.declPtr(decl_id); + const decl_name = decl.name.toSlice(ip); + + if (!decl.has_tv) continue; + if (decl.kind != .named) continue; + if (decl.analysis != .complete) continue; + + const decl_line = 0; + + if (decl.val.typeOf(zcu).ip_index == .type_type) { + const nested_type = decl.val.toType(); + // If this decl is the owner of the type, it will + // already have been declared as a direct child and + // will not need to be typedef'd. + if (nested_type.getOwnerDeclOrNull(zcu)) |owner| { + if (owner == decl_id) continue; + } + + switch (nested_type.zigTypeTag(zcu)) { + // We still may want these for a Zig expression + // evaluator in debuggers, but for now they are + // completely useless. + .ComptimeInt, .ComptimeFloat, .Type, .Undefined, .Null, .EnumLiteral => continue, + else => {}, + } + + fields.appendAssumeCapacity(try o.builder.debugTypedef( + try o.builder.metadataString(decl_name), + try o.getDebugFile(namespace.fileScope(zcu)), + fwd_ref, + decl_line, + try o.lowerDebugType(nested_type, false), + 0, // Align + )); + } + } + } + + if (!required_by_runtime) { + const res = try o.makeNamespaceDebugType(owner_decl_index.?, fields.items); + o.builder.debugForwardReferenceSetType(fwd_ref, res); + continue; + } + + const res = switch (ty.zigTypeTag(zcu)) { + .Enum => res: { + if (!ty.hasRuntimeBitsIgnoreComptime(pt)) { + break :res try o.makeNamespaceDebugType(owner_decl_index.?, fields.items); + } + + const enum_type = ip.loadEnumType(ty.toIntern()); + + const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len); + defer gpa.free(enumerators); + + const int_ty = Type.fromInterned(enum_type.tag_ty); + const int_info = ty.intInfo(zcu); + assert(int_info.bits != 0); + + for (enum_type.names.get(ip), 0..) |field_name_ip, i| { + var bigint_space: Value.BigIntSpace = undefined; + const bigint = if (enum_type.values.len != 0) + Value.fromInterned(enum_type.values.get(ip)[i]).toBigInt(&bigint_space, pt) + else + std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst(); + + enumerators[i] = try o.builder.debugEnumerator( + try o.builder.metadataString(field_name_ip.toSlice(ip)), + int_info.signedness == .unsigned, + int_info.bits, + bigint, + ); + } + + const debug_enum_type = try o.builder.debugEnumerationType( + try o.builder.metadataString(name), + file, + scope, + line, + try o.lowerDebugType(int_ty, required_by_runtime), + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple(enumerators), + ); + + try o.debug_enums.append(gpa, debug_enum_type); + break :res debug_enum_type; + }, + .Opaque => res: { + if (ty.toIntern() == .anyopaque_type) { + break :res try o.builder.debugSignedType( + try o.builder.metadataString("anyopaque"), + 0, + ); + } + + const debug_opaque_type = try o.builder.debugStructType( + try o.builder.metadataString(name), + file, + scope, + line, + .none, // Underlying type + 0, // Size + 0, // Align + .none, // Fields + false, // ByRef + ); + break :res debug_opaque_type; + }, + .Struct => res: { + if (zcu.typeToPackedStruct(ty)) |struct_type| { + const backing_int_ty = struct_type.backingIntTypeUnordered(ip); + if (backing_int_ty != .none) { + const info = Type.fromInterned(backing_int_ty).intInfo(zcu); + const builder_name = try o.builder.metadataString(name); + const debug_int_type = switch (info.signedness) { + .signed => try o.builder.debugSignedType(builder_name, ty.abiSize(pt) * 8), + .unsigned => try o.builder.debugUnsignedType(builder_name, ty.abiSize(pt) * 8), + }; + break :res debug_int_type; + } + } + + switch (ip.indexToKey(ty.toIntern())) { + .anon_struct_type => |tuple| { + try fields.ensureUnusedCapacity(gpa, tuple.types.len); + + comptime assert(struct_layout_version == 2); + var offset: u64 = 0; + + for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { + if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(pt)) continue; + + const field_size = Type.fromInterned(field_ty).abiSize(pt); + const field_align = Type.fromInterned(field_ty).abiAlignment(pt); + const field_offset = field_align.forward(offset); + offset = field_offset + field_size; + + const field_name = if (tuple.names.len != 0) + tuple.names.get(ip)[i].toSlice(ip) + else + try std.fmt.allocPrintZ(gpa, "{d}", .{i}); + defer if (tuple.names.len == 0) gpa.free(field_name); + + fields.appendAssumeCapacity(try o.builder.debugMemberType( + try o.builder.metadataString(field_name), + .none, // File + fwd_ref, + 0, + try o.lowerDebugType(Type.fromInterned(field_ty), required_by_runtime), + field_size * 8, + (field_align.toByteUnits() orelse 0) * 8, + field_offset * 8, + )); + } + + const debug_struct_type = try o.builder.debugStructType( + try o.builder.metadataString(name), + file, + scope, + 0, // Line + .none, // Underlying type + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple(fields.items), + isByRef(ty, pt), + ); + + break :res debug_struct_type; + }, + else => {}, + } + + if (!ty.hasRuntimeBitsIgnoreComptime(pt)) { + break :res try o.makeNamespaceDebugType(owner_decl_index.?, fields.items); + } + const struct_type = zcu.typeToStruct(ty).?; + + if (!struct_type.haveLayout(ip) or !struct_type.haveFieldTypes(ip)) { + break :res try o.makeNamespaceDebugType(owner_decl_index.?, fields.items); + } + + try fields.ensureUnusedCapacity(gpa, struct_type.field_types.len); + + comptime assert(struct_layout_version == 2); + var it = struct_type.iterateRuntimeOrder(ip); + while (it.next()) |field_index| { + const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_index]); + if (!field_ty.hasRuntimeBitsIgnoreComptime(pt)) continue; + const field_size = field_ty.abiSize(pt); + const field_align = pt.structFieldAlignment( + struct_type.fieldAlign(ip, field_index), + field_ty, + struct_type.layout, + ); + const field_offset = ty.structFieldOffset(field_index, pt); + + const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse + try ip.getOrPutStringFmt(gpa, pt.tid, "{d}", .{field_index}, .no_embedded_nulls); + + fields.appendAssumeCapacity(try o.builder.debugMemberType( + try o.builder.metadataString(field_name.toSlice(ip)), + file, + fwd_ref, + 0, // Line + try o.lowerDebugType(field_ty, required_by_runtime), + field_size * 8, + (field_align.toByteUnits() orelse 0) * 8, + field_offset * 8, + )); + } + + const debug_struct_type = try o.builder.debugStructType( + try o.builder.metadataString(name), + file, + scope, + line, + .none, // Underlying type + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple(fields.items), + isByRef(ty, pt), + ); + + break :res debug_struct_type; + }, + .Union => res: { + const union_type = ip.loadUnionType(ty.toIntern()); + if (!union_type.haveFieldTypes(ip) or + !ty.hasRuntimeBitsIgnoreComptime(pt) or + !union_type.haveLayout(ip)) + { + break :res try o.makeNamespaceDebugType(owner_decl_index.?, fields.items); + } + + const layout = pt.getUnionLayout(union_type); + + if (layout.payload_size == 0) { + const debug_union_type = try o.builder.debugStructType( + try o.builder.metadataString(name), + file, + scope, + 0, // Line + .none, // Underlying type + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple( + &.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty), required_by_runtime)}, + ), + isByRef(ty, pt), + ); + + break :res debug_union_type; + } + + try fields.ensureUnusedCapacity(gpa, union_type.loadTagType(ip).names.len); + + const debug_union_fwd_ref = if (layout.tag_size == 0) + fwd_ref + else + try o.builder.debugForwardReference(); + + const tag_type = union_type.loadTagType(ip); + + for (0..tag_type.names.len) |field_index| { + const field_ty = union_type.field_types.get(ip)[field_index]; + if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(pt)) continue; + + const field_size = Type.fromInterned(field_ty).abiSize(pt); + const field_align: InternPool.Alignment = switch (union_type.flagsUnordered(ip).layout) { + .@"packed" => .none, + .auto, .@"extern" => pt.unionFieldNormalAlignment(union_type, @intCast(field_index)), + }; + + const field_name = tag_type.names.get(ip)[field_index]; + fields.appendAssumeCapacity(try o.builder.debugMemberType( + try o.builder.metadataString(field_name.toSlice(ip)), + file, + debug_union_fwd_ref, + 0, // Line + try o.lowerDebugType(Type.fromInterned(field_ty), required_by_runtime), + field_size * 8, + (field_align.toByteUnits() orelse 0) * 8, + 0, // Offset + )); + } + + var union_name_buf: ?[:0]const u8 = null; + defer if (union_name_buf) |buf| gpa.free(buf); + const union_name = if (layout.tag_size == 0) name else name: { + union_name_buf = try std.fmt.allocPrintZ(gpa, "{s}:Payload", .{name}); + break :name union_name_buf.?; + }; + + const debug_union_type = try o.builder.debugUnionType( + try o.builder.metadataString(union_name), + file, + scope, + line, + .none, // Underlying type + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple(fields.items), + isByRef(ty, pt), + ); + + if (layout.tag_size == 0) { + break :res debug_union_type; + } + + o.builder.debugForwardReferenceSetType(debug_union_fwd_ref, debug_union_type); + + var tag_offset: u64 = undefined; + var payload_offset: u64 = undefined; + if (layout.tag_align.compare(.gte, layout.payload_align)) { + tag_offset = 0; + payload_offset = layout.payload_align.forward(layout.tag_size); + } else { + payload_offset = 0; + tag_offset = layout.tag_align.forward(layout.payload_size); + } + + const debug_tag_type = try o.builder.debugMemberType( + try o.builder.metadataString("tag"), + file, // File + fwd_ref, + 0, // Line + try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty), required_by_runtime), + layout.tag_size * 8, + (layout.tag_align.toByteUnits() orelse 0) * 8, + tag_offset * 8, + ); + + const debug_payload_type = try o.builder.debugMemberType( + try o.builder.metadataString("payload"), + file, + fwd_ref, + 0, // Line + debug_union_type, + layout.payload_size * 8, + (layout.payload_align.toByteUnits() orelse 0) * 8, + payload_offset * 8, + ); + + const full_fields: [2]Builder.Metadata = + if (layout.tag_align.compare(.gte, layout.payload_align)) + .{ debug_tag_type, debug_payload_type } + else + .{ debug_payload_type, debug_tag_type }; + + const debug_tagged_union_type = try o.builder.debugStructType( + try o.builder.metadataString(name), + file, // File + scope, + line, + .none, // Underlying type + ty.abiSize(pt) * 8, + (ty.abiAlignment(pt).toByteUnits() orelse 0) * 8, + try o.builder.debugTuple(&full_fields), + isByRef(ty, pt), + ); + + break :res debug_tagged_union_type; + }, + else => unreachable, // Handled above. + }; + + o.builder.debugForwardReferenceSetType(fwd_ref, res); } } @@ -2778,14 +2810,10 @@ pub const Object = struct { const file_scope = namespace.fileScope(zcu); if (namespace.parent == .none) return try o.getDebugFile(file_scope); - const gop = try o.debug_unresolved_namespace_scopes.getOrPut(o.gpa, namespace_index); - - if (!gop.found_existing) gop.value_ptr.* = try o.builder.debugForwardReference(); - - return gop.value_ptr.*; + return o.lowerDebugType(zcu.declPtr(namespace.decl_index).val.toType(), false); } - fn makeEmptyNamespaceDebugType(o: *Object, decl_index: InternPool.DeclIndex) !Builder.Metadata { + fn makeNamespaceDebugType(o: *Object, decl_index: InternPool.DeclIndex, fields: []const Builder.Metadata) !Builder.Metadata { const zcu = o.pt.zcu; const decl = zcu.declPtr(decl_index); const file_scope = zcu.namespacePtr(decl.src_namespace).fileScope(zcu); @@ -2797,7 +2825,8 @@ pub const Object = struct { .none, 0, 0, - .none, + if (fields.len == 0) .none else try o.builder.debugTuple(fields), + false, // is_byref ); } @@ -4711,16 +4740,33 @@ pub const DeclGen = struct { if (!owner_mod.strip) { const debug_file = try o.getDebugFile(file_scope); + const linkage_name = try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)); + const is_internal_linkage = !decl.isExtern(zcu); + + const ty = try o.lowerDebugType(decl.typeOf(zcu), true); const debug_global_var = try o.builder.debugGlobalVar( - try o.builder.metadataString(decl.name.toSlice(ip)), // Name - try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name - debug_file, // File - debug_file, // Scope + linkage_name, + linkage_name, + debug_file, + debug_file, line_number, - try o.lowerDebugType(decl.typeOf(zcu)), + ty, variable_index, - .{ .local = !decl.isExtern(zcu) }, + is_internal_linkage, ); + if (is_internal_linkage) { + const name = try o.builder.metadataString(decl.name.toSlice(ip)); + const debug_scope = try o.namespaceToDebugScope(decl.src_namespace); + + const import = try o.builder.debugImportDeclaration( + name, + debug_file, + debug_scope, + line_number, + debug_global_var, + ); + try o.debug_imports.append(o.gpa, import); + } const debug_expression = try o.builder.debugExpression(&.{}); @@ -5171,11 +5217,12 @@ pub const FuncGen = struct { self.scope = try o.builder.debugSubprogram( self.file, + self.file, // TODO Get the correct scope into here—self.scope is the function's *inner* scope. try o.builder.metadataString(decl.name.toSlice(&zcu.intern_pool)), try o.builder.metadataString(decl.fqn.toSlice(&zcu.intern_pool)), line_number, line_number + func.lbrace_line, - try o.lowerDebugType(fn_ty), + try o.lowerDebugType(fn_ty, true), .{ .di_flags = .{ .StaticMember = true }, .sp_flags = .{ @@ -6725,7 +6772,7 @@ pub const FuncGen = struct { self.file, self.scope, self.prev_dbg_line, - try o.lowerDebugType(ptr_ty.childType(mod)), + try o.lowerDebugType(ptr_ty.childType(mod), true), ); _ = try self.wip.callIntrinsic( @@ -6758,7 +6805,7 @@ pub const FuncGen = struct { self.file, self.scope, self.prev_dbg_line, - try o.lowerDebugType(operand_ty), + try o.lowerDebugType(operand_ty, true), ); const pt = o.pt; @@ -8872,7 +8919,7 @@ pub const FuncGen = struct { self.file, self.scope, lbrace_line, - try o.lowerDebugType(inst_ty), + try o.lowerDebugType(inst_ty, true), @intCast(self.arg_index), ); diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index a23bc86c57..7fc0fbdfc0 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -7651,6 +7651,8 @@ pub const Metadata = enum(u32) { composite_vector_type, derived_pointer_type, derived_member_type, + derived_typedef, + imported_declaration, subroutine_type, enumerator_unsigned, enumerator_signed_positive, @@ -7696,6 +7698,8 @@ pub const Metadata = enum(u32) { .composite_vector_type, .derived_pointer_type, .derived_member_type, + .derived_typedef, + .imported_declaration, .subroutine_type, .enumerator_unsigned, .enumerator_signed_positive, @@ -7812,6 +7816,7 @@ pub const Metadata = enum(u32) { producer: MetadataString, enums: Metadata, globals: Metadata, + imports: Metadata, }; pub const Subprogram = struct { @@ -7860,6 +7865,7 @@ pub const Metadata = enum(u32) { } }; + scope: Metadata, file: Metadata, name: MetadataString, linkage_name: MetadataString, @@ -7905,6 +7911,10 @@ pub const Metadata = enum(u32) { align_in_bits_lo: u32, align_in_bits_hi: u32, fields_tuple: Metadata, + flags: packed struct(u32) { + is_byref: bool, + pad: u31 = 0, + }, pub fn bitSize(self: CompositeType) u64 { return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo; @@ -7938,6 +7948,14 @@ pub const Metadata = enum(u32) { } }; + pub const ImportedEntity = struct { + name: MetadataString, + file: Metadata, + scope: Metadata, + line: u32, + entity: Metadata, + }; + pub const SubroutineType = struct { types_tuple: Metadata, }; @@ -7990,10 +8008,6 @@ pub const Metadata = enum(u32) { }; pub const GlobalVar = struct { - pub const Options = struct { - local: bool, - }; - name: MetadataString, linkage_name: MetadataString, file: Metadata, @@ -8224,6 +8238,7 @@ pub const Metadata = enum(u32) { DIBasicType, DICompositeType, DIDerivedType, + DIImportedEntity, DISubroutineType, DIEnumerator, DISubrange, @@ -9961,7 +9976,7 @@ pub fn printUnbuffered( .enums = extra.enums, .retainedTypes = null, .globals = extra.globals, - .imports = null, + .imports = extra.imports, .macros = null, .dwoId = null, .splitDebugInlining = false, @@ -9985,7 +10000,7 @@ pub fn printUnbuffered( try metadata_formatter.specialized(.@"distinct !", .DISubprogram, .{ .name = extra.name, .linkageName = extra.linkage_name, - .scope = extra.file, + .scope = extra.scope, .file = extra.file, .line = extra.line, .type = extra.ty, @@ -10079,8 +10094,8 @@ pub fn printUnbuffered( else => extra.name, }, .scope = extra.scope, - .file = null, - .line = null, + .file = extra.file, + .line = extra.line, .baseType = extra.underlying_type, .size = extra.bitSize(), .@"align" = extra.bitAlign(), @@ -10101,15 +10116,18 @@ pub fn printUnbuffered( }, .derived_pointer_type, .derived_member_type, + .derived_typedef, => |kind| { const extra = self.metadataExtraData(Metadata.DerivedType, metadata_item.data); try metadata_formatter.specialized(.@"!", .DIDerivedType, .{ .tag = @as(enum { DW_TAG_pointer_type, DW_TAG_member, + DW_TAG_typedef, }, switch (kind) { .derived_pointer_type => .DW_TAG_pointer_type, .derived_member_type => .DW_TAG_member, + .derived_typedef => .DW_TAG_typedef, else => unreachable, }), .name = switch (extra.name) { @@ -10132,6 +10150,22 @@ pub fn printUnbuffered( .annotations = null, }, writer); }, + .imported_declaration => { + const extra = self.metadataExtraData(Metadata.ImportedEntity, metadata_item.data); + + try metadata_formatter.specialized(.@"!", .DIImportedEntity, .{ + .tag = .DW_TAG_imported_declaration, + .scope = extra.scope, + .entity = extra.entity, + .file = extra.file, + .line = extra.line, + .name = switch (extra.name) { + .none => null, + else => extra.name, + }, + .elements = null, + }, writer); + }, .subroutine_type => { const extra = self.metadataExtraData(Metadata.SubroutineType, metadata_item.data); try metadata_formatter.specialized(.@"!", .DISubroutineType, .{ @@ -10255,11 +10289,7 @@ pub fn printUnbuffered( .file = extra.file, .line = extra.line, .type = extra.ty, - .isLocal = switch (kind) { - .global_var => false, - .@"global_var local" => true, - else => unreachable, - }, + .isLocal = kind != .global_var, .isDefinition = true, .declaration = null, .templateParams = null, @@ -11612,7 +11642,17 @@ fn addMetadataExtraAssumeCapacity(self: *Builder, extra: anytype) Metadata.Item. u32 => value, MetadataString, Metadata, Variable.Index, Value => @intFromEnum(value), Metadata.DIFlags => @bitCast(value), - else => @compileError("bad field type: " ++ @typeName(field.type)), + else => blk: { + switch (@typeInfo(field.type)) { + .Struct => |s| { + if (s.backing_integer == u32) + break :blk @bitCast(value); + @compileLog(s.layout, s.backing_integer); + }, + else => {}, + } + @compileError("bad field type: " ++ @typeName(field.type)); + }, }); } return result; @@ -11651,7 +11691,7 @@ fn metadataExtraDataTrail( u32 => value, MetadataString, Metadata, Variable.Index, Value => @enumFromInt(value), Metadata.DIFlags => @bitCast(value), - else => @compileError("bad field type: " ++ @typeName(field.type)), + else => @bitCast(value), }; return .{ .data = result, @@ -11740,15 +11780,17 @@ pub fn debugCompileUnit( producer: MetadataString, enums: Metadata, globals: Metadata, + imports: Metadata, options: Metadata.CompileUnit.Options, ) Allocator.Error!Metadata { try self.ensureUnusedMetadataCapacity(1, Metadata.CompileUnit, 0); - return self.debugCompileUnitAssumeCapacity(file, producer, enums, globals, options); + return self.debugCompileUnitAssumeCapacity(file, producer, enums, globals, imports, options); } pub fn debugSubprogram( self: *Builder, file: Metadata, + scope: Metadata, name: MetadataString, linkage_name: MetadataString, line: u32, @@ -11760,6 +11802,7 @@ pub fn debugSubprogram( try self.ensureUnusedMetadataCapacity(1, Metadata.Subprogram, 0); return self.debugSubprogramAssumeCapacity( file, + scope, name, linkage_name, line, @@ -11815,6 +11858,7 @@ pub fn debugStructType( size_in_bits: u64, align_in_bits: u64, fields_tuple: Metadata, + is_byref: bool, ) Allocator.Error!Metadata { try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0); return self.debugStructTypeAssumeCapacity( @@ -11826,6 +11870,7 @@ pub fn debugStructType( size_in_bits, align_in_bits, fields_tuple, + is_byref, ); } @@ -11839,6 +11884,7 @@ pub fn debugUnionType( size_in_bits: u64, align_in_bits: u64, fields_tuple: Metadata, + is_byref: bool, ) Allocator.Error!Metadata { try self.ensureUnusedMetadataCapacity(1, Metadata.CompositeType, 0); return self.debugUnionTypeAssumeCapacity( @@ -11850,6 +11896,7 @@ pub fn debugUnionType( size_in_bits, align_in_bits, fields_tuple, + is_byref, ); } @@ -11973,6 +12020,53 @@ pub fn debugMemberType( ); } +pub fn debugTypedef( + self: *Builder, + name: MetadataString, + file: Metadata, + scope: Metadata, + line: u32, + underlying_type: Metadata, + align_in_bits: u64, +) Allocator.Error!Metadata { + try self.ensureUnusedMetadataCapacity(1, Metadata.DerivedType, 0); + + assert(!self.strip); + return self.metadataSimpleAssumeCapacity(.derived_typedef, Metadata.DerivedType{ + .name = name, + .file = file, + .scope = scope, + .line = line, + .underlying_type = underlying_type, + .size_in_bits_lo = 0, + .size_in_bits_hi = 0, + .align_in_bits_lo = @truncate(align_in_bits), + .align_in_bits_hi = @truncate(align_in_bits >> 32), + .offset_in_bits_lo = 0, + .offset_in_bits_hi = 0, + }); +} + +pub fn debugImportDeclaration( + self: *Builder, + name: MetadataString, + file: Metadata, + scope: Metadata, + line: u32, + entity: Metadata, +) Allocator.Error!Metadata { + try self.ensureUnusedMetadataCapacity(1, Metadata.ImportedEntity, 0); + + assert(!self.strip); + return self.metadataSimpleAssumeCapacity(.imported_declaration, Metadata.ImportedEntity{ + .name = name, + .file = file, + .scope = scope, + .line = line, + .entity = entity, + }); +} + pub fn debugSubroutineType( self: *Builder, types_tuple: Metadata, @@ -12063,7 +12157,7 @@ pub fn debugGlobalVar( line: u32, ty: Metadata, variable: Variable.Index, - options: Metadata.GlobalVar.Options, + internal: bool, ) Allocator.Error!Metadata { try self.ensureUnusedMetadataCapacity(1, Metadata.GlobalVar, 0); return self.debugGlobalVarAssumeCapacity( @@ -12074,7 +12168,7 @@ pub fn debugGlobalVar( line, ty, variable, - options, + internal, ); } @@ -12207,6 +12301,7 @@ pub fn debugCompileUnitAssumeCapacity( producer: MetadataString, enums: Metadata, globals: Metadata, + imports: Metadata, options: Metadata.CompileUnit.Options, ) Metadata { assert(!self.strip); @@ -12217,6 +12312,7 @@ pub fn debugCompileUnitAssumeCapacity( .producer = producer, .enums = enums, .globals = globals, + .imports = imports, }, ); } @@ -12224,6 +12320,7 @@ pub fn debugCompileUnitAssumeCapacity( fn debugSubprogramAssumeCapacity( self: *Builder, file: Metadata, + scope: Metadata, name: MetadataString, linkage_name: MetadataString, line: u32, @@ -12237,6 +12334,7 @@ fn debugSubprogramAssumeCapacity( @as(u3, @truncate(@as(u32, @bitCast(options.sp_flags)) >> 2))); return self.metadataDistinctAssumeCapacity(tag, Metadata.Subprogram{ .file = file, + .scope = scope, .name = name, .linkage_name = linkage_name, .line = line, @@ -12320,6 +12418,7 @@ fn debugStructTypeAssumeCapacity( size_in_bits: u64, align_in_bits: u64, fields_tuple: Metadata, + is_byref: bool, ) Metadata { assert(!self.strip); return self.debugCompositeTypeAssumeCapacity( @@ -12332,6 +12431,7 @@ fn debugStructTypeAssumeCapacity( size_in_bits, align_in_bits, fields_tuple, + is_byref, ); } @@ -12345,6 +12445,7 @@ fn debugUnionTypeAssumeCapacity( size_in_bits: u64, align_in_bits: u64, fields_tuple: Metadata, + is_byref: bool, ) Metadata { assert(!self.strip); return self.debugCompositeTypeAssumeCapacity( @@ -12357,6 +12458,7 @@ fn debugUnionTypeAssumeCapacity( size_in_bits, align_in_bits, fields_tuple, + is_byref, ); } @@ -12382,6 +12484,7 @@ fn debugEnumerationTypeAssumeCapacity( size_in_bits, align_in_bits, fields_tuple, + false, // is_byref ); } @@ -12407,6 +12510,7 @@ fn debugArrayTypeAssumeCapacity( size_in_bits, align_in_bits, fields_tuple, + size_in_bits > 0, // is_byref ); } @@ -12432,6 +12536,7 @@ fn debugVectorTypeAssumeCapacity( size_in_bits, align_in_bits, fields_tuple, + false, ); } @@ -12446,6 +12551,7 @@ fn debugCompositeTypeAssumeCapacity( size_in_bits: u64, align_in_bits: u64, fields_tuple: Metadata, + is_byref: bool, ) Metadata { assert(!self.strip); return self.metadataSimpleAssumeCapacity(tag, Metadata.CompositeType{ @@ -12459,6 +12565,7 @@ fn debugCompositeTypeAssumeCapacity( .align_in_bits_lo = @truncate(align_in_bits), .align_in_bits_hi = @truncate(align_in_bits >> 32), .fields_tuple = fields_tuple, + .flags = .{ .is_byref = is_byref }, }); } @@ -12769,11 +12876,11 @@ fn debugGlobalVarAssumeCapacity( line: u32, ty: Metadata, variable: Variable.Index, - options: Metadata.GlobalVar.Options, + internal: bool, ) Metadata { assert(!self.strip); return self.metadataDistinctAssumeCapacity( - if (options.local) .@"global_var local" else .global_var, + if (internal) .@"global_var local" else .global_var, Metadata.GlobalVar{ .name = name, .linkage_name = linkage_name, @@ -13804,6 +13911,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co }, .enums = extra.enums, .globals = extra.globals, + .imports = extra.imports, }, metadata_adapter); }, .subprogram, @@ -13818,7 +13926,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co const extra = self.metadataExtraData(Metadata.Subprogram, data); try metadata_block.writeAbbrevAdapted(MetadataBlock.Subprogram{ - .scope = extra.file, + .scope = extra.scope, .name = extra.name, .linkage_name = extra.linkage_name, .file = extra.file, @@ -13892,18 +14000,24 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co .underlying_type = extra.underlying_type, .size_in_bits = extra.bitSize(), .align_in_bits = extra.bitAlign(), - .flags = if (kind == .composite_vector_type) .{ .Vector = true } else .{}, + .flags = .{ + .Vector = kind == .composite_vector_type, + .EnumClass = kind == .composite_enumeration_type, + .TypePassbyReference = extra.flags.is_byref, + }, .elements = extra.fields_tuple, }, metadata_adapter); }, .derived_pointer_type, .derived_member_type, + .derived_typedef, => |kind| { const extra = self.metadataExtraData(Metadata.DerivedType, data); try metadata_block.writeAbbrevAdapted(MetadataBlock.DerivedType{ .tag = switch (kind) { .derived_pointer_type => DW.TAG.pointer_type, .derived_member_type => DW.TAG.member, + .derived_typedef => DW.TAG.typedef, else => unreachable, }, .name = extra.name, @@ -13914,6 +14028,20 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co .size_in_bits = extra.bitSize(), .align_in_bits = extra.bitAlign(), .offset_in_bits = extra.bitOffset(), + .flags = .{ + .StaticMember = false, + }, + }, metadata_adapter); + }, + .imported_declaration => { + const extra = self.metadataExtraData(Metadata.ImportedEntity, data); + try metadata_block.writeAbbrevAdapted(MetadataBlock.ImportedEntity{ + .tag = DW.TAG.imported_declaration, + .scope = extra.scope, + .entity = extra.entity, + .line = extra.line, + .name = extra.name, + .file = extra.file, }, metadata_adapter); }, .subroutine_type => { diff --git a/src/codegen/llvm/ir.zig b/src/codegen/llvm/ir.zig index 6a7c6c6857..2373e626c3 100644 --- a/src/codegen/llvm/ir.zig +++ b/src/codegen/llvm/ir.zig @@ -649,6 +649,7 @@ pub const MetadataBlock = struct { BasicType, CompositeType, DerivedType, + ImportedEntity, SubroutineType, Enumerator, Subrange, @@ -694,7 +695,7 @@ pub const MetadataBlock = struct { pub const ops = [_]AbbrevOp{ .{ .literal = 20 }, .{ .literal = 1 }, // is distinct - .{ .literal = std.dwarf.LANG.C99 }, // source language + .{ .literal = std.dwarf.LANG.C_plus_plus_11 }, // source language MetadataAbbrev, // file MetadataAbbrev, // producer .{ .fixed = 1 }, // isOptimized @@ -706,7 +707,7 @@ pub const MetadataBlock = struct { .{ .literal = 0 }, // retained types .{ .literal = 0 }, // subprograms MetadataAbbrev, // globals - .{ .literal = 0 }, // imported entities + MetadataAbbrev, // imported entities .{ .literal = 0 }, // DWO ID .{ .literal = 0 }, // macros .{ .literal = 0 }, // split debug inlining @@ -722,6 +723,7 @@ pub const MetadataBlock = struct { is_optimized: bool, enums: Builder.Metadata, globals: Builder.Metadata, + imports: Builder.Metadata, }; pub const Subprogram = struct { @@ -863,7 +865,7 @@ pub const MetadataBlock = struct { .{ .vbr = 6 }, // size in bits .{ .vbr = 6 }, // align in bits .{ .vbr = 6 }, // offset in bits - .{ .literal = 0 }, // flags + .{ .fixed = 32 }, // flags .{ .literal = 0 }, // extra data }; @@ -876,6 +878,28 @@ pub const MetadataBlock = struct { size_in_bits: u64, align_in_bits: u64, offset_in_bits: u64, + flags: Builder.Metadata.DIFlags, + }; + + pub const ImportedEntity = struct { + pub const ops = [_]AbbrevOp{ + .{ .literal = 31 }, + .{ .literal = 0 }, // is distinct + .{ .fixed = 32 }, // tag + MetadataAbbrev, // scope + MetadataAbbrev, // entity + LineAbbrev, // line + MetadataAbbrev, // name + MetadataAbbrev, // file + .{ .literal = 0 }, // elements + }; + + tag: u32, + scope: Builder.Metadata, + entity: Builder.Metadata, + line: u32, + name: Builder.MetadataString, + file: Builder.Metadata, }; pub const SubroutineType = struct { diff --git a/test/cases/llvm/debug_types.zig b/test/cases/llvm/debug_types.zig new file mode 100644 index 0000000000..27bd1b3c61 --- /dev/null +++ b/test/cases/llvm/debug_types.zig @@ -0,0 +1,23 @@ +const Ty = struct { + pub const A = void; + pub const B = @Vector(2, u0); + pub const C = u0; + pub const D = enum (u0) {}; + pub const E = type; + pub const F = 1; + pub const G = 1.0; + pub const H = undefined; + pub const I = null; + pub const J = .foo; +}; +pub fn main() void { + inline for (@typeInfo(Ty).Struct.decls) |d|{ + _ = @field(Ty, d.name); + } +} + +// compile +// output_mode=Exe +// backend=llvm +// target=x86_64-linux,x86_64-macos +// \ No newline at end of file