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 {...@@ -1075,15 +1075,13 @@ pub const DeclGen = struct {
1075 },1075 },
1076 .Optional => {1076 .Optional => {
1077 var buf: Type.Payload.ElemType = undefined;1077 var buf: Type.Payload.ElemType = undefined;
1078 const child_type = t.optionalChild(&buf);1078 const child_ty = t.optionalChild(&buf);
1079 if (!child_type.hasRuntimeBits()) {1079 if (!child_ty.hasRuntimeBits()) {
1080 return dg.context.intType(1);1080 return dg.context.intType(1);
1081 }1081 }
1082 const payload_llvm_ty = try dg.llvmType(child_type);1082 const payload_llvm_ty = try dg.llvmType(child_ty);
1083 if (t.isPtrLikeOptional()) {1083 if (t.isPtrLikeOptional()) {
1084 return payload_llvm_ty;1084 return payload_llvm_ty;
1085 } else if (!child_type.hasRuntimeBits()) {
1086 return dg.context.intType(1);
1087 }1085 }
10881086
1089 const fields: [2]*const llvm.Type = .{1087 const fields: [2]*const llvm.Type = .{
...@@ -1905,20 +1903,19 @@ pub const DeclGen = struct {...@@ -1905,20 +1903,19 @@ pub const DeclGen = struct {
1905 }1903 }
19061904
1907 fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {1905 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.*;
1909 errdefer assert(dg.object.di_type_map.remove(ty));1911 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 {
1917 const target = dg.module.getTarget();1912 const target = dg.module.getTarget();
1918 const dib = dg.object.di_builder.?;1913 const dib = dg.object.di_builder.?;
1919 const gpa = dg.gpa;
1920 switch (ty.zigTypeTag()) {1914 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 },
1922 .Int => {1919 .Int => {
1923 const info = ty.intInfo(target);1920 const info = ty.intInfo(target);
1924 assert(info.bits != 0);1921 assert(info.bits != 0);
...@@ -1927,13 +1924,18 @@ pub const DeclGen = struct {...@@ -1927,13 +1924,18 @@ pub const DeclGen = struct {
1927 .signed => DW.ATE.signed,1924 .signed => DW.ATE.signed,
1928 .unsigned => DW.ATE.unsigned,1925 .unsigned => DW.ATE.unsigned,
1929 };1926 };
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.*;
1931 },1929 },
1932 .Enum => {1930 .Enum => {
1933 const owner_decl = ty.getOwnerDecl();1931 const owner_decl = ty.getOwnerDecl();
19341932
1935 if (!ty.hasRuntimeBits()) {1933 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;
1937 }1939 }
19381940
1939 const field_names = ty.enumFields().keys();1941 const field_names = ty.enumFields().keys();
...@@ -1966,7 +1968,7 @@ pub const DeclGen = struct {...@@ -1966,7 +1968,7 @@ pub const DeclGen = struct {
1966 var buffer: Type.Payload.Bits = undefined;1968 var buffer: Type.Payload.Bits = undefined;
1967 const int_ty = ty.intTagType(&buffer);1969 const int_ty = ty.intTagType(&buffer);
19681970
1969 return dib.createEnumerationType(1971 const enum_di_ty = dib.createEnumerationType(
1970 di_scope,1972 di_scope,
1971 name,1973 name,
1972 di_file,1974 di_file,
...@@ -1978,79 +1980,264 @@ pub const DeclGen = struct {...@@ -1978,79 +1980,264 @@ pub const DeclGen = struct {
1978 try lowerDebugType(dg, int_ty),1980 try lowerDebugType(dg, int_ty),
1979 "",1981 "",
1980 );1982 );
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;
1981 },1986 },
1982 .Float => {1987 .Float => {
1983 const bits = ty.floatBits(target);1988 const bits = ty.floatBits(target);
1984 const name = try ty.nameAlloc(gpa); // TODO this is a leak1989 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.*;
1986 },1996 },
1987 .Bool => return dib.createBasicType("bool", 1, DW.ATE.boolean),
1988 .Pointer => {1997 .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
1989 if (ty.isSlice()) {2034 if (ty.isSlice()) {
1990 @panic("TODO debug info type for slices");2035 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1991 //var buf: Type.SlicePtrFieldTypeBuffer = undefined;2036 const ptr_ty = ty.slicePtrFieldType(&buf);
1992 //const ptr_type = ty.slicePtrFieldType(&buf);2037 const len_ty = Type.usize;
19932038
1994 //const fields: [2]*const llvm.Type = .{2039 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1995 // try dg.llvmType(ptr_type),2040 const di_file: ?*llvm.DIFile = null;
1996 // try dg.llvmType(Type.usize),2041 const line = 0;
1997 //};2042 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
1998 //return dg.context.structType(&fields, fields.len, .False);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;
1999 }2106 }
20002107
2001 const ptr_info = ty.ptrInfo().data;
2002 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);2108 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
2003 const name = try ty.nameAlloc(gpa); // TODO this is a leak2109 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2004 return dib.createPointerType(2110 const ptr_di_ty = dib.createPointerType(
2005 elem_di_ty,2111 elem_di_ty,
2006 target.cpu.arch.ptrBitWidth(),2112 target.cpu.arch.ptrBitWidth(),
2007 ty.ptrAlignment(target) * 8,2113 ty.ptrAlignment(target) * 8,
2008 name,2114 name,
2009 );2115 );
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;
2010 },2119 },
2011 .Opaque => {2120 .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;
2013 },2134 },
2014 .Array => {2135 .Array => {
2015 const elem_di_ty = try lowerDebugType(dg, ty.childType());2136 const array_di_ty = dib.createArrayType(
2016 return dib.createArrayType(
2017 ty.abiSize(target) * 8,2137 ty.abiSize(target) * 8,
2018 ty.abiAlignment(target) * 8,2138 ty.abiAlignment(target) * 8,
2019 elem_di_ty,2139 try lowerDebugType(dg, ty.childType()),
2020 @intCast(c_int, ty.arrayLen()),2140 @intCast(c_int, ty.arrayLen()),
2021 );2141 );
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;
2022 },2145 },
2023 .Vector => {2146 .Vector => {
2024 @panic("TODO debug info type for vector");2147 @panic("TODO debug info type for vector");
2025 },2148 },
2026 .Optional => {2149 .Optional => {
2027 @panic("TODO debug info type for optional");2150 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2028 //var buf: Type.Payload.ElemType = undefined;2151 var buf: Type.Payload.ElemType = undefined;
2029 //const child_type = ty.optionalChild(&buf);2152 const child_ty = ty.optionalChild(&buf);
2030 //if (!child_type.hasRuntimeBits()) {2153 if (!child_ty.hasRuntimeBits()) {
2031 // return dg.context.intType(1);2154 gop.value_ptr.* = dib.createBasicType(name, 1, DW.ATE.boolean);
2032 //}2155 return gop.value_ptr.*;
2033 //const payload_llvm_ty = try dg.llvmType(child_type);2156 }
2034 //if (ty.isPtrLikeOptional()) {2157 if (ty.isPtrLikeOptional()) {
2035 // return payload_llvm_ty;2158 const ptr_di_ty = try dg.lowerDebugType(child_ty);
2036 //} else if (!child_type.hasRuntimeBits()) {2159 // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
2037 // return dg.context.intType(1);2160 try dg.object.di_type_map.put(gpa, ty, ptr_di_ty);
2038 //}2161 return ptr_di_ty;
2162 }
20392163
2040 //const fields: [2]*const llvm.Type = .{2164 const di_file: ?*llvm.DIFile = null;
2041 // payload_llvm_ty, dg.context.intType(1),2165 const line = 0;
2042 //};2166 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
2043 //return dg.context.structType(&fields, fields.len, .False);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;
2044 },2231 },
2045 .ErrorUnion => {2232 .ErrorUnion => {
2046 const err_set_ty = ty.errorUnionSet();2233 const err_set_ty = ty.errorUnionSet();
2047 const err_set_di_ty = try dg.lowerDebugType(err_set_ty);
2048 const payload_ty = ty.errorUnionPayload();2234 const payload_ty = ty.errorUnionPayload();
2049 if (!payload_ty.hasRuntimeBits()) {2235 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);
2050 return err_set_di_ty;2239 return err_set_di_ty;
2051 }2240 }
2052 const payload_di_ty = try dg.lowerDebugType(payload_ty);
2053
2054 const name = try ty.nameAlloc(gpa); // TODO this is a leak2241 const name = try ty.nameAlloc(gpa); // TODO this is a leak
2055 const di_file: ?*llvm.DIFile = null;2242 const di_file: ?*llvm.DIFile = null;
2056 const line = 0;2243 const line = 0;
...@@ -2062,6 +2249,7 @@ pub const DeclGen = struct {...@@ -2062,6 +2249,7 @@ pub const DeclGen = struct {
2062 di_file,2249 di_file,
2063 line,2250 line,
2064 );2251 );
2252 gop.value_ptr.* = fwd_decl;
20652253
2066 const err_set_size = err_set_ty.abiSize(target);2254 const err_set_size = err_set_ty.abiSize(target);
2067 const err_set_align = err_set_ty.abiAlignment(target);2255 const err_set_align = err_set_ty.abiAlignment(target);
...@@ -2083,7 +2271,7 @@ pub const DeclGen = struct {...@@ -2083,7 +2271,7 @@ pub const DeclGen = struct {
2083 err_set_align * 8, // align in bits2271 err_set_align * 8, // align in bits
2084 0, // offset in bits2272 0, // offset in bits
2085 0, // flags2273 0, // flags
2086 err_set_di_ty,2274 try dg.lowerDebugType(err_set_ty),
2087 ),2275 ),
2088 dib.createMemberType(2276 dib.createMemberType(
2089 fwd_decl.toScope(),2277 fwd_decl.toScope(),
...@@ -2094,7 +2282,7 @@ pub const DeclGen = struct {...@@ -2094,7 +2282,7 @@ pub const DeclGen = struct {
2094 payload_align * 8, // align in bits2282 payload_align * 8, // align in bits
2095 payload_offset * 8, // offset in bits2283 payload_offset * 8, // offset in bits
2096 0, // flags2284 0, // flags
2097 payload_di_ty,2285 try dg.lowerDebugType(payload_ty),
2098 ),2286 ),
2099 };2287 };
21002288
...@@ -2114,13 +2302,15 @@ pub const DeclGen = struct {...@@ -2114,13 +2302,15 @@ pub const DeclGen = struct {
2114 "", // unique id2302 "", // unique id
2115 );2303 );
2116 dib.replaceTemporary(fwd_decl, replacement_di_type);2304 dib.replaceTemporary(fwd_decl, replacement_di_type);
21172305 // 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);
2118 return replacement_di_type;2307 return replacement_di_type;
2119 },2308 },
2120 .ErrorSet => {2309 .ErrorSet => {
2121 // TODO make this a proper enum with all the error codes in it.2310 // TODO make this a proper enum with all the error codes in it.
2122 // will need to consider how to take incremental compilation into account.2311 // 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.*;
2124 },2314 },
2125 .Struct => {2315 .Struct => {
2126 @panic("TODO debug info type for struct");2316 @panic("TODO debug info type for struct");
...@@ -2347,11 +2537,14 @@ pub const DeclGen = struct {...@@ -2347,11 +2537,14 @@ pub const DeclGen = struct {
2347 }2537 }
2348 }2538 }
23492539
2350 return dib.createSubroutineType(2540 const fn_di_ty = dib.createSubroutineType(
2351 param_di_types.items.ptr,2541 param_di_types.items.ptr,
2352 @intCast(c_int, param_di_types.items.len),2542 @intCast(c_int, param_di_types.items.len),
2353 0,2543 0,
2354 );2544 );
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;
2355 },2548 },
2356 .ComptimeInt => unreachable,2549 .ComptimeInt => unreachable,
2357 .ComptimeFloat => unreachable,2550 .ComptimeFloat => unreachable,