authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-07 22:14:22-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:58:53-07:00
log3654ec87707be408cc3bfa9ae7e59f95c4fdf7b3
treed63caa034ad7785f4b23f038ec5e79c69aa66576
parent40c0bdd3850c0df22a98ad9293d36091d76210c4

LLVM: add debug type lowering for ptr, slice, opaque, optional

also fix issue with memoization and recursiveness.

1 files changed, 252 insertions(+), 59 deletions(-)

src/codegen/llvm.zig+252-59
......@@ -1075,15 +1075,13 @@ pub const DeclGen = struct {
10751075 },
10761076 .Optional => {
10771077 var buf: Type.Payload.ElemType = undefined;
1078 const child_type = t.optionalChild(&buf);
1079 if (!child_type.hasRuntimeBits()) {
1078 const child_ty = t.optionalChild(&buf);
1079 if (!child_ty.hasRuntimeBits()) {
10801080 return dg.context.intType(1);
10811081 }
1082 const payload_llvm_ty = try dg.llvmType(child_type);
1082 const payload_llvm_ty = try dg.llvmType(child_ty);
10831083 if (t.isPtrLikeOptional()) {
10841084 return payload_llvm_ty;
1085 } else if (!child_type.hasRuntimeBits()) {
1086 return dg.context.intType(1);
10871085 }
10881086
10891087 const fields: [2]*const llvm.Type = .{
......@@ -1905,20 +1903,19 @@ pub const DeclGen = struct {
19051903 }
19061904
19071905 fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {
1908 const gop = try dg.object.di_type_map.getOrPut(dg.gpa, ty);
1906 const gpa = dg.gpa;
1907 // Be careful not to reference this `gop` variable after any recursive calls
1908 // to `lowerDebugType`.
1909 const gop = try dg.object.di_type_map.getOrPut(gpa, ty);
1910 if (gop.found_existing) return gop.value_ptr.*;
19091911 errdefer assert(dg.object.di_type_map.remove(ty));
1910 if (!gop.found_existing) {
1911 gop.value_ptr.* = try lowerDebugTypeRaw(dg, ty);
1912 }
1913 return gop.value_ptr.*;
1914 }
1915
1916 fn lowerDebugTypeRaw(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {
19171912 const target = dg.module.getTarget();
19181913 const dib = dg.object.di_builder.?;
1919 const gpa = dg.gpa;
19201914 switch (ty.zigTypeTag()) {
1921 .Void, .NoReturn => return dib.createBasicType("void", 0, DW.ATE.signed),
1915 .Void, .NoReturn => {
1916 gop.value_ptr.* = dib.createBasicType("void", 0, DW.ATE.signed);
1917 return gop.value_ptr.*;
1918 },
19221919 .Int => {
19231920 const info = ty.intInfo(target);
19241921 assert(info.bits != 0);
......@@ -1927,13 +1924,18 @@ pub const DeclGen = struct {
19271924 .signed => DW.ATE.signed,
19281925 .unsigned => DW.ATE.unsigned,
19291926 };
1930 return dib.createBasicType(name, info.bits, dwarf_encoding);
1927 gop.value_ptr.* = dib.createBasicType(name, info.bits, dwarf_encoding);
1928 return gop.value_ptr.*;
19311929 },
19321930 .Enum => {
19331931 const owner_decl = ty.getOwnerDecl();
19341932
19351933 if (!ty.hasRuntimeBits()) {
1936 return dg.makeEmptyNamespaceDIType(owner_decl);
1934 const enum_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl);
1935 // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
1936 // means we can't use `gop` anymore.
1937 try dg.object.di_type_map.put(gpa, ty, enum_di_ty);
1938 return enum_di_ty;
19371939 }
19381940
19391941 const field_names = ty.enumFields().keys();
......@@ -1966,7 +1968,7 @@ pub const DeclGen = struct {
19661968 var buffer: Type.Payload.Bits = undefined;
19671969 const int_ty = ty.intTagType(&buffer);
19681970
1969 return dib.createEnumerationType(
1971 const enum_di_ty = dib.createEnumerationType(
19701972 di_scope,
19711973 name,
19721974 di_file,
......@@ -1978,79 +1980,264 @@ pub const DeclGen = struct {
19781980 try lowerDebugType(dg, int_ty),
19791981 "",
19801982 );
1983 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
1984 try dg.object.di_type_map.put(gpa, ty, enum_di_ty);
1985 return enum_di_ty;
19811986 },
19821987 .Float => {
19831988 const bits = ty.floatBits(target);
19841989 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1985 return dib.createBasicType(name, bits, DW.ATE.float);
1990 gop.value_ptr.* = dib.createBasicType(name, bits, DW.ATE.float);
1991 return gop.value_ptr.*;
1992 },
1993 .Bool => {
1994 gop.value_ptr.* = dib.createBasicType("bool", 1, DW.ATE.boolean);
1995 return gop.value_ptr.*;
19861996 },
1987 .Bool => return dib.createBasicType("bool", 1, DW.ATE.boolean),
19881997 .Pointer => {
1998 // Normalize everything that the debug info does not represent.
1999 const ptr_info = ty.ptrInfo().data;
2000
2001 if (ptr_info.sentinel != null or
2002 ptr_info.@"addrspace" != .generic or
2003 ptr_info.bit_offset != 0 or
2004 ptr_info.host_size != 0 or
2005 ptr_info.@"allowzero" or
2006 !ptr_info.mutable or
2007 ptr_info.@"volatile" or
2008 ptr_info.size == .Many or ptr_info.size == .C)
2009 {
2010 var payload: Type.Payload.Pointer = .{
2011 .data = .{
2012 .pointee_type = ptr_info.pointee_type,
2013 .sentinel = null,
2014 .@"align" = ptr_info.@"align",
2015 .@"addrspace" = .generic,
2016 .bit_offset = 0,
2017 .host_size = 0,
2018 .@"allowzero" = false,
2019 .mutable = true,
2020 .@"volatile" = false,
2021 .size = switch (ptr_info.size) {
2022 .Many, .C, .One => .One,
2023 .Slice => .Slice,
2024 },
2025 },
2026 };
2027 const bland_ptr_ty = Type.initPayload(&payload.base);
2028 const ptr_di_ty = try dg.lowerDebugType(bland_ptr_ty);
2029 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2030 try dg.object.di_type_map.put(gpa, ty, ptr_di_ty);
2031 return ptr_di_ty;
2032 }
2033
19892034 if (ty.isSlice()) {
1990 @panic("TODO debug info type for slices");
1991 //var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1992 //const ptr_type = ty.slicePtrFieldType(&buf);
1993
1994 //const fields: [2]*const llvm.Type = .{
1995 // try dg.llvmType(ptr_type),
1996 // try dg.llvmType(Type.usize),
1997 //};
1998 //return dg.context.structType(&fields, fields.len, .False);
2035 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2036 const ptr_ty = ty.slicePtrFieldType(&buf);
2037 const len_ty = Type.usize;
2038
2039 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2040 const di_file: ?*llvm.DIFile = null;
2041 const line = 0;
2042 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
2043 const fwd_decl = dib.createReplaceableCompositeType(
2044 DW.TAG.structure_type,
2045 name.ptr,
2046 compile_unit_scope,
2047 di_file,
2048 line,
2049 );
2050 gop.value_ptr.* = fwd_decl;
2051
2052 const ptr_size = ptr_ty.abiSize(target);
2053 const ptr_align = ptr_ty.abiAlignment(target);
2054 const len_size = len_ty.abiSize(target);
2055 const len_align = len_ty.abiAlignment(target);
2056
2057 var offset: u64 = 0;
2058 offset += ptr_size;
2059 offset = std.mem.alignForwardGeneric(u64, offset, len_align);
2060 const len_offset = offset;
2061
2062 const fields: [2]*llvm.DIType = .{
2063 dib.createMemberType(
2064 fwd_decl.toScope(),
2065 "ptr",
2066 di_file,
2067 line,
2068 ptr_size * 8, // size in bits
2069 ptr_align * 8, // align in bits
2070 0, // offset in bits
2071 0, // flags
2072 try dg.lowerDebugType(ptr_ty),
2073 ),
2074 dib.createMemberType(
2075 fwd_decl.toScope(),
2076 "len",
2077 di_file,
2078 line,
2079 len_size * 8, // size in bits
2080 len_align * 8, // align in bits
2081 len_offset * 8, // offset in bits
2082 0, // flags
2083 try dg.lowerDebugType(len_ty),
2084 ),
2085 };
2086
2087 const replacement_di_type = dib.createStructType(
2088 compile_unit_scope,
2089 name.ptr,
2090 di_file,
2091 line,
2092 ty.abiSize(target) * 8, // size in bits
2093 ty.abiAlignment(target) * 8, // align in bits
2094 0, // flags
2095 null, // derived from
2096 &fields,
2097 fields.len,
2098 0, // run time lang
2099 null, // vtable holder
2100 "", // unique id
2101 );
2102 dib.replaceTemporary(fwd_decl, replacement_di_type);
2103 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2104 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
2105 return replacement_di_type;
19992106 }
20002107
2001 const ptr_info = ty.ptrInfo().data;
20022108 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
20032109 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2004 return dib.createPointerType(
2110 const ptr_di_ty = dib.createPointerType(
20052111 elem_di_ty,
20062112 target.cpu.arch.ptrBitWidth(),
20072113 ty.ptrAlignment(target) * 8,
20082114 name,
20092115 );
2116 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2117 try dg.object.di_type_map.put(gpa, ty, ptr_di_ty);
2118 return ptr_di_ty;
20102119 },
20112120 .Opaque => {
2012 @panic("TODO debug info type for opaque");
2121 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2122 const owner_decl = ty.getOwnerDecl();
2123 const opaque_di_ty = dib.createForwardDeclType(
2124 DW.TAG.structure_type,
2125 name,
2126 try dg.namespaceToDebugScope(owner_decl.src_namespace),
2127 try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope),
2128 owner_decl.src_node + 1,
2129 );
2130 // The recursive call to `lowerDebugType` va `namespaceToDebugScope`
2131 // means we can't use `gop` anymore.
2132 try dg.object.di_type_map.put(gpa, ty, opaque_di_ty);
2133 return opaque_di_ty;
20132134 },
20142135 .Array => {
2015 const elem_di_ty = try lowerDebugType(dg, ty.childType());
2016 return dib.createArrayType(
2136 const array_di_ty = dib.createArrayType(
20172137 ty.abiSize(target) * 8,
20182138 ty.abiAlignment(target) * 8,
2019 elem_di_ty,
2139 try lowerDebugType(dg, ty.childType()),
20202140 @intCast(c_int, ty.arrayLen()),
20212141 );
2142 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2143 try dg.object.di_type_map.put(gpa, ty, array_di_ty);
2144 return array_di_ty;
20222145 },
20232146 .Vector => {
20242147 @panic("TODO debug info type for vector");
20252148 },
20262149 .Optional => {
2027 @panic("TODO debug info type for optional");
2028 //var buf: Type.Payload.ElemType = undefined;
2029 //const child_type = ty.optionalChild(&buf);
2030 //if (!child_type.hasRuntimeBits()) {
2031 // return dg.context.intType(1);
2032 //}
2033 //const payload_llvm_ty = try dg.llvmType(child_type);
2034 //if (ty.isPtrLikeOptional()) {
2035 // return payload_llvm_ty;
2036 //} else if (!child_type.hasRuntimeBits()) {
2037 // return dg.context.intType(1);
2038 //}
2150 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2151 var buf: Type.Payload.ElemType = undefined;
2152 const child_ty = ty.optionalChild(&buf);
2153 if (!child_ty.hasRuntimeBits()) {
2154 gop.value_ptr.* = dib.createBasicType(name, 1, DW.ATE.boolean);
2155 return gop.value_ptr.*;
2156 }
2157 if (ty.isPtrLikeOptional()) {
2158 const ptr_di_ty = try dg.lowerDebugType(child_ty);
2159 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2160 try dg.object.di_type_map.put(gpa, ty, ptr_di_ty);
2161 return ptr_di_ty;
2162 }
20392163
2040 //const fields: [2]*const llvm.Type = .{
2041 // payload_llvm_ty, dg.context.intType(1),
2042 //};
2043 //return dg.context.structType(&fields, fields.len, .False);
2164 const di_file: ?*llvm.DIFile = null;
2165 const line = 0;
2166 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
2167 const fwd_decl = dib.createReplaceableCompositeType(
2168 DW.TAG.structure_type,
2169 name.ptr,
2170 compile_unit_scope,
2171 di_file,
2172 line,
2173 );
2174 gop.value_ptr.* = fwd_decl;
2175
2176 const non_null_ty = Type.bool;
2177 const payload_size = child_ty.abiSize(target);
2178 const payload_align = child_ty.abiAlignment(target);
2179 const non_null_size = non_null_ty.abiSize(target);
2180 const non_null_align = non_null_ty.abiAlignment(target);
2181
2182 var offset: u64 = 0;
2183 offset += payload_size;
2184 offset = std.mem.alignForwardGeneric(u64, offset, non_null_align);
2185 const non_null_offset = offset;
2186
2187 const fields: [2]*llvm.DIType = .{
2188 dib.createMemberType(
2189 fwd_decl.toScope(),
2190 "data",
2191 di_file,
2192 line,
2193 payload_size * 8, // size in bits
2194 payload_align * 8, // align in bits
2195 0, // offset in bits
2196 0, // flags
2197 try dg.lowerDebugType(child_ty),
2198 ),
2199 dib.createMemberType(
2200 fwd_decl.toScope(),
2201 "some",
2202 di_file,
2203 line,
2204 non_null_size * 8, // size in bits
2205 non_null_align * 8, // align in bits
2206 non_null_offset * 8, // offset in bits
2207 0, // flags
2208 try dg.lowerDebugType(non_null_ty),
2209 ),
2210 };
2211
2212 const replacement_di_type = dib.createStructType(
2213 compile_unit_scope,
2214 name.ptr,
2215 di_file,
2216 line,
2217 ty.abiSize(target) * 8, // size in bits
2218 ty.abiAlignment(target) * 8, // align in bits
2219 0, // flags
2220 null, // derived from
2221 &fields,
2222 fields.len,
2223 0, // run time lang
2224 null, // vtable holder
2225 "", // unique id
2226 );
2227 dib.replaceTemporary(fwd_decl, replacement_di_type);
2228 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2229 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
2230 return replacement_di_type;
20442231 },
20452232 .ErrorUnion => {
20462233 const err_set_ty = ty.errorUnionSet();
2047 const err_set_di_ty = try dg.lowerDebugType(err_set_ty);
20482234 const payload_ty = ty.errorUnionPayload();
20492235 if (!payload_ty.hasRuntimeBits()) {
2236 const err_set_di_ty = try dg.lowerDebugType(err_set_ty);
2237 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2238 try dg.object.di_type_map.put(gpa, ty, err_set_di_ty);
20502239 return err_set_di_ty;
20512240 }
2052 const payload_di_ty = try dg.lowerDebugType(payload_ty);
2053
20542241 const name = try ty.nameAlloc(gpa); // TODO this is a leak
20552242 const di_file: ?*llvm.DIFile = null;
20562243 const line = 0;
......@@ -2062,6 +2249,7 @@ pub const DeclGen = struct {
20622249 di_file,
20632250 line,
20642251 );
2252 gop.value_ptr.* = fwd_decl;
20652253
20662254 const err_set_size = err_set_ty.abiSize(target);
20672255 const err_set_align = err_set_ty.abiAlignment(target);
......@@ -2083,7 +2271,7 @@ pub const DeclGen = struct {
20832271 err_set_align * 8, // align in bits
20842272 0, // offset in bits
20852273 0, // flags
2086 err_set_di_ty,
2274 try dg.lowerDebugType(err_set_ty),
20872275 ),
20882276 dib.createMemberType(
20892277 fwd_decl.toScope(),
......@@ -2094,7 +2282,7 @@ pub const DeclGen = struct {
20942282 payload_align * 8, // align in bits
20952283 payload_offset * 8, // offset in bits
20962284 0, // flags
2097 payload_di_ty,
2285 try dg.lowerDebugType(payload_ty),
20982286 ),
20992287 };
21002288
......@@ -2114,13 +2302,15 @@ pub const DeclGen = struct {
21142302 "", // unique id
21152303 );
21162304 dib.replaceTemporary(fwd_decl, replacement_di_type);
2117
2305 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2306 try dg.object.di_type_map.put(gpa, ty, replacement_di_type);
21182307 return replacement_di_type;
21192308 },
21202309 .ErrorSet => {
21212310 // TODO make this a proper enum with all the error codes in it.
21222311 // will need to consider how to take incremental compilation into account.
2123 return dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
2312 gop.value_ptr.* = dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
2313 return gop.value_ptr.*;
21242314 },
21252315 .Struct => {
21262316 @panic("TODO debug info type for struct");
......@@ -2347,11 +2537,14 @@ pub const DeclGen = struct {
23472537 }
23482538 }
23492539
2350 return dib.createSubroutineType(
2540 const fn_di_ty = dib.createSubroutineType(
23512541 param_di_types.items.ptr,
23522542 @intCast(c_int, param_di_types.items.len),
23532543 0,
23542544 );
2545 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2546 try dg.object.di_type_map.put(gpa, ty, fn_di_ty);
2547 return fn_di_ty;
23552548 },
23562549 .ComptimeInt => unreachable,
23572550 .ComptimeFloat => unreachable,