| ... | ... | @@ -5,12 +5,14 @@ const Allocator = std.mem.Allocator; |
| 5 | 5 | const log = std.log.scoped(.codegen); |
| 6 | 6 | const math = std.math; |
| 7 | 7 | const native_endian = builtin.cpu.arch.endian(); |
| 8 | const DW = std.dwarf; |
| 8 | 9 | |
| 9 | 10 | const llvm = @import("llvm/bindings.zig"); |
| 10 | 11 | const link = @import("../link.zig"); |
| 11 | 12 | const Compilation = @import("../Compilation.zig"); |
| 12 | 13 | const build_options = @import("build_options"); |
| 13 | 14 | const Module = @import("../Module.zig"); |
| 15 | const Package = @import("../Package.zig"); |
| 14 | 16 | const TypedValue = @import("../TypedValue.zig"); |
| 15 | 17 | const Air = @import("../Air.zig"); |
| 16 | 18 | const Liveness = @import("../Liveness.zig"); |
| ... | ... | @@ -159,6 +161,12 @@ pub fn targetTriple(allocator: Allocator, target: std.Target) ![:0]u8 { |
| 159 | 161 | |
| 160 | 162 | pub const Object = struct { |
| 161 | 163 | llvm_module: *const llvm.Module, |
| 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, |
| 162 | 170 | context: *const llvm.Context, |
| 163 | 171 | target_machine: *const llvm.TargetMachine, |
| 164 | 172 | target_data: *const llvm.TargetData, |
| ... | ... | @@ -180,8 +188,10 @@ pub const Object = struct { |
| 180 | 188 | /// The backing memory for `type_map`. Periodically garbage collected after flush(). |
| 181 | 189 | /// The code for doing the periodical GC is not yet implemented. |
| 182 | 190 | type_map_arena: std.heap.ArenaAllocator, |
| 183 | | /// The LLVM global table which holds the names corresponding to Zig errors. Note that the values |
| 184 | | /// are not added until flushModule, when all errors in the compilation are known. |
| 191 | di_type_map: DITypeMap, |
| 192 | /// The LLVM global table which holds the names corresponding to Zig errors. |
| 193 | /// Note that the values are not added until flushModule, when all errors in |
| 194 | /// the compilation are known. |
| 185 | 195 | error_name_table: ?*const llvm.Value, |
| 186 | 196 | |
| 187 | 197 | pub const TypeMap = std.HashMapUnmanaged( |
| ... | ... | @@ -191,6 +201,13 @@ pub const Object = struct { |
| 191 | 201 | std.hash_map.default_max_load_percentage, |
| 192 | 202 | ); |
| 193 | 203 | |
| 204 | pub const DITypeMap = std.HashMapUnmanaged( |
| 205 | Type, |
| 206 | *llvm.DIType, |
| 207 | Type.HashContext64, |
| 208 | std.hash_map.default_max_load_percentage, |
| 209 | ); |
| 210 | |
| 194 | 211 | pub fn create(gpa: Allocator, options: link.Options) !*Object { |
| 195 | 212 | const obj = try gpa.create(Object); |
| 196 | 213 | errdefer gpa.destroy(obj); |
| ... | ... | @@ -204,9 +221,7 @@ pub const Object = struct { |
| 204 | 221 | |
| 205 | 222 | initializeLLVMTarget(options.target.cpu.arch); |
| 206 | 223 | |
| 207 | | const root_nameZ = try gpa.dupeZ(u8, options.root_name); |
| 208 | | defer gpa.free(root_nameZ); |
| 209 | | const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context); |
| 224 | const llvm_module = llvm.Module.createWithName(options.root_name.ptr, context); |
| 210 | 225 | errdefer llvm_module.dispose(); |
| 211 | 226 | |
| 212 | 227 | const llvm_target_triple = try targetTriple(gpa, options.target); |
| ... | ... | @@ -221,6 +236,60 @@ pub const Object = struct { |
| 221 | 236 | return error.InvalidLlvmTriple; |
| 222 | 237 | } |
| 223 | 238 | |
| 239 | llvm_module.setTarget(llvm_target_triple.ptr); |
| 240 | var opt_di_builder: ?*llvm.DIBuilder = null; |
| 241 | errdefer if (opt_di_builder) |di_builder| di_builder.dispose(); |
| 242 | |
| 243 | var di_compile_unit: ?*llvm.DICompileUnit = null; |
| 244 | |
| 245 | if (!options.strip) { |
| 246 | switch (options.object_format) { |
| 247 | .coff => llvm_module.addModuleCodeViewFlag(), |
| 248 | else => llvm_module.addModuleDebugInfoFlag(), |
| 249 | } |
| 250 | const di_builder = llvm_module.createDIBuilder(true); |
| 251 | opt_di_builder = di_builder; |
| 252 | |
| 253 | // Don't use the version string here; LLVM misparses it when it |
| 254 | // includes the git revision. |
| 255 | const producer = try std.fmt.allocPrintZ(gpa, "zig {d}.{d}.{d}", .{ |
| 256 | build_options.semver.major, |
| 257 | build_options.semver.minor, |
| 258 | build_options.semver.patch, |
| 259 | }); |
| 260 | defer gpa.free(producer); |
| 261 | |
| 262 | // For macOS stack traces, we want to avoid having to parse the compilation unit debug |
| 263 | // info. As long as each debug info file has a path independent of the compilation unit |
| 264 | // directory (DW_AT_comp_dir), then we never have to look at the compilation unit debug |
| 265 | // info. If we provide an absolute path to LLVM here for the compilation unit debug |
| 266 | // info, LLVM will emit DWARF info that depends on DW_AT_comp_dir. To avoid this, we |
| 267 | // pass "." for the compilation unit directory. This forces each debug file to have a |
| 268 | // directory rather than be relative to DW_AT_comp_dir. According to DWARF 5, debug |
| 269 | // files will no longer reference DW_AT_comp_dir, for the purpose of being able to |
| 270 | // support the common practice of stripping all but the line number sections from an |
| 271 | // executable. |
| 272 | const compile_unit_dir = d: { |
| 273 | if (options.target.isDarwin()) break :d "."; |
| 274 | const mod = options.module orelse break :d "."; |
| 275 | break :d mod.root_pkg.root_src_directory.path orelse "."; |
| 276 | }; |
| 277 | const compile_unit_dir_z = try gpa.dupeZ(u8, compile_unit_dir); |
| 278 | defer gpa.free(compile_unit_dir_z); |
| 279 | |
| 280 | di_compile_unit = di_builder.createCompileUnit( |
| 281 | DW.LANG.C99, |
| 282 | di_builder.createFile(options.root_name, compile_unit_dir_z), |
| 283 | producer, |
| 284 | options.optimize_mode != .Debug, |
| 285 | "", // flags |
| 286 | 0, // runtime version |
| 287 | "", // split name |
| 288 | 0, // dwo id |
| 289 | true, // emit debug info |
| 290 | ); |
| 291 | } |
| 292 | |
| 224 | 293 | const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) |
| 225 | 294 | .None |
| 226 | 295 | else |
| ... | ... | @@ -266,17 +335,26 @@ pub const Object = struct { |
| 266 | 335 | |
| 267 | 336 | return Object{ |
| 268 | 337 | .llvm_module = llvm_module, |
| 338 | .di_map = .{}, |
| 339 | .di_builder = opt_di_builder, |
| 340 | .di_compile_unit = di_compile_unit, |
| 269 | 341 | .context = context, |
| 270 | 342 | .target_machine = target_machine, |
| 271 | 343 | .target_data = target_data, |
| 272 | 344 | .decl_map = .{}, |
| 273 | 345 | .type_map = .{}, |
| 274 | 346 | .type_map_arena = std.heap.ArenaAllocator.init(gpa), |
| 347 | .di_type_map = .{}, |
| 275 | 348 | .error_name_table = null, |
| 276 | 349 | }; |
| 277 | 350 | } |
| 278 | 351 | |
| 279 | 352 | pub fn deinit(self: *Object, gpa: Allocator) void { |
| 353 | if (self.di_builder) |dib| { |
| 354 | dib.dispose(); |
| 355 | self.di_map.deinit(gpa); |
| 356 | self.di_type_map.deinit(gpa); |
| 357 | } |
| 280 | 358 | self.target_data.dispose(); |
| 281 | 359 | self.target_machine.dispose(); |
| 282 | 360 | self.llvm_module.dispose(); |
| ... | ... | @@ -357,6 +435,9 @@ pub const Object = struct { |
| 357 | 435 | |
| 358 | 436 | pub fn flushModule(self: *Object, comp: *Compilation) !void { |
| 359 | 437 | try self.genErrorNameTable(comp); |
| 438 | |
| 439 | if (self.di_builder) |dib| dib.finalize(); |
| 440 | |
| 360 | 441 | if (comp.verbose_llvm_ir) { |
| 361 | 442 | self.llvm_module.dump(); |
| 362 | 443 | } |
| ... | ... | @@ -470,8 +551,9 @@ pub const Object = struct { |
| 470 | 551 | const target = dg.module.getTarget(); |
| 471 | 552 | const sret = firstParamSRet(fn_info, target); |
| 472 | 553 | const ret_ptr = if (sret) llvm_func.getParam(0) else null; |
| 554 | const gpa = dg.gpa; |
| 473 | 555 | |
| 474 | | var args = std.ArrayList(*const llvm.Value).init(dg.gpa); |
| 556 | var args = std.ArrayList(*const llvm.Value).init(gpa); |
| 475 | 557 | defer args.deinit(); |
| 476 | 558 | |
| 477 | 559 | const param_offset: c_uint = @boolToInt(ret_ptr != null); |
| ... | ... | @@ -482,8 +564,41 @@ pub const Object = struct { |
| 482 | 564 | try args.append(llvm_func.getParam(llvm_arg_i)); |
| 483 | 565 | } |
| 484 | 566 | |
| 567 | var di_file: ?*llvm.DIFile = null; |
| 568 | var di_scope: ?*llvm.DIScope = null; |
| 569 | |
| 570 | if (dg.object.di_builder) |dib| { |
| 571 | di_file = try dg.object.getDIFile(gpa, decl.src_namespace.file_scope); |
| 572 | |
| 573 | const line_number = decl.src_line + 1; |
| 574 | const is_internal_linkage = decl.val.tag() != .extern_fn and |
| 575 | !dg.module.decl_exports.contains(decl); |
| 576 | const noret_bit: c_uint = if (fn_info.return_type.isNoReturn()) |
| 577 | llvm.DIFlags.NoReturn |
| 578 | else |
| 579 | 0; |
| 580 | const subprogram = dib.createFunction( |
| 581 | di_file.?.toScope(), |
| 582 | decl.name, |
| 583 | llvm_func.getValueName(), |
| 584 | di_file.?, |
| 585 | line_number, |
| 586 | try dg.lowerDebugType(decl.ty), |
| 587 | is_internal_linkage, |
| 588 | true, // is definition |
| 589 | line_number + func.lbrace_line, // scope line |
| 590 | llvm.DIFlags.StaticMember | noret_bit, |
| 591 | dg.module.comp.bin_file.options.optimize_mode != .Debug, |
| 592 | null, // decl_subprogram |
| 593 | ); |
| 594 | |
| 595 | llvm_func.fnSetSubprogram(subprogram); |
| 596 | |
| 597 | di_scope = subprogram.toScope(); |
| 598 | } |
| 599 | |
| 485 | 600 | var fg: FuncGen = .{ |
| 486 | | .gpa = dg.gpa, |
| 601 | .gpa = gpa, |
| 487 | 602 | .air = air, |
| 488 | 603 | .liveness = liveness, |
| 489 | 604 | .context = dg.context, |
| ... | ... | @@ -496,6 +611,8 @@ pub const Object = struct { |
| 496 | 611 | .llvm_func = llvm_func, |
| 497 | 612 | .blocks = .{}, |
| 498 | 613 | .single_threaded = module.comp.bin_file.options.single_threaded, |
| 614 | .di_scope = di_scope, |
| 615 | .di_file = di_file, |
| 499 | 616 | }; |
| 500 | 617 | defer fg.deinit(); |
| 501 | 618 | |
| ... | ... | @@ -599,6 +716,22 @@ pub const Object = struct { |
| 599 | 716 | const llvm_value = self.decl_map.get(decl) orelse return; |
| 600 | 717 | llvm_value.deleteGlobal(); |
| 601 | 718 | } |
| 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 | } |
| 602 | 735 | }; |
| 603 | 736 | |
| 604 | 737 | pub const DeclGen = struct { |
| ... | ... | @@ -942,15 +1075,13 @@ pub const DeclGen = struct { |
| 942 | 1075 | }, |
| 943 | 1076 | .Optional => { |
| 944 | 1077 | var buf: Type.Payload.ElemType = undefined; |
| 945 | | const child_type = t.optionalChild(&buf); |
| 946 | | if (!child_type.hasRuntimeBits()) { |
| 1078 | const child_ty = t.optionalChild(&buf); |
| 1079 | if (!child_ty.hasRuntimeBits()) { |
| 947 | 1080 | return dg.context.intType(1); |
| 948 | 1081 | } |
| 949 | | const payload_llvm_ty = try dg.llvmType(child_type); |
| 1082 | const payload_llvm_ty = try dg.llvmType(child_ty); |
| 950 | 1083 | if (t.isPtrLikeOptional()) { |
| 951 | 1084 | return payload_llvm_ty; |
| 952 | | } else if (!child_type.hasRuntimeBits()) { |
| 953 | | return dg.context.intType(1); |
| 954 | 1085 | } |
| 955 | 1086 | |
| 956 | 1087 | const fields: [2]*const llvm.Type = .{ |
| ... | ... | @@ -1771,6 +1902,768 @@ pub const DeclGen = struct { |
| 1771 | 1902 | } |
| 1772 | 1903 | } |
| 1773 | 1904 | |
| 1905 | fn lowerDebugType(dg: *DeclGen, ty: Type) Allocator.Error!*llvm.DIType { |
| 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.*; |
| 1911 | errdefer assert(dg.object.di_type_map.remove(ty)); |
| 1912 | // The Type memory is ephemeral; since we want to store a longer-lived |
| 1913 | // reference, we need to copy it here. |
| 1914 | gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator()); |
| 1915 | const target = dg.module.getTarget(); |
| 1916 | const dib = dg.object.di_builder.?; |
| 1917 | switch (ty.zigTypeTag()) { |
| 1918 | .Void, .NoReturn => { |
| 1919 | gop.value_ptr.* = dib.createBasicType("void", 0, DW.ATE.signed); |
| 1920 | return gop.value_ptr.*; |
| 1921 | }, |
| 1922 | .Int => { |
| 1923 | const info = ty.intInfo(target); |
| 1924 | assert(info.bits != 0); |
| 1925 | const name = try ty.nameAlloc(gpa); |
| 1926 | defer gpa.free(name); |
| 1927 | const dwarf_encoding: c_uint = switch (info.signedness) { |
| 1928 | .signed => DW.ATE.signed, |
| 1929 | .unsigned => DW.ATE.unsigned, |
| 1930 | }; |
| 1931 | gop.value_ptr.* = dib.createBasicType(name, info.bits, dwarf_encoding); |
| 1932 | return gop.value_ptr.*; |
| 1933 | }, |
| 1934 | .Enum => { |
| 1935 | const owner_decl = ty.getOwnerDecl(); |
| 1936 | |
| 1937 | if (!ty.hasRuntimeBits()) { |
| 1938 | const enum_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); |
| 1939 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 1940 | // means we can't use `gop` anymore. |
| 1941 | try dg.object.di_type_map.put(gpa, ty, enum_di_ty); |
| 1942 | return enum_di_ty; |
| 1943 | } |
| 1944 | |
| 1945 | const field_names = ty.enumFields().keys(); |
| 1946 | |
| 1947 | const enumerators = try gpa.alloc(*llvm.DIEnumerator, field_names.len); |
| 1948 | defer gpa.free(enumerators); |
| 1949 | |
| 1950 | var buf_field_index: Value.Payload.U32 = .{ |
| 1951 | .base = .{ .tag = .enum_field_index }, |
| 1952 | .data = undefined, |
| 1953 | }; |
| 1954 | const field_index_val = Value.initPayload(&buf_field_index.base); |
| 1955 | |
| 1956 | for (field_names) |field_name, i| { |
| 1957 | const field_name_z = try gpa.dupeZ(u8, field_name); |
| 1958 | defer gpa.free(field_name_z); |
| 1959 | |
| 1960 | buf_field_index.data = @intCast(u32, i); |
| 1961 | var buf_u64: Value.Payload.U64 = undefined; |
| 1962 | const field_int_val = field_index_val.enumToInt(ty, &buf_u64); |
| 1963 | // See https://github.com/ziglang/zig/issues/645 |
| 1964 | const field_int = field_int_val.toSignedInt(); |
| 1965 | enumerators[i] = dib.createEnumerator(field_name_z, field_int); |
| 1966 | } |
| 1967 | |
| 1968 | const di_file = try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope); |
| 1969 | const di_scope = try dg.namespaceToDebugScope(owner_decl.src_namespace); |
| 1970 | |
| 1971 | const name = try ty.nameAlloc(gpa); |
| 1972 | defer gpa.free(name); |
| 1973 | var buffer: Type.Payload.Bits = undefined; |
| 1974 | const int_ty = ty.intTagType(&buffer); |
| 1975 | |
| 1976 | const enum_di_ty = dib.createEnumerationType( |
| 1977 | di_scope, |
| 1978 | name, |
| 1979 | di_file, |
| 1980 | owner_decl.src_node + 1, |
| 1981 | ty.abiSize(target) * 8, |
| 1982 | ty.abiAlignment(target) * 8, |
| 1983 | enumerators.ptr, |
| 1984 | @intCast(c_int, enumerators.len), |
| 1985 | try lowerDebugType(dg, int_ty), |
| 1986 | "", |
| 1987 | ); |
| 1988 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 1989 | try dg.object.di_type_map.put(gpa, ty, enum_di_ty); |
| 1990 | return enum_di_ty; |
| 1991 | }, |
| 1992 | .Float => { |
| 1993 | const bits = ty.floatBits(target); |
| 1994 | const name = try ty.nameAlloc(gpa); |
| 1995 | defer gpa.free(name); |
| 1996 | gop.value_ptr.* = dib.createBasicType(name, bits, DW.ATE.float); |
| 1997 | return gop.value_ptr.*; |
| 1998 | }, |
| 1999 | .Bool => { |
| 2000 | gop.value_ptr.* = dib.createBasicType("bool", 1, DW.ATE.boolean); |
| 2001 | return gop.value_ptr.*; |
| 2002 | }, |
| 2003 | .Pointer => { |
| 2004 | // Normalize everything that the debug info does not represent. |
| 2005 | const ptr_info = ty.ptrInfo().data; |
| 2006 | |
| 2007 | if (ptr_info.sentinel != null or |
| 2008 | ptr_info.@"addrspace" != .generic or |
| 2009 | ptr_info.bit_offset != 0 or |
| 2010 | ptr_info.host_size != 0 or |
| 2011 | ptr_info.@"allowzero" or |
| 2012 | !ptr_info.mutable or |
| 2013 | ptr_info.@"volatile" or |
| 2014 | ptr_info.size == .Many or ptr_info.size == .C) |
| 2015 | { |
| 2016 | var payload: Type.Payload.Pointer = .{ |
| 2017 | .data = .{ |
| 2018 | .pointee_type = ptr_info.pointee_type, |
| 2019 | .sentinel = null, |
| 2020 | .@"align" = ptr_info.@"align", |
| 2021 | .@"addrspace" = .generic, |
| 2022 | .bit_offset = 0, |
| 2023 | .host_size = 0, |
| 2024 | .@"allowzero" = false, |
| 2025 | .mutable = true, |
| 2026 | .@"volatile" = false, |
| 2027 | .size = switch (ptr_info.size) { |
| 2028 | .Many, .C, .One => .One, |
| 2029 | .Slice => .Slice, |
| 2030 | }, |
| 2031 | }, |
| 2032 | }; |
| 2033 | const bland_ptr_ty = Type.initPayload(&payload.base); |
| 2034 | const ptr_di_ty = try dg.lowerDebugType(bland_ptr_ty); |
| 2035 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2036 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); |
| 2037 | return ptr_di_ty; |
| 2038 | } |
| 2039 | |
| 2040 | if (ty.isSlice()) { |
| 2041 | var buf: Type.SlicePtrFieldTypeBuffer = undefined; |
| 2042 | const ptr_ty = ty.slicePtrFieldType(&buf); |
| 2043 | const len_ty = Type.usize; |
| 2044 | |
| 2045 | const name = try ty.nameAlloc(gpa); |
| 2046 | defer gpa.free(name); |
| 2047 | const di_file: ?*llvm.DIFile = null; |
| 2048 | const line = 0; |
| 2049 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); |
| 2050 | const fwd_decl = dib.createReplaceableCompositeType( |
| 2051 | DW.TAG.structure_type, |
| 2052 | name.ptr, |
| 2053 | compile_unit_scope, |
| 2054 | di_file, |
| 2055 | line, |
| 2056 | ); |
| 2057 | gop.value_ptr.* = fwd_decl; |
| 2058 | |
| 2059 | const ptr_size = ptr_ty.abiSize(target); |
| 2060 | const ptr_align = ptr_ty.abiAlignment(target); |
| 2061 | const len_size = len_ty.abiSize(target); |
| 2062 | const len_align = len_ty.abiAlignment(target); |
| 2063 | |
| 2064 | var offset: u64 = 0; |
| 2065 | offset += ptr_size; |
| 2066 | offset = std.mem.alignForwardGeneric(u64, offset, len_align); |
| 2067 | const len_offset = offset; |
| 2068 | |
| 2069 | const fields: [2]*llvm.DIType = .{ |
| 2070 | dib.createMemberType( |
| 2071 | fwd_decl.toScope(), |
| 2072 | "ptr", |
| 2073 | di_file, |
| 2074 | line, |
| 2075 | ptr_size * 8, // size in bits |
| 2076 | ptr_align * 8, // align in bits |
| 2077 | 0, // offset in bits |
| 2078 | 0, // flags |
| 2079 | try dg.lowerDebugType(ptr_ty), |
| 2080 | ), |
| 2081 | dib.createMemberType( |
| 2082 | fwd_decl.toScope(), |
| 2083 | "len", |
| 2084 | di_file, |
| 2085 | line, |
| 2086 | len_size * 8, // size in bits |
| 2087 | len_align * 8, // align in bits |
| 2088 | len_offset * 8, // offset in bits |
| 2089 | 0, // flags |
| 2090 | try dg.lowerDebugType(len_ty), |
| 2091 | ), |
| 2092 | }; |
| 2093 | |
| 2094 | const replacement_di_ty = dib.createStructType( |
| 2095 | compile_unit_scope, |
| 2096 | name.ptr, |
| 2097 | di_file, |
| 2098 | line, |
| 2099 | ty.abiSize(target) * 8, // size in bits |
| 2100 | ty.abiAlignment(target) * 8, // align in bits |
| 2101 | 0, // flags |
| 2102 | null, // derived from |
| 2103 | &fields, |
| 2104 | fields.len, |
| 2105 | 0, // run time lang |
| 2106 | null, // vtable holder |
| 2107 | "", // unique id |
| 2108 | ); |
| 2109 | dib.replaceTemporary(fwd_decl, replacement_di_ty); |
| 2110 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2111 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); |
| 2112 | return replacement_di_ty; |
| 2113 | } |
| 2114 | |
| 2115 | const elem_di_ty = try lowerDebugType(dg, ptr_info.pointee_type); |
| 2116 | const name = try ty.nameAlloc(gpa); |
| 2117 | defer gpa.free(name); |
| 2118 | const ptr_di_ty = dib.createPointerType( |
| 2119 | elem_di_ty, |
| 2120 | target.cpu.arch.ptrBitWidth(), |
| 2121 | ty.ptrAlignment(target) * 8, |
| 2122 | name, |
| 2123 | ); |
| 2124 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2125 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); |
| 2126 | return ptr_di_ty; |
| 2127 | }, |
| 2128 | .Opaque => { |
| 2129 | if (ty.tag() == .anyopaque) { |
| 2130 | gop.value_ptr.* = dib.createBasicType("anyopaque", 0, DW.ATE.signed); |
| 2131 | return gop.value_ptr.*; |
| 2132 | } |
| 2133 | const name = try ty.nameAlloc(gpa); |
| 2134 | defer gpa.free(name); |
| 2135 | const owner_decl = ty.getOwnerDecl(); |
| 2136 | const opaque_di_ty = dib.createForwardDeclType( |
| 2137 | DW.TAG.structure_type, |
| 2138 | name, |
| 2139 | try dg.namespaceToDebugScope(owner_decl.src_namespace), |
| 2140 | try dg.object.getDIFile(gpa, owner_decl.src_namespace.file_scope), |
| 2141 | owner_decl.src_node + 1, |
| 2142 | ); |
| 2143 | // The recursive call to `lowerDebugType` va `namespaceToDebugScope` |
| 2144 | // means we can't use `gop` anymore. |
| 2145 | try dg.object.di_type_map.put(gpa, ty, opaque_di_ty); |
| 2146 | return opaque_di_ty; |
| 2147 | }, |
| 2148 | .Array => { |
| 2149 | const array_di_ty = dib.createArrayType( |
| 2150 | ty.abiSize(target) * 8, |
| 2151 | ty.abiAlignment(target) * 8, |
| 2152 | try lowerDebugType(dg, ty.childType()), |
| 2153 | @intCast(c_int, ty.arrayLen()), |
| 2154 | ); |
| 2155 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2156 | try dg.object.di_type_map.put(gpa, ty, array_di_ty); |
| 2157 | return array_di_ty; |
| 2158 | }, |
| 2159 | .Vector => { |
| 2160 | const vector_di_ty = dib.createVectorType( |
| 2161 | ty.abiSize(target) * 8, |
| 2162 | ty.abiAlignment(target) * 8, |
| 2163 | try lowerDebugType(dg, ty.childType()), |
| 2164 | ty.vectorLen(), |
| 2165 | ); |
| 2166 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2167 | try dg.object.di_type_map.put(gpa, ty, vector_di_ty); |
| 2168 | return vector_di_ty; |
| 2169 | }, |
| 2170 | .Optional => { |
| 2171 | const name = try ty.nameAlloc(gpa); |
| 2172 | defer gpa.free(name); |
| 2173 | var buf: Type.Payload.ElemType = undefined; |
| 2174 | const child_ty = ty.optionalChild(&buf); |
| 2175 | if (!child_ty.hasRuntimeBits()) { |
| 2176 | gop.value_ptr.* = dib.createBasicType(name, 1, DW.ATE.boolean); |
| 2177 | return gop.value_ptr.*; |
| 2178 | } |
| 2179 | if (ty.isPtrLikeOptional()) { |
| 2180 | const ptr_di_ty = try dg.lowerDebugType(child_ty); |
| 2181 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2182 | try dg.object.di_type_map.put(gpa, ty, ptr_di_ty); |
| 2183 | return ptr_di_ty; |
| 2184 | } |
| 2185 | |
| 2186 | const di_file: ?*llvm.DIFile = null; |
| 2187 | const line = 0; |
| 2188 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); |
| 2189 | const fwd_decl = dib.createReplaceableCompositeType( |
| 2190 | DW.TAG.structure_type, |
| 2191 | name.ptr, |
| 2192 | compile_unit_scope, |
| 2193 | di_file, |
| 2194 | line, |
| 2195 | ); |
| 2196 | gop.value_ptr.* = fwd_decl; |
| 2197 | |
| 2198 | const non_null_ty = Type.bool; |
| 2199 | const payload_size = child_ty.abiSize(target); |
| 2200 | const payload_align = child_ty.abiAlignment(target); |
| 2201 | const non_null_size = non_null_ty.abiSize(target); |
| 2202 | const non_null_align = non_null_ty.abiAlignment(target); |
| 2203 | |
| 2204 | var offset: u64 = 0; |
| 2205 | offset += payload_size; |
| 2206 | offset = std.mem.alignForwardGeneric(u64, offset, non_null_align); |
| 2207 | const non_null_offset = offset; |
| 2208 | |
| 2209 | const fields: [2]*llvm.DIType = .{ |
| 2210 | dib.createMemberType( |
| 2211 | fwd_decl.toScope(), |
| 2212 | "data", |
| 2213 | di_file, |
| 2214 | line, |
| 2215 | payload_size * 8, // size in bits |
| 2216 | payload_align * 8, // align in bits |
| 2217 | 0, // offset in bits |
| 2218 | 0, // flags |
| 2219 | try dg.lowerDebugType(child_ty), |
| 2220 | ), |
| 2221 | dib.createMemberType( |
| 2222 | fwd_decl.toScope(), |
| 2223 | "some", |
| 2224 | di_file, |
| 2225 | line, |
| 2226 | non_null_size * 8, // size in bits |
| 2227 | non_null_align * 8, // align in bits |
| 2228 | non_null_offset * 8, // offset in bits |
| 2229 | 0, // flags |
| 2230 | try dg.lowerDebugType(non_null_ty), |
| 2231 | ), |
| 2232 | }; |
| 2233 | |
| 2234 | const replacement_di_ty = dib.createStructType( |
| 2235 | compile_unit_scope, |
| 2236 | name.ptr, |
| 2237 | di_file, |
| 2238 | line, |
| 2239 | ty.abiSize(target) * 8, // size in bits |
| 2240 | ty.abiAlignment(target) * 8, // align in bits |
| 2241 | 0, // flags |
| 2242 | null, // derived from |
| 2243 | &fields, |
| 2244 | fields.len, |
| 2245 | 0, // run time lang |
| 2246 | null, // vtable holder |
| 2247 | "", // unique id |
| 2248 | ); |
| 2249 | dib.replaceTemporary(fwd_decl, replacement_di_ty); |
| 2250 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2251 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); |
| 2252 | return replacement_di_ty; |
| 2253 | }, |
| 2254 | .ErrorUnion => { |
| 2255 | const err_set_ty = ty.errorUnionSet(); |
| 2256 | const payload_ty = ty.errorUnionPayload(); |
| 2257 | if (!payload_ty.hasRuntimeBits()) { |
| 2258 | const err_set_di_ty = try dg.lowerDebugType(err_set_ty); |
| 2259 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2260 | try dg.object.di_type_map.put(gpa, ty, err_set_di_ty); |
| 2261 | return err_set_di_ty; |
| 2262 | } |
| 2263 | const name = try ty.nameAlloc(gpa); |
| 2264 | defer gpa.free(name); |
| 2265 | const di_file: ?*llvm.DIFile = null; |
| 2266 | const line = 0; |
| 2267 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); |
| 2268 | const fwd_decl = dib.createReplaceableCompositeType( |
| 2269 | DW.TAG.structure_type, |
| 2270 | name.ptr, |
| 2271 | compile_unit_scope, |
| 2272 | di_file, |
| 2273 | line, |
| 2274 | ); |
| 2275 | gop.value_ptr.* = fwd_decl; |
| 2276 | |
| 2277 | const err_set_size = err_set_ty.abiSize(target); |
| 2278 | const err_set_align = err_set_ty.abiAlignment(target); |
| 2279 | const payload_size = payload_ty.abiSize(target); |
| 2280 | const payload_align = payload_ty.abiAlignment(target); |
| 2281 | |
| 2282 | var offset: u64 = 0; |
| 2283 | offset += err_set_size; |
| 2284 | offset = std.mem.alignForwardGeneric(u64, offset, payload_align); |
| 2285 | const payload_offset = offset; |
| 2286 | |
| 2287 | const fields: [2]*llvm.DIType = .{ |
| 2288 | dib.createMemberType( |
| 2289 | fwd_decl.toScope(), |
| 2290 | "tag", |
| 2291 | di_file, |
| 2292 | line, |
| 2293 | err_set_size * 8, // size in bits |
| 2294 | err_set_align * 8, // align in bits |
| 2295 | 0, // offset in bits |
| 2296 | 0, // flags |
| 2297 | try dg.lowerDebugType(err_set_ty), |
| 2298 | ), |
| 2299 | dib.createMemberType( |
| 2300 | fwd_decl.toScope(), |
| 2301 | "value", |
| 2302 | di_file, |
| 2303 | line, |
| 2304 | payload_size * 8, // size in bits |
| 2305 | payload_align * 8, // align in bits |
| 2306 | payload_offset * 8, // offset in bits |
| 2307 | 0, // flags |
| 2308 | try dg.lowerDebugType(payload_ty), |
| 2309 | ), |
| 2310 | }; |
| 2311 | |
| 2312 | const replacement_di_ty = dib.createStructType( |
| 2313 | compile_unit_scope, |
| 2314 | name.ptr, |
| 2315 | di_file, |
| 2316 | line, |
| 2317 | ty.abiSize(target) * 8, // size in bits |
| 2318 | ty.abiAlignment(target) * 8, // align in bits |
| 2319 | 0, // flags |
| 2320 | null, // derived from |
| 2321 | &fields, |
| 2322 | fields.len, |
| 2323 | 0, // run time lang |
| 2324 | null, // vtable holder |
| 2325 | "", // unique id |
| 2326 | ); |
| 2327 | dib.replaceTemporary(fwd_decl, replacement_di_ty); |
| 2328 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2329 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); |
| 2330 | return replacement_di_ty; |
| 2331 | }, |
| 2332 | .ErrorSet => { |
| 2333 | // TODO make this a proper enum with all the error codes in it. |
| 2334 | // will need to consider how to take incremental compilation into account. |
| 2335 | gop.value_ptr.* = dib.createBasicType("anyerror", 16, DW.ATE.unsigned); |
| 2336 | return gop.value_ptr.*; |
| 2337 | }, |
| 2338 | .Struct => { |
| 2339 | const compile_unit_scope = dg.object.di_compile_unit.?.toScope(); |
| 2340 | const name = try ty.nameAlloc(gpa); |
| 2341 | defer gpa.free(name); |
| 2342 | const fwd_decl = dib.createReplaceableCompositeType( |
| 2343 | DW.TAG.structure_type, |
| 2344 | name.ptr, |
| 2345 | compile_unit_scope, |
| 2346 | null, // file |
| 2347 | 0, // line |
| 2348 | ); |
| 2349 | gop.value_ptr.* = fwd_decl; |
| 2350 | |
| 2351 | if (ty.isTupleOrAnonStruct()) { |
| 2352 | const tuple = ty.tupleFields(); |
| 2353 | |
| 2354 | var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{}; |
| 2355 | defer di_fields.deinit(gpa); |
| 2356 | |
| 2357 | try di_fields.ensureUnusedCapacity(gpa, tuple.types.len); |
| 2358 | |
| 2359 | comptime assert(struct_layout_version == 2); |
| 2360 | var offset: u64 = 0; |
| 2361 | |
| 2362 | for (tuple.types) |field_ty, i| { |
| 2363 | const field_val = tuple.values[i]; |
| 2364 | if (field_val.tag() != .unreachable_value) continue; |
| 2365 | |
| 2366 | const field_size = field_ty.abiSize(target); |
| 2367 | const field_align = field_ty.abiAlignment(target); |
| 2368 | const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2369 | offset = field_offset + field_size; |
| 2370 | |
| 2371 | const field_name = if (ty.castTag(.anon_struct)) |payload| |
| 2372 | try gpa.dupeZ(u8, payload.data.names[i]) |
| 2373 | else |
| 2374 | try std.fmt.allocPrintZ(gpa, "{d}", .{i}); |
| 2375 | defer gpa.free(field_name); |
| 2376 | |
| 2377 | try di_fields.append(gpa, dib.createMemberType( |
| 2378 | fwd_decl.toScope(), |
| 2379 | field_name, |
| 2380 | null, // file |
| 2381 | 0, // line |
| 2382 | field_size * 8, // size in bits |
| 2383 | field_align * 8, // align in bits |
| 2384 | field_offset * 8, // offset in bits |
| 2385 | 0, // flags |
| 2386 | try dg.lowerDebugType(field_ty), |
| 2387 | )); |
| 2388 | } |
| 2389 | |
| 2390 | const replacement_di_ty = dib.createStructType( |
| 2391 | compile_unit_scope, |
| 2392 | name.ptr, |
| 2393 | null, // file |
| 2394 | 0, // line |
| 2395 | ty.abiSize(target) * 8, // size in bits |
| 2396 | ty.abiAlignment(target) * 8, // align in bits |
| 2397 | 0, // flags |
| 2398 | null, // derived from |
| 2399 | di_fields.items.ptr, |
| 2400 | @intCast(c_int, di_fields.items.len), |
| 2401 | 0, // run time lang |
| 2402 | null, // vtable holder |
| 2403 | "", // unique id |
| 2404 | ); |
| 2405 | dib.replaceTemporary(fwd_decl, replacement_di_ty); |
| 2406 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2407 | try dg.object.di_type_map.put(gpa, ty, replacement_di_ty); |
| 2408 | return replacement_di_ty; |
| 2409 | } |
| 2410 | |
| 2411 | const TODO_implement_this = true; // TODO |
| 2412 | if (TODO_implement_this or !ty.hasRuntimeBits()) { |
| 2413 | const owner_decl = ty.getOwnerDecl(); |
| 2414 | const struct_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); |
| 2415 | dib.replaceTemporary(fwd_decl, struct_di_ty); |
| 2416 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2417 | // means we can't use `gop` anymore. |
| 2418 | try dg.object.di_type_map.put(gpa, ty, struct_di_ty); |
| 2419 | return struct_di_ty; |
| 2420 | } |
| 2421 | @panic("TODO debug info type for struct"); |
| 2422 | |
| 2423 | //const struct_obj = ty.castTag(.@"struct").?.data; |
| 2424 | |
| 2425 | //if (struct_obj.layout == .Packed) { |
| 2426 | // var buf: Type.Payload.Bits = undefined; |
| 2427 | // const int_ty = struct_obj.packedIntegerType(target, &buf); |
| 2428 | // const int_llvm_ty = try dg.llvmType(int_ty); |
| 2429 | // gop.value_ptr.* = int_llvm_ty; |
| 2430 | // return int_llvm_ty; |
| 2431 | //} |
| 2432 | |
| 2433 | //const name = try struct_obj.getFullyQualifiedName(gpa); |
| 2434 | //defer gpa.free(name); |
| 2435 | |
| 2436 | //const llvm_struct_ty = dg.context.structCreateNamed(name); |
| 2437 | //gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls |
| 2438 | |
| 2439 | //assert(struct_obj.haveFieldTypes()); |
| 2440 | |
| 2441 | //var llvm_field_types: std.ArrayListUnmanaged(*const llvm.Type) = .{}; |
| 2442 | //defer llvm_field_types.deinit(gpa); |
| 2443 | |
| 2444 | //try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count()); |
| 2445 | |
| 2446 | //comptime assert(struct_layout_version == 2); |
| 2447 | //var offset: u64 = 0; |
| 2448 | //var big_align: u32 = 0; |
| 2449 | |
| 2450 | //for (struct_obj.fields.values()) |field| { |
| 2451 | // if (field.is_comptime or !field.ty.hasRuntimeBits()) continue; |
| 2452 | |
| 2453 | // const field_align = field.normalAlignment(target); |
| 2454 | // big_align = @maximum(big_align, field_align); |
| 2455 | // const prev_offset = offset; |
| 2456 | // offset = std.mem.alignForwardGeneric(u64, offset, field_align); |
| 2457 | |
| 2458 | // const padding_len = offset - prev_offset; |
| 2459 | // if (padding_len > 0) { |
| 2460 | // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2461 | // try llvm_field_types.append(gpa, llvm_array_ty); |
| 2462 | // } |
| 2463 | // const field_llvm_ty = try dg.llvmType(field.ty); |
| 2464 | // try llvm_field_types.append(gpa, field_llvm_ty); |
| 2465 | |
| 2466 | // offset += field.ty.abiSize(target); |
| 2467 | //} |
| 2468 | //{ |
| 2469 | // const prev_offset = offset; |
| 2470 | // offset = std.mem.alignForwardGeneric(u64, offset, big_align); |
| 2471 | // const padding_len = offset - prev_offset; |
| 2472 | // if (padding_len > 0) { |
| 2473 | // const llvm_array_ty = dg.context.intType(8).arrayType(@intCast(c_uint, padding_len)); |
| 2474 | // try llvm_field_types.append(gpa, llvm_array_ty); |
| 2475 | // } |
| 2476 | //} |
| 2477 | |
| 2478 | //llvm_struct_ty.structSetBody( |
| 2479 | // llvm_field_types.items.ptr, |
| 2480 | // @intCast(c_uint, llvm_field_types.items.len), |
| 2481 | // .False, |
| 2482 | //); |
| 2483 | |
| 2484 | //return llvm_struct_ty; |
| 2485 | }, |
| 2486 | .Union => { |
| 2487 | const owner_decl = ty.getOwnerDecl(); |
| 2488 | |
| 2489 | const name = try ty.nameAlloc(gpa); |
| 2490 | defer gpa.free(name); |
| 2491 | const fwd_decl = dib.createReplaceableCompositeType( |
| 2492 | DW.TAG.structure_type, |
| 2493 | name.ptr, |
| 2494 | dg.object.di_compile_unit.?.toScope(), |
| 2495 | null, // file |
| 2496 | 0, // line |
| 2497 | ); |
| 2498 | gop.value_ptr.* = fwd_decl; |
| 2499 | |
| 2500 | const TODO_implement_this = true; // TODO |
| 2501 | if (TODO_implement_this or !ty.hasRuntimeBits()) { |
| 2502 | const union_di_ty = try dg.makeEmptyNamespaceDIType(owner_decl); |
| 2503 | dib.replaceTemporary(fwd_decl, union_di_ty); |
| 2504 | // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType` |
| 2505 | // means we can't use `gop` anymore. |
| 2506 | try dg.object.di_type_map.put(gpa, ty, union_di_ty); |
| 2507 | return union_di_ty; |
| 2508 | } |
| 2509 | |
| 2510 | @panic("TODO debug info type for union"); |
| 2511 | //const gop = try dg.object.type_map.getOrPut(gpa, ty); |
| 2512 | //if (gop.found_existing) return gop.value_ptr.*; |
| 2513 | |
| 2514 | //// The Type memory is ephemeral; since we want to store a longer-lived |
| 2515 | //// reference, we need to copy it here. |
| 2516 | //gop.key_ptr.* = try ty.copy(dg.object.type_map_arena.allocator()); |
| 2517 | |
| 2518 | //const layout = ty.unionGetLayout(target); |
| 2519 | //const union_obj = ty.cast(Type.Payload.Union).?.data; |
| 2520 | |
| 2521 | //if (layout.payload_size == 0) { |
| 2522 | // const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 2523 | // gop.value_ptr.* = enum_tag_llvm_ty; |
| 2524 | // return enum_tag_llvm_ty; |
| 2525 | //} |
| 2526 | |
| 2527 | //const name = try union_obj.getFullyQualifiedName(gpa); |
| 2528 | //defer gpa.free(name); |
| 2529 | |
| 2530 | //const llvm_union_ty = dg.context.structCreateNamed(name); |
| 2531 | //gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls |
| 2532 | |
| 2533 | //const aligned_field = union_obj.fields.values()[layout.most_aligned_field]; |
| 2534 | //const llvm_aligned_field_ty = try dg.llvmType(aligned_field.ty); |
| 2535 | |
| 2536 | //const llvm_payload_ty = ty: { |
| 2537 | // if (layout.most_aligned_field_size == layout.payload_size) { |
| 2538 | // break :ty llvm_aligned_field_ty; |
| 2539 | // } |
| 2540 | // const padding_len = @intCast(c_uint, layout.payload_size - layout.most_aligned_field_size); |
| 2541 | // const fields: [2]*const llvm.Type = .{ |
| 2542 | // llvm_aligned_field_ty, |
| 2543 | // dg.context.intType(8).arrayType(padding_len), |
| 2544 | // }; |
| 2545 | // break :ty dg.context.structType(&fields, fields.len, .True); |
| 2546 | //}; |
| 2547 | |
| 2548 | //if (layout.tag_size == 0) { |
| 2549 | // var llvm_fields: [1]*const llvm.Type = .{llvm_payload_ty}; |
| 2550 | // llvm_union_ty.structSetBody(&llvm_fields, llvm_fields.len, .False); |
| 2551 | // return llvm_union_ty; |
| 2552 | //} |
| 2553 | //const enum_tag_llvm_ty = try dg.llvmType(union_obj.tag_ty); |
| 2554 | |
| 2555 | //// Put the tag before or after the payload depending on which one's |
| 2556 | //// alignment is greater. |
| 2557 | //var llvm_fields: [3]*const llvm.Type = undefined; |
| 2558 | //var llvm_fields_len: c_uint = 2; |
| 2559 | |
| 2560 | //if (layout.tag_align >= layout.payload_align) { |
| 2561 | // llvm_fields = .{ enum_tag_llvm_ty, llvm_payload_ty, undefined }; |
| 2562 | //} else { |
| 2563 | // llvm_fields = .{ llvm_payload_ty, enum_tag_llvm_ty, undefined }; |
| 2564 | //} |
| 2565 | |
| 2566 | //// Insert padding to make the LLVM struct ABI size match the Zig union ABI size. |
| 2567 | //if (layout.padding != 0) { |
| 2568 | // llvm_fields[2] = dg.context.intType(8).arrayType(layout.padding); |
| 2569 | // llvm_fields_len = 3; |
| 2570 | //} |
| 2571 | |
| 2572 | //llvm_union_ty.structSetBody(&llvm_fields, llvm_fields_len, .False); |
| 2573 | //return llvm_union_ty; |
| 2574 | }, |
| 2575 | .Fn => { |
| 2576 | const fn_info = ty.fnInfo(); |
| 2577 | const sret = firstParamSRet(fn_info, target); |
| 2578 | |
| 2579 | var param_di_types = std.ArrayList(*llvm.DIType).init(dg.gpa); |
| 2580 | defer param_di_types.deinit(); |
| 2581 | |
| 2582 | // Return type goes first. |
| 2583 | const di_ret_ty = if (sret or !fn_info.return_type.hasRuntimeBits()) |
| 2584 | Type.void |
| 2585 | else |
| 2586 | fn_info.return_type; |
| 2587 | try param_di_types.append(try dg.lowerDebugType(di_ret_ty)); |
| 2588 | |
| 2589 | if (sret) { |
| 2590 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| 2591 | .base = .{ .tag = .single_mut_pointer }, |
| 2592 | .data = fn_info.return_type, |
| 2593 | }; |
| 2594 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| 2595 | try param_di_types.append(try dg.lowerDebugType(ptr_ty)); |
| 2596 | } |
| 2597 | |
| 2598 | for (fn_info.param_types) |param_ty| { |
| 2599 | if (!param_ty.hasRuntimeBits()) continue; |
| 2600 | |
| 2601 | if (isByRef(param_ty)) { |
| 2602 | var ptr_ty_payload: Type.Payload.ElemType = .{ |
| 2603 | .base = .{ .tag = .single_mut_pointer }, |
| 2604 | .data = param_ty, |
| 2605 | }; |
| 2606 | const ptr_ty = Type.initPayload(&ptr_ty_payload.base); |
| 2607 | try param_di_types.append(try dg.lowerDebugType(ptr_ty)); |
| 2608 | } else { |
| 2609 | try param_di_types.append(try dg.lowerDebugType(param_ty)); |
| 2610 | } |
| 2611 | } |
| 2612 | |
| 2613 | const fn_di_ty = dib.createSubroutineType( |
| 2614 | param_di_types.items.ptr, |
| 2615 | @intCast(c_int, param_di_types.items.len), |
| 2616 | 0, |
| 2617 | ); |
| 2618 | // The recursive call to `lowerDebugType` means we can't use `gop` anymore. |
| 2619 | try dg.object.di_type_map.put(gpa, ty, fn_di_ty); |
| 2620 | return fn_di_ty; |
| 2621 | }, |
| 2622 | .ComptimeInt => unreachable, |
| 2623 | .ComptimeFloat => unreachable, |
| 2624 | .Type => unreachable, |
| 2625 | .Undefined => unreachable, |
| 2626 | .Null => unreachable, |
| 2627 | .EnumLiteral => unreachable, |
| 2628 | |
| 2629 | .BoundFn => @panic("TODO remove BoundFn from the language"), |
| 2630 | |
| 2631 | .Frame => @panic("TODO implement lowerDebugType for Frame types"), |
| 2632 | .AnyFrame => @panic("TODO implement lowerDebugType for AnyFrame types"), |
| 2633 | } |
| 2634 | } |
| 2635 | |
| 2636 | fn namespaceToDebugScope(dg: *DeclGen, namespace: *const Module.Namespace) !*llvm.DIScope { |
| 2637 | if (namespace.parent == null) { |
| 2638 | const di_file = try dg.object.getDIFile(dg.gpa, namespace.file_scope); |
| 2639 | return di_file.toScope(); |
| 2640 | } |
| 2641 | const di_type = try dg.lowerDebugType(namespace.ty); |
| 2642 | return di_type.toScope(); |
| 2643 | } |
| 2644 | |
| 2645 | /// This is to be used instead of void for debug info types, to avoid tripping |
| 2646 | /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"' |
| 2647 | /// when targeting CodeView (Windows). |
| 2648 | fn makeEmptyNamespaceDIType(dg: *DeclGen, decl: *const Module.Decl) !*llvm.DIType { |
| 2649 | const fields: [0]*llvm.DIType = .{}; |
| 2650 | return dg.object.di_builder.?.createStructType( |
| 2651 | try dg.namespaceToDebugScope(decl.src_namespace), |
| 2652 | decl.name, // TODO use fully qualified name |
| 2653 | try dg.object.getDIFile(dg.gpa, decl.src_namespace.file_scope), |
| 2654 | decl.src_line + 1, |
| 2655 | 0, // size in bits |
| 2656 | 0, // align in bits |
| 2657 | 0, // flags |
| 2658 | null, // derived from |
| 2659 | undefined, // TODO should be able to pass &fields, |
| 2660 | fields.len, |
| 2661 | 0, // run time lang |
| 2662 | null, // vtable holder |
| 2663 | "", // unique id |
| 2664 | ); |
| 2665 | } |
| 2666 | |
| 1774 | 2667 | const ParentPtr = struct { |
| 1775 | 2668 | ty: Type, |
| 1776 | 2669 | llvm_ptr: *const llvm.Value, |
| ... | ... | @@ -2085,6 +2978,8 @@ pub const FuncGen = struct { |
| 2085 | 2978 | liveness: Liveness, |
| 2086 | 2979 | context: *const llvm.Context, |
| 2087 | 2980 | builder: *const llvm.Builder, |
| 2981 | di_scope: ?*llvm.DIScope, |
| 2982 | di_file: ?*llvm.DIFile, |
| 2088 | 2983 | |
| 2089 | 2984 | /// This stores the LLVM values used in a function, such that they can be referred to |
| 2090 | 2985 | /// in other instructions. This table is cleared before every function is generated. |
| ... | ... | @@ -2100,7 +2995,7 @@ pub const FuncGen = struct { |
| 2100 | 2995 | /// it omits 0-bit types. If the function uses sret as the first parameter, |
| 2101 | 2996 | /// this slice does not include it. |
| 2102 | 2997 | args: []const *const llvm.Value, |
| 2103 | | arg_index: usize, |
| 2998 | arg_index: c_uint, |
| 2104 | 2999 | |
| 2105 | 3000 | llvm_func: *const llvm.Value, |
| 2106 | 3001 | |
| ... | ... | @@ -2330,10 +3225,7 @@ pub const FuncGen = struct { |
| 2330 | 3225 | .constant => unreachable, |
| 2331 | 3226 | .const_ty => unreachable, |
| 2332 | 3227 | .unreach => self.airUnreach(inst), |
| 2333 | | .dbg_stmt => blk: { |
| 2334 | | // TODO: implement debug info |
| 2335 | | break :blk null; |
| 2336 | | }, |
| 3228 | .dbg_stmt => self.airDbgStmt(inst), |
| 2337 | 3229 | // zig fmt: on |
| 2338 | 3230 | }; |
| 2339 | 3231 | if (opt_value) |val| { |
| ... | ... | @@ -3043,6 +3935,17 @@ pub const FuncGen = struct { |
| 3043 | 3935 | return null; |
| 3044 | 3936 | } |
| 3045 | 3937 | |
| 3938 | fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value { |
| 3939 | const di_scope = self.di_scope orelse return null; |
| 3940 | const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt; |
| 3941 | self.builder.setCurrentDebugLocation( |
| 3942 | @intCast(c_int, self.dg.decl.src_line + dbg_stmt.line + 1), |
| 3943 | @intCast(c_int, dbg_stmt.column + 1), |
| 3944 | di_scope, |
| 3945 | ); |
| 3946 | return null; |
| 3947 | } |
| 3948 | |
| 3046 | 3949 | fn airAssembly(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 3047 | 3950 | // Eventually, the Zig compiler needs to be reworked to have inline assembly go |
| 3048 | 3951 | // through the same parsing code regardless of backend, and have LLVM-flavored |
| ... | ... | @@ -4243,15 +5146,42 @@ pub const FuncGen = struct { |
| 4243 | 5146 | self.arg_index += 1; |
| 4244 | 5147 | |
| 4245 | 5148 | const inst_ty = self.air.typeOfIndex(inst); |
| 4246 | | if (isByRef(inst_ty)) { |
| 4247 | | // TODO declare debug variable |
| 4248 | | return arg_val; |
| 4249 | | } else { |
| 4250 | | const ptr_val = self.buildAlloca(try self.dg.llvmType(inst_ty)); |
| 4251 | | _ = self.builder.buildStore(arg_val, ptr_val); |
| 4252 | | // TODO declare debug variable |
| 4253 | | return arg_val; |
| 5149 | if (self.dg.object.di_builder) |dib| { |
| 5150 | const src_index = self.getSrcArgIndex(self.arg_index - 1); |
| 5151 | const func = self.dg.decl.getFunction().?; |
| 5152 | const lbrace_line = func.owner_decl.src_line + func.lbrace_line + 1; |
| 5153 | const lbrace_col = func.lbrace_column + 1; |
| 5154 | const di_local_var = dib.createParameterVariable( |
| 5155 | self.di_scope.?, |
| 5156 | func.getParamName(src_index).ptr, // TODO test 0 bit args |
| 5157 | self.di_file.?, |
| 5158 | lbrace_line, |
| 5159 | try self.dg.lowerDebugType(inst_ty), |
| 5160 | true, // always preserve |
| 5161 | 0, // flags |
| 5162 | self.arg_index, // includes +1 because 0 is return type |
| 5163 | ); |
| 5164 | |
| 5165 | const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?); |
| 5166 | const insert_block = self.builder.getInsertBlock(); |
| 5167 | if (isByRef(inst_ty)) { |
| 5168 | _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block); |
| 5169 | } else { |
| 5170 | _ = dib.insertDbgValueIntrinsicAtEnd(arg_val, di_local_var, debug_loc, insert_block); |
| 5171 | } |
| 4254 | 5172 | } |
| 5173 | |
| 5174 | return arg_val; |
| 5175 | } |
| 5176 | |
| 5177 | fn getSrcArgIndex(self: *FuncGen, runtime_index: u32) u32 { |
| 5178 | const fn_info = self.dg.decl.ty.fnInfo(); |
| 5179 | var i: u32 = 0; |
| 5180 | for (fn_info.param_types) |param_ty, src_index| { |
| 5181 | if (!param_ty.hasRuntimeBits()) continue; |
| 5182 | if (i == runtime_index) return @intCast(u32, src_index); |
| 5183 | i += 1; |
| 5184 | } else unreachable; |
| 4255 | 5185 | } |
| 4256 | 5186 | |
| 4257 | 5187 | fn airAlloc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| ... | ... | @@ -4774,7 +5704,7 @@ pub const FuncGen = struct { |
| 4774 | 5704 | const prev_debug_location = self.builder.getCurrentDebugLocation2(); |
| 4775 | 5705 | defer { |
| 4776 | 5706 | self.builder.positionBuilderAtEnd(prev_block); |
| 4777 | | if (!self.dg.module.comp.bin_file.options.strip) { |
| 5707 | if (self.di_scope != null) { |
| 4778 | 5708 | self.builder.setCurrentDebugLocation2(prev_debug_location); |
| 4779 | 5709 | } |
| 4780 | 5710 | } |