authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2024-02-15 02:26:32+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-15 02:46:18-08:00
log6fe90a913a8876e78692d5e89652559f72e7644f
tree94c14895d96b669ed2f9d10d95a68f746dd73b5a
parentc280811d1d5b5d73e1eb4243c577f86375447e99

llvm: fix lowering of recursive debug info

This change allows recursing over types that are currently being resolved fully with a second pass of forward resolution. Closes #16414

2 files changed, 61 insertions(+), 34 deletions(-)

src/codegen/llvm.zig+49-34
...@@ -1928,17 +1928,26 @@ pub const Object = struct {...@@ -1928,17 +1928,26 @@ pub const Object = struct {
1928 const gop = try o.di_type_map.getOrPut(gpa, ty.toIntern());1928 const gop = try o.di_type_map.getOrPut(gpa, ty.toIntern());
1929 if (gop.found_existing) {1929 if (gop.found_existing) {
1930 const annotated = gop.value_ptr.*;1930 const annotated = gop.value_ptr.*;
1931 const di_type = annotated.toDIType();1931 switch (annotated) {
1932 if (!annotated.isFwdOnly() or resolve == .fwd) {1932 // This type is currently attempting to be resolved fully, so make
1933 return di_type;1933 // sure a second recursion through the types uses forward resolution.
1934 .null => assert(resolve == .fwd),
1935 // This type already has at least forward resolution, only resolve
1936 // fully during full resolution.
1937 _ => {
1938 const di_type = annotated.toDIType();
1939 if (!annotated.isFwdOnly() or resolve == .fwd) {
1940 return di_type;
1941 }
1942 const entry: Object.DITypeMap.Entry = .{
1943 .key_ptr = gop.key_ptr,
1944 .value_ptr = gop.value_ptr,
1945 };
1946 return o.lowerDebugTypeImpl(entry, resolve, di_type);
1947 },
1934 }1948 }
1935 const entry: Object.DITypeMap.Entry = .{1949 } else gop.value_ptr.* = .null;
1936 .key_ptr = gop.key_ptr,1950 errdefer if (!gop.found_existing) assert(o.di_type_map.orderedRemove(ty.toIntern()));
1937 .value_ptr = gop.value_ptr,
1938 };
1939 return o.lowerDebugTypeImpl(entry, resolve, di_type);
1940 }
1941 errdefer assert(o.di_type_map.orderedRemove(ty.toIntern()));
1942 const entry: Object.DITypeMap.Entry = .{1951 const entry: Object.DITypeMap.Entry = .{
1943 .key_ptr = gop.key_ptr,1952 .key_ptr = gop.key_ptr,
1944 .value_ptr = gop.value_ptr,1953 .value_ptr = gop.value_ptr,
...@@ -2041,7 +2050,7 @@ pub const Object = struct {...@@ -2041,7 +2050,7 @@ pub const Object = struct {
2041 ty.abiAlignment(mod).toByteUnits(0) * 8,2050 ty.abiAlignment(mod).toByteUnits(0) * 8,
2042 enumerators.ptr,2051 enumerators.ptr,
2043 @intCast(enumerators.len),2052 @intCast(enumerators.len),
2044 try o.lowerDebugType(int_ty, .full),2053 try o.lowerDebugType(int_ty, resolve),
2045 "",2054 "",
2046 );2055 );
2047 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2056 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
...@@ -2139,7 +2148,7 @@ pub const Object = struct {...@@ -2139,7 +2148,7 @@ pub const Object = struct {
2139 ptr_align.toByteUnits(0) * 8, // align in bits2148 ptr_align.toByteUnits(0) * 8, // align in bits
2140 0, // offset in bits2149 0, // offset in bits
2141 0, // flags2150 0, // flags
2142 try o.lowerDebugType(ptr_ty, .full),2151 try o.lowerDebugType(ptr_ty, resolve),
2143 ),2152 ),
2144 dib.createMemberType(2153 dib.createMemberType(
2145 fwd_decl.toScope(),2154 fwd_decl.toScope(),
...@@ -2150,7 +2159,7 @@ pub const Object = struct {...@@ -2150,7 +2159,7 @@ pub const Object = struct {
2150 len_align.toByteUnits(0) * 8, // align in bits2159 len_align.toByteUnits(0) * 8, // align in bits
2151 len_offset * 8, // offset in bits2160 len_offset * 8, // offset in bits
2152 0, // flags2161 0, // flags
2153 try o.lowerDebugType(len_ty, .full),2162 try o.lowerDebugType(len_ty, resolve),
2154 ),2163 ),
2155 };2164 };
21562165
...@@ -2214,7 +2223,7 @@ pub const Object = struct {...@@ -2214,7 +2223,7 @@ pub const Object = struct {
2214 const array_di_ty = dib.createArrayType(2223 const array_di_ty = dib.createArrayType(
2215 ty.abiSize(mod) * 8,2224 ty.abiSize(mod) * 8,
2216 ty.abiAlignment(mod).toByteUnits(0) * 8,2225 ty.abiAlignment(mod).toByteUnits(0) * 8,
2217 try o.lowerDebugType(ty.childType(mod), .full),2226 try o.lowerDebugType(ty.childType(mod), resolve),
2218 @intCast(ty.arrayLen(mod)),2227 @intCast(ty.arrayLen(mod)),
2219 );2228 );
2220 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2229 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
...@@ -2240,7 +2249,7 @@ pub const Object = struct {...@@ -2240,7 +2249,7 @@ pub const Object = struct {
2240 break :blk dib.createBasicType(name, info.bits, dwarf_encoding);2249 break :blk dib.createBasicType(name, info.bits, dwarf_encoding);
2241 },2250 },
2242 .Bool => dib.createBasicType("bool", 1, DW.ATE.boolean),2251 .Bool => dib.createBasicType("bool", 1, DW.ATE.boolean),
2243 else => try o.lowerDebugType(ty.childType(mod), .full),2252 else => try o.lowerDebugType(ty.childType(mod), resolve),
2244 };2253 };
22452254
2246 const vector_di_ty = dib.createVectorType(2255 const vector_di_ty = dib.createVectorType(
...@@ -2307,7 +2316,7 @@ pub const Object = struct {...@@ -2307,7 +2316,7 @@ pub const Object = struct {
2307 payload_align.toByteUnits(0) * 8, // align in bits2316 payload_align.toByteUnits(0) * 8, // align in bits
2308 0, // offset in bits2317 0, // offset in bits
2309 0, // flags2318 0, // flags
2310 try o.lowerDebugType(child_ty, .full),2319 try o.lowerDebugType(child_ty, resolve),
2311 ),2320 ),
2312 dib.createMemberType(2321 dib.createMemberType(
2313 fwd_decl.toScope(),2322 fwd_decl.toScope(),
...@@ -2318,7 +2327,7 @@ pub const Object = struct {...@@ -2318,7 +2327,7 @@ pub const Object = struct {
2318 non_null_align.toByteUnits(0) * 8, // align in bits2327 non_null_align.toByteUnits(0) * 8, // align in bits
2319 non_null_offset * 8, // offset in bits2328 non_null_offset * 8, // offset in bits
2320 0, // flags2329 0, // flags
2321 try o.lowerDebugType(non_null_ty, .full),2330 try o.lowerDebugType(non_null_ty, resolve),
2322 ),2331 ),
2323 };2332 };
23242333
...@@ -2345,7 +2354,7 @@ pub const Object = struct {...@@ -2345,7 +2354,7 @@ pub const Object = struct {
2345 .ErrorUnion => {2354 .ErrorUnion => {
2346 const payload_ty = ty.errorUnionPayload(mod);2355 const payload_ty = ty.errorUnionPayload(mod);
2347 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {2356 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
2348 const err_set_di_ty = try o.lowerDebugType(Type.anyerror, .full);2357 const err_set_di_ty = try o.lowerDebugType(Type.anyerror, resolve);
2349 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.2358 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2350 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(err_set_di_ty));2359 try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(err_set_di_ty));
2351 return err_set_di_ty;2360 return err_set_di_ty;
...@@ -2399,7 +2408,7 @@ pub const Object = struct {...@@ -2399,7 +2408,7 @@ pub const Object = struct {
2399 error_align.toByteUnits(0) * 8, // align in bits2408 error_align.toByteUnits(0) * 8, // align in bits
2400 error_offset * 8, // offset in bits2409 error_offset * 8, // offset in bits
2401 0, // flags2410 0, // flags
2402 try o.lowerDebugType(Type.anyerror, .full),2411 try o.lowerDebugType(Type.anyerror, resolve),
2403 );2412 );
2404 fields[payload_index] = dib.createMemberType(2413 fields[payload_index] = dib.createMemberType(
2405 fwd_decl.toScope(),2414 fwd_decl.toScope(),
...@@ -2410,7 +2419,7 @@ pub const Object = struct {...@@ -2410,7 +2419,7 @@ pub const Object = struct {
2410 payload_align.toByteUnits(0) * 8, // align in bits2419 payload_align.toByteUnits(0) * 8, // align in bits
2411 payload_offset * 8, // offset in bits2420 payload_offset * 8, // offset in bits
2412 0, // flags2421 0, // flags
2413 try o.lowerDebugType(payload_ty, .full),2422 try o.lowerDebugType(payload_ty, resolve),
2414 );2423 );
24152424
2416 const full_di_ty = dib.createStructType(2425 const full_di_ty = dib.createStructType(
...@@ -2506,7 +2515,7 @@ pub const Object = struct {...@@ -2506,7 +2515,7 @@ pub const Object = struct {
2506 field_align.toByteUnits(0) * 8, // align in bits2515 field_align.toByteUnits(0) * 8, // align in bits
2507 field_offset * 8, // offset in bits2516 field_offset * 8, // offset in bits
2508 0, // flags2517 0, // flags
2509 try o.lowerDebugType(Type.fromInterned(field_ty), .full),2518 try o.lowerDebugType(Type.fromInterned(field_ty), resolve),
2510 ));2519 ));
2511 }2520 }
25122521
...@@ -2584,7 +2593,7 @@ pub const Object = struct {...@@ -2584,7 +2593,7 @@ pub const Object = struct {
2584 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse2593 const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
2585 try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});2594 try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});
25862595
2587 const field_di_ty = try o.lowerDebugType(field_ty, .full);2596 const field_di_ty = try o.lowerDebugType(field_ty, resolve);
25882597
2589 try di_fields.append(gpa, dib.createMemberType(2598 try di_fields.append(gpa, dib.createMemberType(
2590 fwd_decl.toScope(),2599 fwd_decl.toScope(),
...@@ -2653,7 +2662,7 @@ pub const Object = struct {...@@ -2653,7 +2662,7 @@ pub const Object = struct {
2653 const layout = mod.getUnionLayout(union_obj);2662 const layout = mod.getUnionLayout(union_obj);
26542663
2655 if (layout.payload_size == 0) {2664 if (layout.payload_size == 0) {
2656 const tag_di_ty = try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), .full);2665 const tag_di_ty = try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), resolve);
2657 const di_fields = [_]*llvm.DIType{tag_di_ty};2666 const di_fields = [_]*llvm.DIType{tag_di_ty};
2658 const full_di_ty = dib.createStructType(2667 const full_di_ty = dib.createStructType(
2659 compile_unit_scope,2668 compile_unit_scope,
...@@ -2689,7 +2698,7 @@ pub const Object = struct {...@@ -2689,7 +2698,7 @@ pub const Object = struct {
2689 const field_size = Type.fromInterned(field_ty).abiSize(mod);2698 const field_size = Type.fromInterned(field_ty).abiSize(mod);
2690 const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));2699 const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));
26912700
2692 const field_di_ty = try o.lowerDebugType(Type.fromInterned(field_ty), .full);2701 const field_di_ty = try o.lowerDebugType(Type.fromInterned(field_ty), resolve);
2693 const field_name = union_obj.field_names.get(ip)[field_index];2702 const field_name = union_obj.field_names.get(ip)[field_index];
2694 di_fields.appendAssumeCapacity(dib.createMemberType(2703 di_fields.appendAssumeCapacity(dib.createMemberType(
2695 fwd_decl.toScope(),2704 fwd_decl.toScope(),
...@@ -2751,7 +2760,7 @@ pub const Object = struct {...@@ -2751,7 +2760,7 @@ pub const Object = struct {
2751 layout.tag_align.toByteUnits(0) * 8,2760 layout.tag_align.toByteUnits(0) * 8,
2752 tag_offset * 8, // offset in bits2761 tag_offset * 8, // offset in bits
2753 0, // flags2762 0, // flags
2754 try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), .full),2763 try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), resolve),
2755 );2764 );
27562765
2757 const payload_di = dib.createMemberType(2766 const payload_di = dib.createMemberType(
...@@ -2802,21 +2811,21 @@ pub const Object = struct {...@@ -2802,21 +2811,21 @@ pub const Object = struct {
2802 if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(mod)) {2811 if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(mod)) {
2803 const sret = firstParamSRet(fn_info, mod);2812 const sret = firstParamSRet(fn_info, mod);
2804 const di_ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);2813 const di_ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);
2805 try param_di_types.append(try o.lowerDebugType(di_ret_ty, .full));2814 try param_di_types.append(try o.lowerDebugType(di_ret_ty, resolve));
28062815
2807 if (sret) {2816 if (sret) {
2808 const ptr_ty = try mod.singleMutPtrType(Type.fromInterned(fn_info.return_type));2817 const ptr_ty = try mod.singleMutPtrType(Type.fromInterned(fn_info.return_type));
2809 try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));2818 try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
2810 }2819 }
2811 } else {2820 } else {
2812 try param_di_types.append(try o.lowerDebugType(Type.void, .full));2821 try param_di_types.append(try o.lowerDebugType(Type.void, resolve));
2813 }2822 }
28142823
2815 if (Type.fromInterned(fn_info.return_type).isError(mod) and2824 if (Type.fromInterned(fn_info.return_type).isError(mod) and
2816 o.module.comp.config.any_error_tracing)2825 o.module.comp.config.any_error_tracing)
2817 {2826 {
2818 const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());2827 const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());
2819 try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));2828 try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
2820 }2829 }
28212830
2822 for (0..fn_info.param_types.len) |i| {2831 for (0..fn_info.param_types.len) |i| {
...@@ -2825,9 +2834,9 @@ pub const Object = struct {...@@ -2825,9 +2834,9 @@ pub const Object = struct {
28252834
2826 if (isByRef(param_ty, mod)) {2835 if (isByRef(param_ty, mod)) {
2827 const ptr_ty = try mod.singleMutPtrType(param_ty);2836 const ptr_ty = try mod.singleMutPtrType(param_ty);
2828 try param_di_types.append(try o.lowerDebugType(ptr_ty, .full));2837 try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
2829 } else {2838 } else {
2830 try param_di_types.append(try o.lowerDebugType(param_ty, .full));2839 try param_di_types.append(try o.lowerDebugType(param_ty, resolve));
2831 }2840 }
2832 }2841 }
28332842
...@@ -11682,6 +11691,7 @@ const optional_layout_version = 3;...@@ -11682,6 +11691,7 @@ const optional_layout_version = 3;
11682/// whether the type is fully resolved. Types that are only fwd declared11691/// whether the type is fully resolved. Types that are only fwd declared
11683/// have the LSB flipped to a 1.11692/// have the LSB flipped to a 1.
11684const AnnotatedDITypePtr = enum(usize) {11693const AnnotatedDITypePtr = enum(usize) {
11694 null,
11685 _,11695 _,
1168611696
11687 fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {11697 fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {
...@@ -11702,12 +11712,17 @@ const AnnotatedDITypePtr = enum(usize) {...@@ -11702,12 +11712,17 @@ const AnnotatedDITypePtr = enum(usize) {
11702 }11712 }
1170311713
11704 fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {11714 fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {
11705 const fixed_addr = @intFromEnum(self) & ~@as(usize, 1);11715 switch (self) {
11706 return @ptrFromInt(fixed_addr);11716 .null => unreachable,
11717 _ => return @ptrFromInt(@intFromEnum(self) & ~@as(usize, 1)),
11718 }
11707 }11719 }
1170811720
11709 fn isFwdOnly(self: AnnotatedDITypePtr) bool {11721 fn isFwdOnly(self: AnnotatedDITypePtr) bool {
11710 return @as(u1, @truncate(@intFromEnum(self))) != 0;11722 switch (self) {
11723 .null => unreachable,
11724 _ => return @as(u1, @truncate(@intFromEnum(self))) != 0,
11725 }
11711 }11726 }
11712};11727};
1171311728
test/behavior/struct.zig+12
...@@ -2114,3 +2114,15 @@ test "initiate global variable with runtime value" {...@@ -2114,3 +2114,15 @@ test "initiate global variable with runtime value" {
2114 };2114 };
2115 try expect(S.some_struct.field == 1);2115 try expect(S.some_struct.field == 1);
2116}2116}
2117
2118test "struct containing optional pointer to array of @This()" {
2119 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
2120
2121 const S = struct {
2122 x: ?*const [1]@This(),
2123 };
2124
2125 var s: S = .{ .x = &.{.{ .x = null }} };
2126 _ = &s;
2127 try expect(s.x.?[0].x == null);
2128}