authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-07 19:54:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-08 14:58:53-07:00
log0d24bc7da0b85c6b178b918f963fde94d8e10ee7
tree2ce259c1164c931ce1ac87aef5134416b1ae067f
parent627209253c65363483fbdae9effad51f1aed8c98

LLVM: add DISubprogram and DIType lowering; handle dbg_stmt


3 files changed, 589 insertions(+), 32 deletions(-)

lib/std/dwarf.zig+15
...@@ -226,6 +226,21 @@ pub const LNCT = struct {...@@ -226,6 +226,21 @@ pub const LNCT = struct {
226 pub const hi_user = 0x3fff;226 pub const hi_user = 0x3fff;
227};227};
228228
229pub const CC = enum(u8) {
230 normal = 0x1,
231 program = 0x2,
232 nocall = 0x3,
233
234 pass_by_reference = 0x4,
235 pass_by_value = 0x5,
236
237 lo_user = 0x40,
238 hi_user = 0xff,
239
240 GNU_renesas_sh = 0x40,
241 GNU_borland_fastcall_i386 = 0x41,
242};
243
229const PcRange = struct {244const PcRange = struct {
230 start: u64,245 start: u64,
231 end: u64,246 end: u64,
src/codegen/llvm.zig+526-25
...@@ -161,7 +161,12 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {...@@ -161,7 +161,12 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 {
161161
162pub const Object = struct {162pub const Object = struct {
163 llvm_module: *const llvm.Module,163 llvm_module: *const llvm.Module,
164 dibuilder: ?*llvm.DIBuilder,164 di_builder: ?*llvm.DIBuilder,
165 /// One of these mappings:
166 /// - *Module.File => *DIFile
167 /// - *Module.Decl => *DISubprogram
168 di_map: std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DIScope),
169 di_compile_unit: ?*llvm.DICompileUnit,
165 context: *const llvm.Context,170 context: *const llvm.Context,
166 target_machine: *const llvm.TargetMachine,171 target_machine: *const llvm.TargetMachine,
167 target_data: *const llvm.TargetData,172 target_data: *const llvm.TargetData,
...@@ -224,16 +229,18 @@ pub const Object = struct {...@@ -224,16 +229,18 @@ pub const Object = struct {
224 }229 }
225230
226 llvm_module.setTarget(llvm_target_triple.ptr);231 llvm_module.setTarget(llvm_target_triple.ptr);
227 var opt_dbuilder: ?*llvm.DIBuilder = null;232 var opt_di_builder: ?*llvm.DIBuilder = null;
228 errdefer if (opt_dbuilder) |dibuilder| dibuilder.dispose();233 errdefer if (opt_di_builder) |di_builder| di_builder.dispose();
234
235 var di_compile_unit: ?*llvm.DICompileUnit = null;
229236
230 if (!options.strip) {237 if (!options.strip) {
231 switch (options.object_format) {238 switch (options.object_format) {
232 .coff => llvm_module.addModuleCodeViewFlag(),239 .coff => llvm_module.addModuleCodeViewFlag(),
233 else => llvm_module.addModuleDebugInfoFlag(),240 else => llvm_module.addModuleDebugInfoFlag(),
234 }241 }
235 const dibuilder = llvm_module.createDIBuilder(true);242 const di_builder = llvm_module.createDIBuilder(true);
236 opt_dbuilder = dibuilder;243 opt_di_builder = di_builder;
237244
238 // Don't use the version string here; LLVM misparses it when it245 // Don't use the version string here; LLVM misparses it when it
239 // includes the git revision.246 // includes the git revision.
...@@ -262,9 +269,9 @@ pub const Object = struct {...@@ -262,9 +269,9 @@ pub const Object = struct {
262 const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);269 const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir);
263 defer gpa.free(compile_unit_dir_z);270 defer gpa.free(compile_unit_dir_z);
264271
265 _ = dibuilder.createCompileUnit(272 di_compile_unit = di_builder.createCompileUnit(
266 DW.LANG.C99,273 DW.LANG.C99,
267 dibuilder.createFile(options.root_name, compile_unit_dir_z),274 di_builder.createFile(options.root_name, compile_unit_dir_z),
268 producer,275 producer,
269 options.optimize_mode != .Debug,276 options.optimize_mode != .Debug,
270 "", // flags277 "", // flags
...@@ -320,7 +327,9 @@ pub const Object = struct {...@@ -320,7 +327,9 @@ pub const Object = struct {
320327
321 return Object{328 return Object{
322 .llvm_module = llvm_module,329 .llvm_module = llvm_module,
323 .dibuilder = opt_dbuilder,330 .di_map = .{},
331 .di_builder = opt_di_builder,
332 .di_compile_unit = di_compile_unit,
324 .context = context,333 .context = context,
325 .target_machine = target_machine,334 .target_machine = target_machine,
326 .target_data = target_data,335 .target_data = target_data,
...@@ -332,7 +341,10 @@ pub const Object = struct {...@@ -332,7 +341,10 @@ pub const Object = struct {
332 }341 }
333342
334 pub fn deinit(self: *Object, gpa: Allocator) void {343 pub fn deinit(self: *Object, gpa: Allocator) void {
335 if (self.dibuilder) |dib| dib.dispose();344 if (self.di_builder) |dib| {
345 dib.dispose();
346 self.di_map.deinit(gpa);
347 }
336 self.target_data.dispose();348 self.target_data.dispose();
337 self.target_machine.dispose();349 self.target_machine.dispose();
338 self.llvm_module.dispose();350 self.llvm_module.dispose();
...@@ -413,6 +425,9 @@ pub const Object = struct {...@@ -413,6 +425,9 @@ pub const Object = struct {
413425
414 pub fn flushModule(self: *Object, comp: *Compilation) !void {426 pub fn flushModule(self: *Object, comp: *Compilation) !void {
415 try self.genErrorNameTable(comp);427 try self.genErrorNameTable(comp);
428
429 if (self.di_builder) |dib| dib.finalize();
430
416 if (comp.verbose_llvm_ir) {431 if (comp.verbose_llvm_ir) {
417 self.llvm_module.dump();432 self.llvm_module.dump();
418 }433 }
...@@ -526,8 +541,9 @@ pub const Object = struct {...@@ -526,8 +541,9 @@ pub const Object = struct {
526 const target = dg.module.getTarget();541 const target = dg.module.getTarget();
527 const sret = firstParamSRet(fn_info, target);542 const sret = firstParamSRet(fn_info, target);
528 const ret_ptr = if (sret) llvm_func.getParam(0) else null;543 const ret_ptr = if (sret) llvm_func.getParam(0) else null;
544 const gpa = dg.gpa;
529545
530 var args = std.ArrayList(*const llvm.Value).init(dg.gpa);546 var args = std.ArrayList(*const llvm.Value).init(gpa);
531 defer args.deinit();547 defer args.deinit();
532548
533 const param_offset: c_uint = @boolToInt(ret_ptr != null);549 const param_offset: c_uint = @boolToInt(ret_ptr != null);
...@@ -538,8 +554,53 @@ pub const Object = struct {...@@ -538,8 +554,53 @@ pub const Object = struct {
538 try args.append(llvm_func.getParam(llvm_arg_i));554 try args.append(llvm_func.getParam(llvm_arg_i));
539 }555 }
540556
557 var di_file: ?*llvm.DIFile = null;
558 var di_scope: ?*llvm.DIScope = null;
559
560 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 };
574
575 const line_number = decl.src_line + 1;
576 const is_internal_linkage = decl.val.tag() != .extern_fn and
577 !dg.module.decl_exports.contains(decl);
578 const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
579 llvm.DIFlags.NoReturn
580 else
581 0;
582 const subprogram = dib.createFunction(
583 di_file.?.toScope(),
584 decl.name,
585 llvm_func.getValueName(),
586 di_file.?,
587 line_number,
588 try dg.lowerDebugType(decl.ty),
589 is_internal_linkage,
590 true, // is definition
591 line_number + func.lbrace_line, // scope line
592 llvm.DIFlags.StaticMember | noret_bit,
593 dg.module.comp.bin_file.options.optimize_mode != .Debug,
594 null, // decl_subprogram
595 );
596
597 llvm_func.fnSetSubprogram(subprogram);
598
599 di_scope = subprogram.toScope();
600 }
601
541 var fg: FuncGen = .{602 var fg: FuncGen = .{
542 .gpa = dg.gpa,603 .gpa = gpa,
543 .air = air,604 .air = air,
544 .liveness = liveness,605 .liveness = liveness,
545 .context = dg.context,606 .context = dg.context,
...@@ -552,6 +613,8 @@ pub const Object = struct {...@@ -552,6 +613,8 @@ pub const Object = struct {
552 .llvm_func = llvm_func,613 .llvm_func = llvm_func,
553 .blocks = .{},614 .blocks = .{},
554 .single_threaded = module.comp.bin_file.options.single_threaded,615 .single_threaded = module.comp.bin_file.options.single_threaded,
616 .di_scope = di_scope,
617 .di_file = di_file,
555 };618 };
556 defer fg.deinit();619 defer fg.deinit();
557620
...@@ -1827,6 +1890,418 @@ pub const DeclGen = struct {...@@ -1827,6 +1890,418 @@ pub const DeclGen = struct {
1827 }1890 }
1828 }1891 }
18291892
1893 fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType {
1894 const gpa = dg.gpa;
1895 const target = dg.module.getTarget();
1896 const dib = dg.object.di_builder.?;
1897 switch (ty.zigTypeTag()) {
1898 .Void, .NoReturn => return dib.createBasicType("void", 0, DW.ATE.signed),
1899 .Int => {
1900 const info = ty.intInfo(target);
1901 assert(info.bits != 0);
1902 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1903 const dwarf_encoding: c_uint = switch (info.signedness) {
1904 .signed => DW.ATE.signed,
1905 .unsigned => DW.ATE.unsigned,
1906 };
1907 return dib.createBasicType(name, info.bits, dwarf_encoding);
1908 },
1909 .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);
1916 },
1917 .Float => {
1918 const bits = ty.floatBits(target);
1919 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1920 return dib.createBasicType(name, bits, DW.ATE.float);
1921 },
1922 .Bool => return dib.createBasicType("bool", 1, DW.ATE.boolean),
1923 .Pointer => {
1924 if (ty.isSlice()) {
1925 @panic("TODO debug info type for slices");
1926 //var buf: Type.SlicePtrFieldTypeBuffer = undefined;
1927 //const ptr_type = ty.slicePtrFieldType(&buf);
1928
1929 //const fields: [2]*const llvm.Type = .{
1930 // try dg.llvmType(ptr_type),
1931 // try dg.llvmType(Type.usize),
1932 //};
1933 //return dg.context.structType(&fields, fields.len, .False);
1934 }
1935
1936 const ptr_info = ty.ptrInfo().data;
1937 const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type);
1938 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1939 return dib.createPointerType(
1940 elem_di_ty,
1941 target.cpu.arch.ptrBitWidth(),
1942 ty.ptrAlignment(target) * 8,
1943 name,
1944 );
1945 },
1946 .Opaque => {
1947 @panic("TODO debug info type for opaque");
1948 },
1949 .Array => {
1950 const elem_di_ty = try lowerDebugType(dg, ty.childType());
1951 return dib.createArrayType(
1952 ty.abiSize(target) * 8,
1953 ty.abiAlignment(target) * 8,
1954 elem_di_ty,
1955 @intCast(c_int, ty.arrayLen()),
1956 );
1957 },
1958 .Vector => {
1959 @panic("TODO debug info type for vector");
1960 },
1961 .Optional => {
1962 @panic("TODO debug info type for optional");
1963 //var buf: Type.Payload.ElemType = undefined;
1964 //const child_type = ty.optionalChild(&buf);
1965 //if (!child_type.hasRuntimeBits()) {
1966 // return dg.context.intType(1);
1967 //}
1968 //const payload_llvm_ty = try dg.llvmType(child_type);
1969 //if (ty.isPtrLikeOptional()) {
1970 // return payload_llvm_ty;
1971 //} else if (!child_type.hasRuntimeBits()) {
1972 // return dg.context.intType(1);
1973 //}
1974
1975 //const fields: [2]*const llvm.Type = .{
1976 // payload_llvm_ty, dg.context.intType(1),
1977 //};
1978 //return dg.context.structType(&fields, fields.len, .False);
1979 },
1980 .ErrorUnion => {
1981 const err_set_ty = ty.errorUnionSet();
1982 const err_set_di_ty = try dg.lowerDebugType(err_set_ty);
1983 const payload_ty = ty.errorUnionPayload();
1984 if (!payload_ty.hasRuntimeBits()) {
1985 return err_set_di_ty;
1986 }
1987 const payload_di_ty = try dg.lowerDebugType(payload_ty);
1988
1989 const name = try ty.nameAlloc(gpa); // TODO this is a leak
1990 const di_file: ?*llvm.DIFile = null;
1991 const line = 0;
1992 const compile_unit_scope = dg.object.di_compile_unit.?.toScope();
1993 const fwd_decl = dib.createReplaceableCompositeType(
1994 DW.TAG.structure_type,
1995 name.ptr,
1996 compile_unit_scope,
1997 di_file,
1998 line,
1999 );
2000
2001 const err_set_size = err_set_ty.abiSize(target);
2002 const err_set_align = err_set_ty.abiAlignment(target);
2003 const payload_size = payload_ty.abiSize(target);
2004 const payload_align = payload_ty.abiAlignment(target);
2005
2006 var offset: u64 = 0;
2007 offset += err_set_size;
2008 offset = std.mem.alignForwardGeneric(u64, offset, payload_align);
2009 const payload_offset = offset;
2010
2011 const fields: [2]*llvm.DIType = .{
2012 dib.createMemberType(
2013 fwd_decl.toScope(),
2014 "tag",
2015 di_file,
2016 line,
2017 err_set_size * 8, // size in bits
2018 err_set_align * 8, // align in bits
2019 0, // offset in bits
2020 0, // flags
2021 err_set_di_ty,
2022 ),
2023 dib.createMemberType(
2024 fwd_decl.toScope(),
2025 "value",
2026 di_file,
2027 line,
2028 payload_size * 8, // size in bits
2029 payload_align * 8, // align in bits
2030 payload_offset * 8, // offset in bits
2031 0, // flags
2032 payload_di_ty,
2033 ),
2034 };
2035
2036 const replacement_di_type = dib.createStructType(
2037 compile_unit_scope,
2038 name.ptr,
2039 di_file,
2040 line,
2041 ty.abiSize(target) * 8, // size in bits
2042 ty.abiAlignment(target) * 8, // align in bits
2043 0, // flags
2044 null, // derived from
2045 &fields,
2046 fields.len,
2047 0, // run time lang
2048 null, // vtable holder
2049 "", // unique id
2050 );
2051 dib.replaceTemporary(fwd_decl, replacement_di_type);
2052
2053 return replacement_di_type;
2054 },
2055 .ErrorSet => {
2056 // TODO make this a proper enum with all the error codes in it.
2057 // will need to consider how to take incremental compilation into account.
2058 return dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
2059 },
2060 .Struct => {
2061 @panic("TODO debug info type for struct");
2062 //const gop = try dg.object.type_map.getOrPut(gpa, ty);
2063 //if (gop.found_existing) return gop.value_ptr.*;
2064
2065 //// The Type memory is ephemeral; since we want to store a longer-lived
2066 //// reference, we need to copy it here.
2067 //gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
2068
2069 //if (ty.isTupleOrAnonStruct()) {
2070 // const tuple = ty.tupleFields();
2071 // const llvm_struct_ty = dg.context.structCreateNamed("");
2072 // gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
2073
2074 // var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
2075 // defer llvm_field_types.deinit(gpa);
2076
2077 // try llvm_field_types.ensureUnusedCapacity(gpa, tuple.types.len);
2078
2079 // comptime assert(struct_layout_version == 2);
2080 // var offset: u64 = 0;
2081 // var big_align: u32 = 0;
2082
2083 // for (tuple.types) |field_ty, i| {
2084 // const field_val = tuple.values[i];
2085 // if (field_val.tag() != .unreachable_value) continue;
2086
2087 // const field_align = field_ty.abiAlignment(target);
2088 // big_align = @maximum(big_align, field_align);
2089 // const prev_offset = offset;
2090 // offset = std.mem.alignForwardGeneric(u64, offset, field_align);
2091
2092 // const padding_len = offset - prev_offset;
2093 // if (padding_len > 0) {
2094 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2095 // try llvm_field_types.append(gpa, llvm_array_ty);
2096 // }
2097 // const field_llvm_ty = try dg.llvmType(field_ty);
2098 // try llvm_field_types.append(gpa, field_llvm_ty);
2099
2100 // offset += field_ty.abiSize(target);
2101 // }
2102 // {
2103 // const prev_offset = offset;
2104 // offset = std.mem.alignForwardGeneric(u64, offset, big_align);
2105 // const padding_len = offset - prev_offset;
2106 // if (padding_len > 0) {
2107 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2108 // try llvm_field_types.append(gpa, llvm_array_ty);
2109 // }
2110 // }
2111
2112 // llvm_struct_ty.structSetBody(
2113 // llvm_field_types.items.ptr,
2114 // @intCast(c_uint, llvm_field_types.items.len),
2115 // .False,
2116 // );
2117
2118 // return llvm_struct_ty;
2119 //}
2120
2121 //const struct_obj = ty.castTag(.@"struct").?.data;
2122
2123 //if (struct_obj.layout == .Packed) {
2124 // var buf: Type.Payload.Bits = undefined;
2125 // const int_ty = struct_obj.packedIntegerType(target, &buf);
2126 // const int_llvm_ty = try dg.llvmType(int_ty);
2127 // gop.value_ptr.* = int_llvm_ty;
2128 // return int_llvm_ty;
2129 //}
2130
2131 //const name = try struct_obj.getFullyQualifiedName(gpa);
2132 //defer gpa.free(name);
2133
2134 //const llvm_struct_ty = dg.context.structCreateNamed(name);
2135 //gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls
2136
2137 //assert(struct_obj.haveFieldTypes());
2138
2139 //var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{};
2140 //defer llvm_field_types.deinit(gpa);
2141
2142 //try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count());
2143
2144 //comptime assert(struct_layout_version == 2);
2145 //var offset: u64 = 0;
2146 //var big_align: u32 = 0;
2147
2148 //for (struct_obj.fields.values()) |field| {
2149 // if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
2150
2151 // const field_align = field.normalAlignment(target);
2152 // big_align = @maximum(big_align, field_align);
2153 // const prev_offset = offset;
2154 // offset = std.mem.alignForwardGeneric(u64, offset, field_align);
2155
2156 // const padding_len = offset - prev_offset;
2157 // if (padding_len > 0) {
2158 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2159 // try llvm_field_types.append(gpa, llvm_array_ty);
2160 // }
2161 // const field_llvm_ty = try dg.llvmType(field.ty);
2162 // try llvm_field_types.append(gpa, field_llvm_ty);
2163
2164 // offset += field.ty.abiSize(target);
2165 //}
2166 //{
2167 // const prev_offset = offset;
2168 // offset = std.mem.alignForwardGeneric(u64, offset, big_align);
2169 // const padding_len = offset - prev_offset;
2170 // if (padding_len > 0) {
2171 // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len));
2172 // try llvm_field_types.append(gpa, llvm_array_ty);
2173 // }
2174 //}
2175
2176 //llvm_struct_ty.structSetBody(
2177 // llvm_field_types.items.ptr,
2178 // @intCast(c_uint, llvm_field_types.items.len),
2179 // .False,
2180 //);
2181
2182 //return llvm_struct_ty;
2183 },
2184 .Union => {
2185 @panic("TODO debug info type for union");
2186 //const gop = try dg.object.type_map.getOrPut(gpa, ty);
2187 //if (gop.found_existing) return gop.value_ptr.*;
2188
2189 //// The Type memory is ephemeral; since we want to store a longer-lived
2190 //// reference, we need to copy it here.
2191 //gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator());
2192
2193 //const layout = ty.unionGetLayout(target);
2194 //const union_obj = ty.cast(Type.Payload.Union).?.data;
2195
2196 //if (layout.payload_size == 0) {
2197 // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
2198 // gop.value_ptr.* = enum_tag_llvm_ty;
2199 // return enum_tag_llvm_ty;
2200 //}
2201
2202 //const name = try union_obj.getFullyQualifiedName(gpa);
2203 //defer gpa.free(name);
2204
2205 //const llvm_union_ty = dg.context.structCreateNamed(name);
2206 //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls
2207
2208 //const aligned_field = union_obj.fields.values()[layout.most_aligned_field];
2209 //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty);
2210
2211 //const llvm_payload_ty = ty: {
2212 // if (layout.most_aligned_field_size == layout.payload_size) {
2213 // break :ty llvm_aligned_field_ty;
2214 // }
2215 // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size);
2216 // const fields: [2]*const llvm.Type = .{
2217 // llvm_aligned_field_ty,
2218 // dg.context.intType(8).arrayType(padding_len),
2219 // };
2220 // break :ty dg.context.structType(&fields, fields.len, .True);
2221 //};
2222
2223 //if (layout.tag_size == 0) {
2224 // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty};
2225 // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False);
2226 // return llvm_union_ty;
2227 //}
2228 //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty);
2229
2230 //// Put the tag before or after the payload depending on which one's
2231 //// alignment is greater.
2232 //var llvm_fields: [3]*const llvm.Type = undefined;
2233 //var llvm_fields_len: c_uint = 2;
2234
2235 //if (layout.tag_align >= layout.payload_align) {
2236 // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined };
2237 //} else {
2238 // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined };
2239 //}
2240
2241 //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size.
2242 //if (layout.padding != 0) {
2243 // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding);
2244 // llvm_fields_len = 3;
2245 //}
2246
2247 //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False);
2248 //return llvm_union_ty;
2249 },
2250 .Fn => {
2251 const fn_info = ty.fnInfo();
2252 const sret = firstParamSRet(fn_info, target);
2253
2254 var param_di_types = std.ArrayList(*llvm.DIType).init(dg.gpa);
2255 defer param_di_types.deinit();
2256
2257 // Return type goes first.
2258 const di_ret_ty = if (sret) Type.void else fn_info.return_type;
2259 try param_di_types.append(try dg.lowerDebugType(di_ret_ty));
2260
2261 if (sret) {
2262 var ptr_ty_payload: Type.Payload.ElemType = .{
2263 .base = .{ .tag = .single_mut_pointer },
2264 .data = fn_info.return_type,
2265 };
2266 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2267 try param_di_types.append(try dg.lowerDebugType(ptr_ty));
2268 }
2269
2270 for (fn_info.param_types) |param_ty| {
2271 if (!param_ty.hasRuntimeBits()) continue;
2272
2273 if (isByRef(param_ty)) {
2274 var ptr_ty_payload: Type.Payload.ElemType = .{
2275 .base = .{ .tag = .single_mut_pointer },
2276 .data = param_ty,
2277 };
2278 const ptr_ty = Type.initPayload(&ptr_ty_payload.base);
2279 try param_di_types.append(try dg.lowerDebugType(ptr_ty));
2280 } else {
2281 try param_di_types.append(try dg.lowerDebugType(param_ty));
2282 }
2283 }
2284
2285 return dib.createSubroutineType(
2286 param_di_types.items.ptr,
2287 @intCast(c_int, param_di_types.items.len),
2288 0,
2289 );
2290 },
2291 .ComptimeInt => unreachable,
2292 .ComptimeFloat => unreachable,
2293 .Type => unreachable,
2294 .Undefined => unreachable,
2295 .Null => unreachable,
2296 .EnumLiteral => unreachable,
2297
2298 .BoundFn => @panic("TODO remove BoundFn from the language"),
2299
2300 .Frame => @panic("TODO implement lowerDebugType for Frame types"),
2301 .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"),
2302 }
2303 }
2304
1830 const ParentPtr = struct {2305 const ParentPtr = struct {
1831 ty: Type,2306 ty: Type,
1832 llvm_ptr: *const llvm.Value,2307 llvm_ptr: *const llvm.Value,
...@@ -2141,6 +2616,8 @@ pub const FuncGen = struct {...@@ -2141,6 +2616,8 @@ pub const FuncGen = struct {
2141 liveness: Liveness,2616 liveness: Liveness,
2142 context: *const llvm.Context,2617 context: *const llvm.Context,
2143 builder: *const llvm.Builder,2618 builder: *const llvm.Builder,
2619 di_scope: ?*llvm.DIScope,
2620 di_file: ?*llvm.DIFile,
21442621
2145 /// This stores the LLVM values used in a function, such that they can be referred to2622 /// This stores the LLVM values used in a function, such that they can be referred to
2146 /// in other instructions. This table is cleared before every function is generated.2623 /// in other instructions. This table is cleared before every function is generated.
...@@ -2156,7 +2633,7 @@ pub const FuncGen = struct {...@@ -2156,7 +2633,7 @@ pub const FuncGen = struct {
2156 /// it omits 0-bit types. If the function uses sret as the first parameter,2633 /// it omits 0-bit types. If the function uses sret as the first parameter,
2157 /// this slice does not include it.2634 /// this slice does not include it.
2158 args: []const *const llvm.Value,2635 args: []const *const llvm.Value,
2159 arg_index: usize,2636 arg_index: c_uint,
21602637
2161 llvm_func: *const llvm.Value,2638 llvm_func: *const llvm.Value,
21622639
...@@ -2386,10 +2863,7 @@ pub const FuncGen = struct {...@@ -2386,10 +2863,7 @@ pub const FuncGen = struct {
2386 .constant => unreachable,2863 .constant => unreachable,
2387 .const_ty => unreachable,2864 .const_ty => unreachable,
2388 .unreach => self.airUnreach(inst),2865 .unreach => self.airUnreach(inst),
2389 .dbg_stmt => blk: {2866 .dbg_stmt => self.airDbgStmt(inst),
2390 // TODO: implement debug info
2391 break :blk null;
2392 },
2393 // zig fmt: on2867 // zig fmt: on
2394 };2868 };
2395 if (opt_value) |val| {2869 if (opt_value) |val| {
...@@ -3099,6 +3573,17 @@ pub const FuncGen = struct {...@@ -3099,6 +3573,17 @@ pub const FuncGen = struct {
3099 return null;3573 return null;
3100 }3574 }
31013575
3576 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value {
3577 const di_scope = self.di_scope orelse return null;
3578 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
3579 self.builder.setCurrentDebugLocation(
3580 @intCast(c_int, dbg_stmt.line + 1),
3581 @intCast(c_int, dbg_stmt.column + 1),
3582 di_scope,
3583 );
3584 return null;
3585 }
3586
3102 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3587 fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3103 // Eventually, the Zig compiler needs to be reworked to have inline assembly go3588 // Eventually, the Zig compiler needs to be reworked to have inline assembly go
3104 // through the same parsing code regardless of backend, and have LLVM-flavored3589 // through the same parsing code regardless of backend, and have LLVM-flavored
...@@ -4299,15 +4784,31 @@ pub const FuncGen = struct {...@@ -4299,15 +4784,31 @@ pub const FuncGen = struct {
4299 self.arg_index += 1;4784 self.arg_index += 1;
43004785
4301 const inst_ty = self.air.typeOfIndex(inst);4786 const inst_ty = self.air.typeOfIndex(inst);
4302 if (isByRef(inst_ty)) {4787 const result = r: {
4303 // TODO declare debug variable4788 if (isByRef(inst_ty)) {
4304 return arg_val;4789 break :r arg_val;
4305 } else {4790 } else {
4306 const ptr_val = self.buildAlloca(try self.dg.llvmType(inst_ty));4791 const ptr_val = self.buildAlloca(try self.dg.llvmType(inst_ty));
4307 _ = self.builder.buildStore(arg_val, ptr_val);4792 _ = self.builder.buildStore(arg_val, ptr_val);
4308 // TODO declare debug variable4793 break :r arg_val;
4309 return arg_val;4794 }
4795 };
4796
4797 if (self.dg.object.di_builder) |dib| {
4798 const func = self.dg.decl.getFunction().?;
4799 _ = dib.createParameterVariable(
4800 self.di_scope.?,
4801 func.getParamName(self.arg_index - 1).ptr, // TODO test 0 bit args
4802 self.di_file.?,
4803 func.owner_decl.src_line + func.lbrace_line + 1,
4804 try self.dg.lowerDebugType(inst_ty),
4805 true, // always preserve
4806 0, // flags
4807 self.arg_index, // includes +1 because 0 is return type
4808 );
4310 }4809 }
4810
4811 return result;
4311 }4812 }
43124813
4313 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {4814 fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
...@@ -4830,7 +5331,7 @@ pub const FuncGen = struct {...@@ -4830,7 +5331,7 @@ pub const FuncGen = struct {
4830 const prev_debug_location = self.builder.getCurrentDebugLocation2();5331 const prev_debug_location = self.builder.getCurrentDebugLocation2();
4831 defer {5332 defer {
4832 self.builder.positionBuilderAtEnd(prev_block);5333 self.builder.positionBuilderAtEnd(prev_block);
4833 if (!self.dg.module.comp.bin_file.options.strip) {5334 if (self.di_scope != null) {
4834 self.builder.setCurrentDebugLocation2(prev_debug_location);5335 self.builder.setCurrentDebugLocation2(prev_debug_location);
4835 }5336 }
4836 }5337 }
src/codegen/llvm/bindings.zig+48-7
...@@ -193,6 +193,9 @@ pub const Value = opaque {...@@ -193,6 +193,9 @@ pub const Value = opaque {
193 pub const setValueName2 = LLVMSetValueName2;193 pub const setValueName2 = LLVMSetValueName2;
194 extern fn LLVMSetValueName2(Val: *const Value, Name: [*]const u8, NameLen: usize) void;194 extern fn LLVMSetValueName2(Val: *const Value, Name: [*]const u8, NameLen: usize) void;
195195
196 pub const getValueName = LLVMGetValueName;
197 extern fn LLVMGetValueName(Val: *const Value) [*:0]const u8;
198
196 pub const takeName = ZigLLVMTakeName;199 pub const takeName = ZigLLVMTakeName;
197 extern fn ZigLLVMTakeName(new_owner: *const Value, victim: *const Value) void;200 extern fn ZigLLVMTakeName(new_owner: *const Value, victim: *const Value) void;
198201
...@@ -836,7 +839,7 @@ pub const Builder = opaque {...@@ -836,7 +839,7 @@ pub const Builder = opaque {
836 pub const buildExactSDiv = LLVMBuildExactSDiv;839 pub const buildExactSDiv = LLVMBuildExactSDiv;
837 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;840 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
838841
839 pub const zigSetCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;842 pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
840 extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void;843 extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_int, column: c_int, scope: *DIScope) void;
841844
842 pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;845 pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
...@@ -1505,16 +1508,16 @@ pub const DIBuilder = opaque {...@@ -1505,16 +1508,16 @@ pub const DIBuilder = opaque {
1505 dib: *DIBuilder,1508 dib: *DIBuilder,
1506 scope: *DIScope,1509 scope: *DIScope,
1507 name: [*:0]const u8,1510 name: [*:0]const u8,
1508 file: *DIFile,1511 file: ?*DIFile,
1509 line_number: c_uint,1512 line_number: c_uint,
1510 size_in_bits: u64,1513 size_in_bits: u64,
1511 align_in_bits: u64,1514 align_in_bits: u64,
1512 flags: c_uint,1515 flags: c_uint,
1513 derived_from: *DIType,1516 derived_from: ?*DIType,
1514 types_array: [*]const *DIType,1517 types_array: [*]const *DIType,
1515 types_array_len: c_int,1518 types_array_len: c_int,
1516 run_time_lang: c_uint,1519 run_time_lang: c_uint,
1517 vtable_holder: *DIType,1520 vtable_holder: ?*DIType,
1518 unique_id: [*:0]const u8,1521 unique_id: [*:0]const u8,
1519 ) *DIType;1522 ) *DIType;
15201523
...@@ -1539,7 +1542,7 @@ pub const DIBuilder = opaque {...@@ -1539,7 +1542,7 @@ pub const DIBuilder = opaque {
1539 dib: *DIBuilder,1542 dib: *DIBuilder,
1540 scope: *DIScope,1543 scope: *DIScope,
1541 name: [*:0]const u8,1544 name: [*:0]const u8,
1542 file: *DIFile,1545 file: ?*DIFile,
1543 line: c_uint,1546 line: c_uint,
1544 size_in_bits: u64,1547 size_in_bits: u64,
1545 align_in_bits: u64,1548 align_in_bits: u64,
...@@ -1554,7 +1557,7 @@ pub const DIBuilder = opaque {...@@ -1554,7 +1557,7 @@ pub const DIBuilder = opaque {
1554 tag: c_uint,1557 tag: c_uint,
1555 name: [*:0]const u8,1558 name: [*:0]const u8,
1556 scope: *DIScope,1559 scope: *DIScope,
1557 file: *DIFile,1560 file: ?*DIFile,
1558 line: c_uint,1561 line: c_uint,
1559 ) *DIType;1562 ) *DIType;
15601563
...@@ -1668,7 +1671,7 @@ pub const DIBuilder = opaque {...@@ -1668,7 +1671,7 @@ pub const DIBuilder = opaque {
1668 scope_line: c_uint,1671 scope_line: c_uint,
1669 flags: c_uint,1672 flags: c_uint,
1670 is_optimized: bool,1673 is_optimized: bool,
1671 decl_subprogram: *DISubprogram,1674 decl_subprogram: ?*DISubprogram,
1672 ) *DISubprogram;1675 ) *DISubprogram;
16731676
1674 pub const createVectorType = ZigLLVMDIBuilderCreateVectorType;1677 pub const createVectorType = ZigLLVMDIBuilderCreateVectorType;
...@@ -1698,3 +1701,41 @@ pub const DIBuilder = opaque {...@@ -1698,3 +1701,41 @@ pub const DIBuilder = opaque {
1698 insert_before_instr: *const Value,1701 insert_before_instr: *const Value,
1699 ) *const Value;1702 ) *const Value;
1700};1703};
1704
1705pub const DIFlags = opaque {
1706 pub const Zero = 0;
1707 pub const Private = 1;
1708 pub const Protected = 2;
1709 pub const Public = 3;
1710
1711 pub const FwdDecl = 1 << 2;
1712 pub const AppleBlock = 1 << 3;
1713 pub const BlockByrefStruct = 1 << 4;
1714 pub const Virtual = 1 << 5;
1715 pub const Artificial = 1 << 6;
1716 pub const Explicit = 1 << 7;
1717 pub const Prototyped = 1 << 8;
1718 pub const ObjcClassComplete = 1 << 9;
1719 pub const ObjectPointer = 1 << 10;
1720 pub const Vector = 1 << 11;
1721 pub const StaticMember = 1 << 12;
1722 pub const LValueReference = 1 << 13;
1723 pub const RValueReference = 1 << 14;
1724 pub const Reserved = 1 << 15;
1725
1726 pub const SingleInheritance = 1 << 16;
1727 pub const MultipleInheritance = 2 << 16;
1728 pub const VirtualInheritance = 3 << 16;
1729
1730 pub const IntroducedVirtual = 1 << 18;
1731 pub const BitField = 1 << 19;
1732 pub const NoReturn = 1 << 20;
1733 pub const TypePassByValue = 1 << 22;
1734 pub const TypePassByReference = 1 << 23;
1735 pub const EnumClass = 1 << 24;
1736 pub const Thunk = 1 << 25;
1737 pub const NonTrivial = 1 << 26;
1738 pub const BigEndian = 1 << 27;
1739 pub const LittleEndian = 1 << 28;
1740 pub const AllCallsDescribed = 1 << 29;
1741};