authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-07 21:10:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:58:53-07:00
log40c0bdd3850c0df22a98ad9293d36091d76210c4
tree57939c51d1432c62a8de4720ee11100d03e40b1e
parent0d24bc7da0b85c6b178b918f963fde94d8e10ee7

LLVM: memoize debug types and add enum debug types


2 files changed, 113 insertions(+), 22 deletions(-)

src/codegen/llvm.zig+112-20
......@@ -188,6 +188,7 @@ pub const Object = struct {
188188 /// The backing memory for `type_map`. Periodically garbage collected after flush().
189189 /// The code for doing the periodical GC is not yet implemented.
190190 type_map_arena: std.heap.ArenaAllocator,
191 di_type_map: DITypeMap,
191192 /// The LLVM global table which holds the names corresponding to Zig errors.
192193 /// Note that the values are not added until flushModule, when all errors in
193194 /// the compilation are known.
......@@ -200,6 +201,13 @@ pub const Object = struct {
200201 std.hash_map.default_max_load_percentage,
201202 );
202203
204 pub const DITypeMap = std.HashMapUnmanaged(
205 Type,
206 *llvm.DIType,
207 Type.HashContext64,
208 std.hash_map.default_max_load_percentage,
209 );
210
203211 pub fn create(gpa: Allocator, options: link.Options) !*Object {
204212 const obj = try gpa.create(Object);
205213 errdefer gpa.destroy(obj);
......@@ -336,6 +344,7 @@ pub const Object = struct {
336344 .decl_map = .{},
337345 .type_map = .{},
338346 .type_map_arena = std.heap.ArenaAllocator.init(gpa),
347 .di_type_map = .{},
339348 .error_name_table = null,
340349 };
341350 }
......@@ -344,6 +353,7 @@ pub const Object = struct {
344353 if (self.di_builder) |dib| {
345354 dib.dispose();
346355 self.di_map.deinit(gpa);
356 self.di_type_map.deinit(gpa);
347357 }
348358 self.target_data.dispose();
349359 self.target_machine.dispose();
......@@ -558,19 +568,7 @@ pub const Object = struct {
558568 var di_scope: ?*llvm.DIScope = null;
559569
560570 if (dg.object.di_builder) |dib| {
561 di_file = s: {
562 const file = decl.src_namespace.file_scope;
563 const gop = try dg.object.di_map.getOrPut(gpa, file);
564 if (!gop.found_existing) {
565 const dir_path = file.pkg.root_src_directory.path orelse ".";
566 const sub_file_path_z = try gpa.dupeZ(u8, file.sub_file_path);
567 defer gpa.free(sub_file_path_z);
568 const dir_path_z = try gpa.dupeZ(u8, dir_path);
569 defer gpa.free(dir_path_z);
570 gop.value_ptr.* = dib.createFile(sub_file_path_z, dir_path_z).toScope();
571 }
572 break :s @ptrCast(*llvm.DIFile, gop.value_ptr.*);
573 };
571 di_file = try dg.object.getDIFile(gpa, decl.src_namespace.file_scope);
574572
575573 const line_number = decl.src_line + 1;
576574 const is_internal_linkage = decl.val.tag() != .extern_fn and
......@@ -718,6 +716,22 @@ pub const Object = struct {
718716 const llvm_value = self.decl_map.get(decl) orelse return;
719717 llvm_value.deleteGlobal();
720718 }
719
720 fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {
721 const gop = try o.di_map.getOrPut(gpa, file);
722 errdefer assert(o.di_map.remove(file));
723 if (gop.found_existing) {
724 return @ptrCast(*llvm.DIFile, gop.value_ptr.*);
725 }
726 const dir_path = file.pkg.root_src_directory.path orelse ".";
727 const sub_file_path_z = try gpa.dupeZ(u8, file.sub_file_path);
728 defer gpa.free(sub_file_path_z);
729 const dir_path_z = try gpa.dupeZ(u8, dir_path);
730 defer gpa.free(dir_path_z);
731 const di_file = o.di_builder.?.createFile(sub_file_path_z, dir_path_z);
732 gop.value_ptr.* = di_file.toScope();
733 return di_file;
734 }
721735};
722736
723737pub const DeclGen = struct {
......@@ -1891,9 +1905,18 @@ pub const DeclGen = struct {
18911905 }
18921906
18931907 fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {
1894 const gpa = dg.gpa;
1908 const gop = try dg.object.di_type_map.getOrPut(dg.gpa, ty);
1909 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 {
18951917 const target = dg.module.getTarget();
18961918 const dib = dg.object.di_builder.?;
1919 const gpa = dg.gpa;
18971920 switch (ty.zigTypeTag()) {
18981921 .Void, .NoReturn => return dib.createBasicType("void", 0, DW.ATE.signed),
18991922 .Int => {
......@@ -1907,12 +1930,54 @@ pub const DeclGen = struct {
19071930 return dib.createBasicType(name, info.bits, dwarf_encoding);
19081931 },
19091932 .Enum => {
1910 @panic("TODO debug info type for enums");
1911 //var buffer: Type.Payload.Bits = undefined;
1912 //const int_ty = ty.intTagType(&buffer);
1913 //const bit_count = int_ty.intInfo(target).bits;
1914 //assert(bit_count != 0);
1915 //return dg.context.intType(bit_count);
1933 const owner_decl = ty.getOwnerDecl();
1934
1935 if (!ty.hasRuntimeBits()) {
1936 return dg.makeEmptyNamespaceDIType(owner_decl);
1937 }
1938
1939 const field_names = ty.enumFields().keys();
1940
1941 const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len);
1942 defer gpa.free(enumerators);
1943
1944 var buf_field_index: Value.Payload.U32 = .{
1945 .base = .{ .tag = .enum_field_index },
1946 .data = undefined,
1947 };
1948 const field_index_val = Value.initPayload(&buf_field_index.base);
1949
1950 for (field_names) |field_name, i| {
1951 const field_name_z = try gpa.dupeZ(u8, field_name);
1952 defer gpa.free(field_name_z);
1953
1954 buf_field_index.data = @intCast(u32, i);
1955 var buf_u64: Value.Payload.U64 = undefined;
1956 const field_int_val = field_index_val.enumToInt(ty, &buf_u64);
1957 // See https://github.com/ziglang/zig/issues/645
1958 const field_int = field_int_val.toSignedInt();
1959 enumerators[i] = dib.createEnumerator(field_name_z, field_int);
1960 }
1961
1962 const di_file = try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope);
1963 const di_scope = try dg.namespaceToDebugScope(owner_decl.src_namespace);
1964
1965 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1966 var buffer: Type.Payload.Bits = undefined;
1967 const int_ty = ty.intTagType(&buffer);
1968
1969 return dib.createEnumerationType(
1970 di_scope,
1971 name,
1972 di_file,
1973 owner_decl.src_node + 1,
1974 ty.abiSize(target) * 8,
1975 ty.abiAlignment(target) * 8,
1976 enumerators.ptr,
1977 @intCast(c_int, enumerators.len),
1978 try lowerDebugType(dg, int_ty),
1979 "",
1980 );
19161981 },
19171982 .Float => {
19181983 const bits = ty.floatBits(target);
......@@ -2302,6 +2367,33 @@ pub const DeclGen = struct {
23022367 }
23032368 }
23042369
2370 fn namespaceToDebugScope(dg: *DeclGen, namespace: *const Module.Namespace) !*llvm.DIScope {
2371 const di_type = try dg.lowerDebugType(namespace.ty);
2372 return di_type.toScope();
2373 }
2374
2375 /// This is to be used instead of void for debug info types, to avoid tripping
2376 /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"'
2377 /// when targeting CodeView (Windows).
2378 fn makeEmptyNamespaceDIType(dg: *DeclGen, decl: *const Module.Decl) !*llvm.DIType {
2379 const fields: [0]*llvm.DIType = .{};
2380 return dg.object.di_builder.?.createStructType(
2381 try dg.namespaceToDebugScope(decl.src_namespace),
2382 decl.name, // TODO use fully qualified name
2383 try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope),
2384 decl.src_line + 1,
2385 0, // size in bits
2386 0, // align in bits
2387 0, // flags
2388 null, // derived from
2389 undefined, // TODO should be able to pass &fields,
2390 fields.len,
2391 0, // run time lang
2392 null, // vtable holder
2393 "", // unique id
2394 );
2395 }
2396
23052397 const ParentPtr = struct {
23062398 ty: Type,
23072399 llvm_ptr: *const llvm.Value,
src/stage1/analyze.cpp+1-2
......@@ -9073,8 +9073,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatu
90739073 for (uint32_t i = 0; i < field_count; i += 1) {
90749074 TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
90759075
9076 // TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t
9077 // http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html
9076 // https://github.com/ziglang/zig/issues/645
90789077 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name),
90799078 bigint_as_signed(&enum_field->value));
90809079 }