Commit c11c7a28a3
Changed files (1)
src
codegen
src/codegen/llvm.zig
@@ -770,37 +770,19 @@ pub const Object = struct {
builder: Builder,
module: *Module,
- di_builder: ?if (build_options.have_llvm) *llvm.DIBuilder else noreturn,
- /// One of these mappings:
- /// - *Module.File => *DIFile
- /// - *Module.Decl (Fn) => *DISubprogram
- /// - *Module.Decl (Non-Fn) => *DIGlobalVariable
- di_map: if (build_options.have_llvm) std.AutoHashMapUnmanaged(*const anyopaque, *llvm.DINode) else struct {
- const K = *const anyopaque;
- const V = noreturn;
- const Self = @This();
+ debug_compile_unit: Builder.Metadata,
- metadata: ?noreturn = null,
- size: Size = 0,
- available: Size = 0,
+ debug_enums_fwd_ref: Builder.Metadata,
+ debug_globals_fwd_ref: Builder.Metadata,
- pub const Size = u0;
+ debug_enums: std.ArrayListUnmanaged(Builder.Metadata),
+ debug_globals: std.ArrayListUnmanaged(Builder.Metadata),
- pub fn deinit(self: *Self, allocator: Allocator) void {
- _ = allocator;
- self.* = undefined;
- }
+ debug_type_map: std.AutoHashMapUnmanaged(Type, Builder.Metadata),
+
+ debug_unresolved_namespace_scopes: std.AutoArrayHashMapUnmanaged(InternPool.NamespaceIndex, Builder.Metadata),
- pub fn get(self: Self, key: K) ?V {
- _ = self;
- _ = key;
- return null;
- }
- },
- di_compile_unit: ?if (build_options.have_llvm) *llvm.DICompileUnit else noreturn,
- target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void,
- target_data: if (build_options.have_llvm) *llvm.TargetData else void,
target: std.Target,
/// Ideally we would use `llvm_module.getNamedFunction` to go from *Decl to LLVM function,
/// but that has some downsides:
@@ -820,7 +802,6 @@ pub const Object = struct {
/// TODO when InternPool garbage collection is implemented, this map needs
/// to be garbage collected as well.
type_map: TypeMap,
- di_type_map: DITypeMap,
/// The LLVM global table which holds the names corresponding to Zig errors.
/// Note that the values are not added until `emit`, when all errors in
/// the compilation are known.
@@ -850,146 +831,87 @@ pub const Object = struct {
pub const TypeMap = std.AutoHashMapUnmanaged(InternPool.Index, Builder.Type);
- /// This is an ArrayHashMap as opposed to a HashMap because in `emit` we
- /// want to iterate over it while adding entries to it.
- pub const DITypeMap = std.AutoArrayHashMapUnmanaged(InternPool.Index, AnnotatedDITypePtr);
-
pub fn create(arena: Allocator, comp: *Compilation) !*Object {
if (build_options.only_c) unreachable;
const gpa = comp.gpa;
const target = comp.root_mod.resolved_target.result;
const llvm_target_triple = try targetTriple(arena, target);
const strip = comp.root_mod.strip;
- const optimize_mode = comp.root_mod.optimize_mode;
- const pic = comp.root_mod.pic;
var builder = try Builder.init(.{
.allocator = gpa,
- .use_lib_llvm = comp.config.use_lib_llvm,
- .strip = strip or !comp.config.use_lib_llvm, // TODO
+ .use_lib_llvm = false,
+ .strip = strip,
.name = comp.root_name,
.target = target,
.triple = llvm_target_triple,
});
errdefer builder.deinit();
- var target_machine: if (build_options.have_llvm) *llvm.TargetMachine else void = undefined;
- var target_data: if (build_options.have_llvm) *llvm.TargetData else void = undefined;
- if (builder.useLibLlvm()) {
- debug_info: {
- switch (comp.config.debug_format) {
- .strip => break :debug_info,
- .code_view => builder.llvm.module.?.addModuleCodeViewFlag(),
- .dwarf => |f| builder.llvm.module.?.addModuleDebugInfoFlag(f == .@"64"),
- }
- builder.llvm.di_builder = builder.llvm.module.?.createDIBuilder(true);
-
- // Don't use the version string here; LLVM misparses it when it
- // includes the git revision.
- const producer = try builder.fmt("zig {d}.{d}.{d}", .{
- build_options.semver.major,
- build_options.semver.minor,
- build_options.semver.patch,
- });
-
- // We fully resolve all paths at this point to avoid lack of
- // source line info in stack traces or lack of debugging
- // information which, if relative paths were used, would be
- // very location dependent.
- // TODO: the only concern I have with this is WASI as either host or target, should
- // we leave the paths as relative then?
- // TODO: This is totally wrong. In dwarf, paths are encoded as relative to
- // a particular directory, and then the directory path is specified elsewhere.
- // In the compiler frontend we have it stored correctly in this
- // way already, but here we throw all that sweet information
- // into the garbage can by converting into absolute paths. What
- // a terrible tragedy.
- const compile_unit_dir_z = blk: {
- if (comp.module) |zcu| m: {
- const d = try zcu.root_mod.root.joinStringZ(arena, "");
- if (d.len == 0) break :m;
- if (std.fs.path.isAbsolute(d)) break :blk d;
- const realpath = std.fs.realpathAlloc(arena, d) catch break :blk d;
- break :blk try arena.dupeZ(u8, realpath);
- }
- const cwd = try std.process.getCwdAlloc(arena);
- break :blk try arena.dupeZ(u8, cwd);
- };
-
- builder.llvm.di_compile_unit = builder.llvm.di_builder.?.createCompileUnit(
- DW.LANG.C99,
- builder.llvm.di_builder.?.createFile(comp.root_name, compile_unit_dir_z),
- producer.slice(&builder).?,
- optimize_mode != .Debug,
- "", // flags
- 0, // runtime version
- "", // split name
- 0, // dwo id
- true, // emit debug info
- );
+ builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }});
+
+ // We fully resolve all paths at this point to avoid lack of
+ // source line info in stack traces or lack of debugging
+ // information which, if relative paths were used, would be
+ // very location dependent.
+ // TODO: the only concern I have with this is WASI as either host or target, should
+ // we leave the paths as relative then?
+ // TODO: This is totally wrong. In dwarf, paths are encoded as relative to
+ // a particular directory, and then the directory path is specified elsewhere.
+ // In the compiler frontend we have it stored correctly in this
+ // way already, but here we throw all that sweet information
+ // into the garbage can by converting into absolute paths. What
+ // a terrible tragedy.
+ const compile_unit_dir = blk: {
+ if (comp.module) |zcu| m: {
+ const d = try zcu.root_mod.root.joinString(arena, "");
+ if (d.len == 0) break :m;
+ if (std.fs.path.isAbsolute(d)) break :blk d;
+ break :blk std.fs.realpathAlloc(arena, d) catch break :blk d;
}
+ break :blk try std.process.getCwdAlloc(arena);
+ };
- const opt_level: llvm.CodeGenOptLevel = if (optimize_mode == .Debug)
- .None
- else
- .Aggressive;
+ const debug_file = try builder.debugFile(
+ try builder.string(compile_unit_dir),
+ try builder.string(comp.root_name),
+ );
- const reloc_mode: llvm.RelocMode = if (pic)
- .PIC
- else if (comp.config.link_mode == .Dynamic)
- llvm.RelocMode.DynamicNoPIC
- else
- .Static;
-
- const code_model: llvm.CodeModel = switch (comp.root_mod.code_model) {
- .default => .Default,
- .tiny => .Tiny,
- .small => .Small,
- .kernel => .Kernel,
- .medium => .Medium,
- .large => .Large,
- };
+ const debug_enums_fwd_ref = try builder.debugForwardReference();
+ const debug_globals_fwd_ref = try builder.debugForwardReference();
+
+ const debug_compile_unit = try builder.debugCompileUnit(
+ debug_file,
+ // Don't use the version string here; LLVM misparses it when it
+ // includes the git revision.
+ try builder.fmt("zig {d}.{d}.{d}", .{
+ build_options.semver.major,
+ build_options.semver.minor,
+ build_options.semver.patch,
+ }),
+ debug_enums_fwd_ref,
+ debug_globals_fwd_ref,
+ .{ .optimized = comp.root_mod.optimize_mode != .Debug },
+ );
- // TODO handle float ABI better- it should depend on the ABI portion of std.Target
- const float_abi: llvm.ABIType = .Default;
-
- target_machine = llvm.TargetMachine.create(
- builder.llvm.target.?,
- builder.target_triple.slice(&builder).?,
- if (target.cpu.model.llvm_name) |s| s.ptr else null,
- comp.root_mod.resolved_target.llvm_cpu_features.?,
- opt_level,
- reloc_mode,
- code_model,
- comp.function_sections,
- comp.data_sections,
- float_abi,
- if (target_util.llvmMachineAbi(target)) |s| s.ptr else null,
+ if (!builder.strip) {
+ const debug_info_version = try builder.debugModuleFlag(
+ try builder.debugConstant(try builder.intConst(.i32, 2)),
+ try builder.string("Debug Info Version"),
+ try builder.debugConstant(try builder.intConst(.i32, 3)),
+ );
+ const dwarf_version = try builder.debugModuleFlag(
+ try builder.debugConstant(try builder.intConst(.i32, 2)),
+ try builder.string("Dwarf Version"),
+ try builder.debugConstant(try builder.intConst(.i32, 4)),
);
- errdefer target_machine.dispose();
-
- target_data = target_machine.createTargetDataLayout();
- errdefer target_data.dispose();
-
- builder.llvm.module.?.setModuleDataLayout(target_data);
-
- if (pic) builder.llvm.module.?.setModulePICLevel();
- if (comp.config.pie) builder.llvm.module.?.setModulePIELevel();
- if (code_model != .Default) builder.llvm.module.?.setModuleCodeModel(code_model);
- if (comp.llvm_opt_bisect_limit >= 0) {
- builder.llvm.context.setOptBisectLimit(comp.llvm_opt_bisect_limit);
- }
+ try builder.debugNamed(try builder.string("llvm.module.flags"), &.{
+ debug_info_version,
+ dwarf_version,
+ });
- builder.data_layout = try builder.fmt("{}", .{DataLayoutBuilder{ .target = target }});
- if (std.debug.runtime_safety) {
- const rep = target_data.stringRep();
- defer llvm.disposeMessage(rep);
- std.testing.expectEqualStrings(
- std.mem.span(rep),
- builder.data_layout.slice(&builder).?,
- ) catch unreachable;
- }
+ try builder.debugNamed(try builder.string("llvm.dbg.cu"), &.{debug_compile_unit});
}
const obj = try arena.create(Object);
@@ -997,17 +919,18 @@ pub const Object = struct {
.gpa = gpa,
.builder = builder,
.module = comp.module.?,
- .di_map = .{},
- .di_builder = if (builder.useLibLlvm()) builder.llvm.di_builder else null, // TODO
- .di_compile_unit = if (builder.useLibLlvm()) builder.llvm.di_compile_unit else null,
- .target_machine = target_machine,
- .target_data = target_data,
+ .debug_compile_unit = debug_compile_unit,
+ .debug_enums_fwd_ref = debug_enums_fwd_ref,
+ .debug_globals_fwd_ref = debug_globals_fwd_ref,
+ .debug_enums = .{},
+ .debug_globals = .{},
+ .debug_type_map = .{},
+ .debug_unresolved_namespace_scopes = .{},
.target = target,
.decl_map = .{},
.anon_decl_map = .{},
.named_enum_map = .{},
.type_map = .{},
- .di_type_map = .{},
.error_name_table = .none,
.extern_collisions = .{},
.null_opt_usize = .no_init,
@@ -1018,12 +941,10 @@ pub const Object = struct {
pub fn deinit(self: *Object) void {
const gpa = self.gpa;
- self.di_map.deinit(gpa);
- self.di_type_map.deinit(gpa);
- if (self.builder.useLibLlvm()) {
- self.target_data.dispose();
- self.target_machine.dispose();
- }
+ self.debug_globals.deinit(gpa);
+ self.debug_enums.deinit(gpa);
+ self.debug_type_map.deinit(gpa);
+ self.debug_unresolved_namespace_scopes.deinit(gpa);
self.decl_map.deinit(gpa);
self.anon_decl_map.deinit(gpa);
self.named_enum_map.deinit(gpa);
@@ -1193,26 +1114,29 @@ pub const Object = struct {
try self.genCmpLtErrorsLenFunction();
try self.genModuleLevelAssembly();
- if (self.di_builder) |dib| {
- // When lowering debug info for pointers, we emitted the element types as
- // forward decls. Now we must go flesh those out.
- // Here we iterate over a hash map while modifying it but it is OK because
- // we never add or remove entries during this loop.
+ {
var i: usize = 0;
- while (i < self.di_type_map.count()) : (i += 1) {
- const value_ptr = &self.di_type_map.values()[i];
- const annotated = value_ptr.*;
- if (!annotated.isFwdOnly()) continue;
- const entry: Object.DITypeMap.Entry = .{
- .key_ptr = &self.di_type_map.keys()[i],
- .value_ptr = value_ptr,
- };
- _ = try self.lowerDebugTypeImpl(entry, .full, annotated.toDIType());
- }
+ while (i < self.debug_unresolved_namespace_scopes.count()) : (i += 1) {
+ const namespace_index = self.debug_unresolved_namespace_scopes.keys()[i];
+ const fwd_ref = self.debug_unresolved_namespace_scopes.values()[i];
+ const namespace = self.module.namespacePtr(namespace_index);
+
+ const debug_type = try self.lowerDebugType(namespace.ty);
- dib.finalize();
+ self.builder.debugForwardReferenceSetType(fwd_ref, debug_type);
+ }
}
+ self.builder.debugForwardReferenceSetType(
+ self.debug_enums_fwd_ref,
+ try self.builder.debugTuple(self.debug_enums.items),
+ );
+
+ self.builder.debugForwardReferenceSetType(
+ self.debug_globals_fwd_ref,
+ try self.builder.debugTuple(self.debug_globals.items),
+ );
+
if (options.pre_ir_path) |path| {
if (std.mem.eql(u8, path, "-")) {
self.builder.dump();
@@ -1238,35 +1162,126 @@ pub const Object = struct {
if (options.asm_path == null and options.bin_path == null and
options.post_ir_path == null and options.post_bc_path == null) return;
- if (options.post_bc_path) |path| {
- if (!self.builder.useLibLlvm()) {
- var arena_allocator = std.heap.ArenaAllocator.init(self.gpa);
- defer arena_allocator.deinit();
- const arena = arena_allocator.allocator();
+ var bitcode_arena_allocator = std.heap.ArenaAllocator.init(
+ std.heap.page_allocator,
+ );
+ errdefer bitcode_arena_allocator.deinit();
- var file = try std.fs.cwd().createFileZ(path, .{});
- defer file.close();
- const bitcode = try self.builder.toBitcode(arena);
+ const bitcode = try self.builder.toBitcode(
+ bitcode_arena_allocator.allocator(),
+ );
- const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
- try file.writeAll(ptr[0..(bitcode.len * 4)]);
- return;
- }
+ if (options.post_bc_path) |path| {
+ var file = try std.fs.cwd().createFileZ(path, .{});
+ defer file.close();
+
+ const ptr: [*]const u8 = @ptrCast(bitcode.ptr);
+ try file.writeAll(ptr[0..(bitcode.len * 4)]);
}
- if (!self.builder.useLibLlvm()) {
+ if (!self.module.comp.config.use_lib_llvm) {
log.err("emitting without libllvm not implemented", .{});
return error.FailedToEmit;
}
+ Builder.initializeLLVMTarget(self.module.comp.root_mod.resolved_target.result.cpu.arch);
+
+ const context: *llvm.Context = llvm.Context.create();
+ defer context.dispose();
+
+ const module = blk: {
+ const bitcode_memory_buffer = llvm.MemoryBuffer.createMemoryBufferWithMemoryRange(
+ @ptrCast(bitcode.ptr),
+ bitcode.len * 4,
+ "BitcodeBuffer",
+ llvm.Bool.False,
+ );
+ defer bitcode_memory_buffer.dispose();
+
+ var module: *llvm.Module = undefined;
+ if (context.parseBitcodeInContext2(bitcode_memory_buffer, &module).toBool()) {
+ std.debug.print("Failed to parse bitcode\n", .{});
+ return error.FailedToEmit;
+ }
+
+ break :blk module;
+ };
+ bitcode_arena_allocator.deinit();
+
+ var error_message: [*:0]const u8 = undefined;
+ var target: *llvm.Target = undefined;
+ if (llvm.Target.getFromTriple(
+ self.builder.target_triple.slice(&self.builder).?,
+ &target,
+ &error_message,
+ ).toBool()) {
+ defer llvm.disposeMessage(error_message);
+
+ log.err("LLVM failed to parse '{s}': {s}", .{
+ self.builder.target_triple.slice(&self.builder).?,
+ error_message,
+ });
+ @panic("Invalid LLVM triple");
+ }
+
+ const optimize_mode = self.module.comp.root_mod.optimize_mode;
+ const pic = self.module.comp.root_mod.pic;
+
+ const opt_level: llvm.CodeGenOptLevel = if (optimize_mode == .Debug)
+ .None
+ else
+ .Aggressive;
+
+ const reloc_mode: llvm.RelocMode = if (pic)
+ .PIC
+ else if (self.module.comp.config.link_mode == .Dynamic)
+ llvm.RelocMode.DynamicNoPIC
+ else
+ .Static;
+
+ const code_model: llvm.CodeModel = switch (self.module.comp.root_mod.code_model) {
+ .default => .Default,
+ .tiny => .Tiny,
+ .small => .Small,
+ .kernel => .Kernel,
+ .medium => .Medium,
+ .large => .Large,
+ };
+
+ // TODO handle float ABI better- it should depend on the ABI portion of std.Target
+ const float_abi: llvm.ABIType = .Default;
+
+ var target_machine = llvm.TargetMachine.create(
+ target,
+ self.builder.target_triple.slice(&self.builder).?,
+ if (self.module.comp.root_mod.resolved_target.result.cpu.model.llvm_name) |s| s.ptr else null,
+ self.module.comp.root_mod.resolved_target.llvm_cpu_features.?,
+ opt_level,
+ reloc_mode,
+ code_model,
+ self.module.comp.function_sections,
+ self.module.comp.data_sections,
+ float_abi,
+ if (target_util.llvmMachineAbi(self.module.comp.root_mod.resolved_target.result)) |s| s.ptr else null,
+ );
+ errdefer target_machine.dispose();
+
+ if (pic) module.setModulePICLevel();
+ if (self.module.comp.config.pie) module.setModulePIELevel();
+ if (code_model != .Default) module.setModuleCodeModel(code_model);
+
+ if (self.module.comp.llvm_opt_bisect_limit >= 0) {
+ context.setOptBisectLimit(self.module.comp.llvm_opt_bisect_limit);
+ }
+
// Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
// So we call the entire pipeline multiple times if this is requested.
- var error_message: [*:0]const u8 = undefined;
+ // var error_message: [*:0]const u8 = undefined;
var emit_bin_path = options.bin_path;
var post_ir_path = options.post_ir_path;
if (options.asm_path != null and options.bin_path != null) {
- if (self.target_machine.emitToFile(
- self.builder.llvm.module.?,
+ if (target_machine.emitToFile(
+ module,
&error_message,
options.is_debug,
options.is_small,
@@ -1289,8 +1304,8 @@ pub const Object = struct {
post_ir_path = null;
}
- if (self.target_machine.emitToFile(
- self.builder.llvm.module.?,
+ if (target_machine.emitToFile(
+ module,
&error_message,
options.is_debug,
options.is_small,
@@ -1300,7 +1315,7 @@ pub const Object = struct {
options.asm_path,
emit_bin_path,
post_ir_path,
- options.post_bc_path,
+ null,
)) {
defer llvm.disposeMessage(error_message);
@@ -1440,7 +1455,7 @@ pub const Object = struct {
if (isByRef(param_ty, zcu)) {
const alignment = param_ty.abiAlignment(zcu).toLlvm();
const param_llvm_ty = param.typeOfWip(&wip);
- const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
+ const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(arg_ptr);
} else {
@@ -1488,7 +1503,7 @@ pub const Object = struct {
const param_llvm_ty = try o.lowerType(param_ty);
const alignment = param_ty.abiAlignment(zcu).toLlvm();
- const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
+ const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
@@ -1533,7 +1548,7 @@ pub const Object = struct {
const param_ty = Type.fromInterned(fn_info.param_types.get(ip)[it.zig_index - 1]);
const param_llvm_ty = try o.lowerType(param_ty);
const param_alignment = param_ty.abiAlignment(zcu).toLlvm();
- const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, param_alignment, target);
+ const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, param_alignment, target);
const llvm_ty = try o.builder.structType(.normal, field_types);
for (0..field_types.len) |field_i| {
const param = wip.arg(llvm_arg_i);
@@ -1563,7 +1578,7 @@ pub const Object = struct {
llvm_arg_i += 1;
const alignment = param_ty.abiAlignment(zcu).toLlvm();
- const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
+ const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
@@ -1578,7 +1593,7 @@ pub const Object = struct {
llvm_arg_i += 1;
const alignment = param_ty.abiAlignment(zcu).toLlvm();
- const arg_ptr = try buildAllocaInner(&wip, false, param_llvm_ty, alignment, target);
+ const arg_ptr = try buildAllocaInner(&wip, param_llvm_ty, alignment, target);
_ = try wip.store(.normal, param, arg_ptr, alignment);
args.appendAssumeCapacity(if (isByRef(param_ty, zcu))
@@ -1592,40 +1607,34 @@ pub const Object = struct {
function_index.setAttributes(try attributes.finish(&o.builder), &o.builder);
- var di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn = null;
- var di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn = null;
-
- if (o.di_builder) |dib| {
- di_file = try o.getDIFile(gpa, namespace.file_scope);
+ const file = try o.getDebugFile(namespace.file_scope);
+ const subprogram = blk: {
const line_number = decl.src_line + 1;
const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
!zcu.decl_exports.contains(decl_index);
- const noret_bit: c_uint = if (fn_info.return_type == .noreturn_type)
+ const noret_bit: u29 = if (fn_info.return_type == .noreturn_type)
llvm.DIFlags.NoReturn
else
0;
- const decl_di_ty = try o.lowerDebugType(decl.ty, .full);
- const subprogram = dib.createFunction(
- di_file.?.toScope(),
- ip.stringToSlice(decl.name),
- function_index.name(&o.builder).slice(&o.builder).?,
- di_file.?,
+ const debug_decl_type = try o.lowerDebugType(decl.ty);
+
+ break :blk try o.builder.debugSubprogram(
+ file,
+ try o.builder.string(ip.stringToSlice(decl.name)),
+ function_index.name(&o.builder),
line_number,
- decl_di_ty,
- is_internal_linkage,
- true, // is definition
- line_number + func.lbrace_line, // scope line
- llvm.DIFlags.StaticMember | noret_bit,
- owner_mod.optimize_mode != .Debug,
- null, // decl_subprogram
+ line_number + func.lbrace_line,
+ debug_decl_type,
+ .{
+ .optimized = owner_mod.optimize_mode != .Debug,
+ .definition = true,
+ .local = is_internal_linkage,
+ .debug_info_flags = llvm.DIFlags.StaticMember | noret_bit,
+ },
+ o.debug_compile_unit,
);
- try o.di_map.put(gpa, decl, subprogram.toNode());
-
- function_index.toLlvm(&o.builder).fnSetSubprogram(subprogram);
-
- di_scope = subprogram.toScope();
- }
+ };
var fg: FuncGen = .{
.gpa = gpa,
@@ -1639,8 +1648,9 @@ pub const Object = struct {
.func_inst_table = .{},
.blocks = .{},
.sync_scope = if (owner_mod.single_threaded) .singlethread else .system,
- .di_scope = di_scope,
- .di_file = di_file,
+ .file = file,
+ .subprogram = subprogram,
+ .current_scope = subprogram,
.base_line = dg.decl.src_line,
.prev_dbg_line = 0,
.prev_dbg_column = 0,
@@ -1726,26 +1736,7 @@ pub const Object = struct {
global_index.setUnnamedAddr(.default, &self.builder);
if (comp.config.dll_export_fns)
global_index.setDllStorageClass(.default, &self.builder);
- if (self.di_map.get(decl)) |di_node| {
- const decl_name_slice = decl_name.slice(&self.builder).?;
- if (try decl.isFunction(mod)) {
- const di_func: *llvm.DISubprogram = @ptrCast(di_node);
- const linkage_name = llvm.MDString.get(
- self.builder.llvm.context,
- decl_name_slice.ptr,
- decl_name_slice.len,
- );
- di_func.replaceLinkageName(linkage_name);
- } else {
- const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
- const linkage_name = llvm.MDString.get(
- self.builder.llvm.context,
- decl_name_slice.ptr,
- decl_name_slice.len,
- );
- di_global.replaceLinkageName(linkage_name);
- }
- }
+
if (decl.val.getVariable(mod)) |decl_var| {
global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
if (decl_var.is_threadlocal) .generaldynamic else .default,
@@ -1759,27 +1750,6 @@ pub const Object = struct {
);
try global_index.rename(main_exp_name, &self.builder);
- if (self.di_map.get(decl)) |di_node| {
- const main_exp_name_slice = main_exp_name.slice(&self.builder).?;
- if (try decl.isFunction(mod)) {
- const di_func: *llvm.DISubprogram = @ptrCast(di_node);
- const linkage_name = llvm.MDString.get(
- self.builder.llvm.context,
- main_exp_name_slice.ptr,
- main_exp_name_slice.len,
- );
- di_func.replaceLinkageName(linkage_name);
- } else {
- const di_global: *llvm.DIGlobalVariable = @ptrCast(di_node);
- const linkage_name = llvm.MDString.get(
- self.builder.llvm.context,
- main_exp_name_slice.ptr,
- main_exp_name_slice.len,
- );
- di_global.replaceLinkageName(linkage_name);
- }
- }
-
if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
global_index.ptrConst(&self.builder).kind
.variable.setThreadLocal(.generaldynamic, &self.builder);
@@ -1909,119 +1879,64 @@ pub const Object = struct {
global.delete(&self.builder);
}
- fn getDIFile(o: *Object, gpa: Allocator, file: *const Module.File) !*llvm.DIFile {
- const gop = try o.di_map.getOrPut(gpa, file);
- errdefer assert(o.di_map.remove(file));
- if (gop.found_existing) {
- return @ptrCast(gop.value_ptr.*);
- }
- const dir_path_z = d: {
- var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- const sub_path = std.fs.path.dirname(file.sub_file_path) orelse "";
- const dir_path = try file.mod.root.joinStringZ(gpa, sub_path);
- if (std.fs.path.isAbsolute(dir_path)) break :d dir_path;
- const abs = std.fs.realpath(dir_path, &buffer) catch break :d dir_path;
- gpa.free(dir_path);
- break :d try gpa.dupeZ(u8, abs);
- };
- defer gpa.free(dir_path_z);
- const sub_file_path_z = try gpa.dupeZ(u8, std.fs.path.basename(file.sub_file_path));
- defer gpa.free(sub_file_path_z);
- const di_file = o.di_builder.?.createFile(sub_file_path_z, dir_path_z);
- gop.value_ptr.* = di_file.toNode();
- return di_file;
+ fn getDebugFile(o: *Object, file: *const Module.File) Allocator.Error!Builder.Metadata {
+ return try o.builder.debugFile(
+ if (std.fs.path.dirname(file.sub_file_path)) |dirname| try o.builder.string(dirname) else .empty,
+ try o.builder.string(std.fs.path.basename(file.sub_file_path)),
+ );
}
- const DebugResolveStatus = enum { fwd, full };
-
- /// In the implementation of this function, it is required to store a forward decl
- /// into `gop` before making any recursive calls (even directly).
- fn lowerDebugType(
+ pub fn lowerDebugType(
o: *Object,
ty: Type,
- resolve: DebugResolveStatus,
- ) Allocator.Error!*llvm.DIType {
- const gpa = o.gpa;
- // Be careful not to reference this `gop` variable after any recursive calls
- // to `lowerDebugType`.
- const gop = try o.di_type_map.getOrPut(gpa, ty.toIntern());
- if (gop.found_existing) {
- const annotated = gop.value_ptr.*;
- switch (annotated) {
- // This type is currently attempting to be resolved fully, so make
- // sure a second recursion through the types uses forward resolution.
- .null => assert(resolve == .fwd),
- // This type already has at least forward resolution, only resolve
- // fully during full resolution.
- _ => {
- const di_type = annotated.toDIType();
- if (!annotated.isFwdOnly() or resolve == .fwd) {
- return di_type;
- }
- const entry: Object.DITypeMap.Entry = .{
- .key_ptr = gop.key_ptr,
- .value_ptr = gop.value_ptr,
- };
- return o.lowerDebugTypeImpl(entry, resolve, di_type);
- },
- }
- } else gop.value_ptr.* = .null;
- errdefer if (!gop.found_existing) assert(o.di_type_map.orderedRemove(ty.toIntern()));
- const entry: Object.DITypeMap.Entry = .{
- .key_ptr = gop.key_ptr,
- .value_ptr = gop.value_ptr,
- };
- return o.lowerDebugTypeImpl(entry, resolve, null);
- }
-
- /// This is a helper function used by `lowerDebugType`.
- fn lowerDebugTypeImpl(
- o: *Object,
- gop: Object.DITypeMap.Entry,
- resolve: DebugResolveStatus,
- opt_fwd_decl: ?*llvm.DIType,
- ) Allocator.Error!*llvm.DIType {
- const ty = Type.fromInterned(gop.key_ptr.*);
+ ) Allocator.Error!Builder.Metadata {
+ if (o.builder.strip) return Builder.Metadata.none;
const gpa = o.gpa;
const target = o.target;
- const dib = o.di_builder.?;
const mod = o.module;
const ip = &mod.intern_pool;
+
+ if (o.debug_type_map.get(ty)) |debug_type| return debug_type;
+
switch (ty.zigTypeTag(mod)) {
- .Void, .NoReturn => {
- const di_type = dib.createBasicType("void", 0, DW.ATE.signed);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
- return di_type;
+ .Void,
+ .NoReturn,
+ => {
+ const debug_void_type = try o.builder.debugSignedType(
+ try o.builder.string("void"),
+ 0,
+ );
+ try o.debug_type_map.put(gpa, ty, debug_void_type);
+ return debug_void_type;
},
.Int => {
const info = ty.intInfo(mod);
assert(info.bits != 0);
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const dwarf_encoding: c_uint = switch (info.signedness) {
- .signed => DW.ATE.signed,
- .unsigned => DW.ATE.unsigned,
+ const builder_name = try o.builder.string(name);
+ const debug_bits = ty.abiSize(mod) * 8; // lldb cannot handle non-byte sized types
+ const debug_int_type = switch (info.signedness) {
+ .signed => try o.builder.debugSignedType(builder_name, debug_bits),
+ .unsigned => try o.builder.debugUnsignedType(builder_name, debug_bits),
};
- const di_bits = ty.abiSize(mod) * 8; // lldb cannot handle non-byte sized types
- const di_type = dib.createBasicType(name, di_bits, dwarf_encoding);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
- return di_type;
+ try o.debug_type_map.put(gpa, ty, debug_int_type);
+ return debug_int_type;
},
.Enum => {
const owner_decl_index = ty.getOwnerDecl(mod);
const owner_decl = o.module.declPtr(owner_decl_index);
if (!ty.hasRuntimeBitsIgnoreComptime(mod)) {
- const enum_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
- // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(enum_di_ty));
- return enum_di_ty;
+ const debug_enum_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
+ try o.debug_type_map.put(gpa, ty, debug_enum_type);
+ try o.debug_enums.append(gpa, debug_enum_type);
+ return debug_enum_type;
}
const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
- const enumerators = try gpa.alloc(*llvm.DIEnumerator, enum_type.names.len);
+ const enumerators = try gpa.alloc(Builder.Metadata, enum_type.names.len);
defer gpa.free(enumerators);
const int_ty = Type.fromInterned(enum_type.tag_ty);
@@ -2029,66 +1944,59 @@ pub const Object = struct {
assert(int_info.bits != 0);
for (enum_type.names.get(ip), 0..) |field_name_ip, i| {
- const field_name_z = ip.stringToSlice(field_name_ip);
-
var bigint_space: Value.BigIntSpace = undefined;
const bigint = if (enum_type.values.len != 0)
Value.fromInterned(enum_type.values.get(ip)[i]).toBigInt(&bigint_space, mod)
else
std.math.big.int.Mutable.init(&bigint_space.limbs, i).toConst();
- if (bigint.limbs.len == 1) {
- enumerators[i] = dib.createEnumerator(field_name_z, bigint.limbs[0], int_info.signedness == .unsigned);
- continue;
- }
- if (@sizeOf(usize) == @sizeOf(u64)) {
- enumerators[i] = dib.createEnumerator2(
- field_name_z,
- @intCast(bigint.limbs.len),
- bigint.limbs.ptr,
- int_info.bits,
- int_info.signedness == .unsigned,
- );
- continue;
- }
- @panic("TODO implement bigint debug enumerators to llvm int for 32-bit compiler builds");
+ enumerators[i] = try o.builder.debugEnumerator(
+ try o.builder.string(ip.stringToSlice(field_name_ip)),
+ int_ty.isUnsignedInt(mod),
+ int_info.bits,
+ bigint,
+ );
}
- const di_file = try o.getDIFile(gpa, mod.namespacePtr(owner_decl.src_namespace).file_scope);
- const di_scope = try o.namespaceToDebugScope(owner_decl.src_namespace);
+ const file = try o.getDebugFile(mod.namespacePtr(owner_decl.src_namespace).file_scope);
+ const scope = try o.namespaceToDebugScope(owner_decl.src_namespace);
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const enum_di_ty = dib.createEnumerationType(
- di_scope,
- name,
- di_file,
- owner_decl.src_node + 1,
+ const debug_enum_type = try o.builder.debugEnumerationType(
+ try o.builder.string(name),
+ file,
+ scope,
+ owner_decl.src_node + 1, // Line
+ try o.lowerDebugType(int_ty),
ty.abiSize(mod) * 8,
ty.abiAlignment(mod).toByteUnits(0) * 8,
- enumerators.ptr,
- @intCast(enumerators.len),
- try o.lowerDebugType(int_ty, resolve),
- "",
+ try o.builder.debugTuple(enumerators),
);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(enum_di_ty));
- return enum_di_ty;
+
+ try o.debug_type_map.put(gpa, ty, debug_enum_type);
+ try o.debug_enums.append(gpa, debug_enum_type);
+ return debug_enum_type;
},
.Float => {
const bits = ty.floatBits(target);
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const di_type = dib.createBasicType(name, bits, DW.ATE.float);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
- return di_type;
+ const debug_float_type = try o.builder.debugFloatType(
+ try o.builder.string(name),
+ bits,
+ );
+ try o.debug_type_map.put(gpa, ty, debug_float_type);
+ return debug_float_type;
},
.Bool => {
- const di_bits = 8; // lldb cannot handle non-byte sized types
- const di_type = dib.createBasicType("bool", di_bits, DW.ATE.boolean);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_type);
- return di_type;
+ const debug_bool_type = try o.builder.debugBoolType(
+ try o.builder.string("bool"),
+ 8, // lldb cannot handle non-byte sized types
+ );
+ try o.debug_type_map.put(gpa, ty, debug_bool_type);
+ return debug_bool_type;
},
.Pointer => {
// Normalize everything that the debug info does not represent.
@@ -2118,136 +2026,145 @@ pub const Object = struct {
},
},
});
- const ptr_di_ty = try o.lowerDebugType(bland_ptr_ty, resolve);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.init(ptr_di_ty, resolve));
- return ptr_di_ty;
+ const debug_ptr_type = try o.lowerDebugType(bland_ptr_ty);
+ try o.debug_type_map.put(gpa, ty, debug_ptr_type);
+ return debug_ptr_type;
}
+ const debug_fwd_ref = try o.builder.debugForwardReference();
+
+ // Set as forward reference while the type is lowered in case it references itself
+ try o.debug_type_map.put(gpa, ty, debug_fwd_ref);
+
if (ty.isSlice(mod)) {
const ptr_ty = ty.slicePtrFieldType(mod);
const len_ty = Type.usize;
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const di_file: ?*llvm.DIFile = null;
const line = 0;
- const compile_unit_scope = o.di_compile_unit.?.toScope();
-
- const fwd_decl = opt_fwd_decl orelse blk: {
- const fwd_decl = dib.createReplaceableCompositeType(
- DW.TAG.structure_type,
- name.ptr,
- compile_unit_scope,
- di_file,
- line,
- );
- gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
- if (resolve == .fwd) return fwd_decl;
- break :blk fwd_decl;
- };
const ptr_size = ptr_ty.abiSize(mod);
const ptr_align = ptr_ty.abiAlignment(mod);
const len_size = len_ty.abiSize(mod);
const len_align = len_ty.abiAlignment(mod);
- var offset: u64 = 0;
- offset += ptr_size;
- offset = len_align.forward(offset);
- const len_offset = offset;
-
- const fields: [2]*llvm.DIType = .{
- dib.createMemberType(
- fwd_decl.toScope(),
- "ptr",
- di_file,
- line,
- ptr_size * 8, // size in bits
- ptr_align.toByteUnits(0) * 8, // align in bits
- 0, // offset in bits
- 0, // flags
- try o.lowerDebugType(ptr_ty, resolve),
- ),
- dib.createMemberType(
- fwd_decl.toScope(),
- "len",
- di_file,
- line,
- len_size * 8, // size in bits
- len_align.toByteUnits(0) * 8, // align in bits
- len_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(len_ty, resolve),
- ),
- };
+ const len_offset = len_align.forward(ptr_size);
+
+ const debug_ptr_type = try o.builder.debugMemberType(
+ try o.builder.string("ptr"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(ptr_ty),
+ ptr_size * 8,
+ ptr_align.toByteUnits(0) * 8,
+ 0, // Offset
+ );
+
+ const debug_len_type = try o.builder.debugMemberType(
+ try o.builder.string("len"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(len_ty),
+ len_size * 8,
+ len_align.toByteUnits(0) * 8,
+ len_offset * 8,
+ );
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- di_file,
+ const debug_slice_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
line,
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- &fields,
- fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(&.{
+ debug_ptr_type,
+ debug_len_type,
+ }),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_slice_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_slice_type;
+
+ return debug_slice_type;
}
- const elem_di_ty = try o.lowerDebugType(Type.fromInterned(ptr_info.child), .fwd);
+ const debug_elem_ty = try o.lowerDebugType(Type.fromInterned(ptr_info.child));
+
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const ptr_di_ty = dib.createPointerType(
- elem_di_ty,
+
+ const debug_ptr_type = try o.builder.debugPointerType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ Builder.Metadata.none, // Scope
+ 0, // Line
+ debug_elem_ty,
target.ptrBitWidth(),
ty.ptrAlignment(mod).toByteUnits(0) * 8,
- name,
+ 0, // Offset
);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(ptr_di_ty));
- return ptr_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_ptr_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_ptr_type;
+
+ return debug_ptr_type;
},
.Opaque => {
if (ty.toIntern() == .anyopaque_type) {
- const di_ty = dib.createBasicType("anyopaque", 0, DW.ATE.signed);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
- return di_ty;
+ const debug_opaque_type = try o.builder.debugSignedType(
+ try o.builder.string("anyopaque"),
+ 0,
+ );
+ try o.debug_type_map.put(gpa, ty, debug_opaque_type);
+ return debug_opaque_type;
}
+
const name = try o.allocTypeName(ty);
defer gpa.free(name);
const owner_decl_index = ty.getOwnerDecl(mod);
const owner_decl = o.module.declPtr(owner_decl_index);
- const opaque_di_ty = dib.createForwardDeclType(
- DW.TAG.structure_type,
- name,
+ const debug_opaque_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ try o.getDebugFile(mod.namespacePtr(owner_decl.src_namespace).file_scope),
try o.namespaceToDebugScope(owner_decl.src_namespace),
- try o.getDIFile(gpa, mod.namespacePtr(owner_decl.src_namespace).file_scope),
- owner_decl.src_node + 1,
+ owner_decl.src_node + 1, // Line
+ Builder.Metadata.none, // Underlying type
+ 0, // Size
+ 0, // Align
+ Builder.Metadata.none, // Fields
);
- // The recursive call to `lowerDebugType` va `namespaceToDebugScope`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(opaque_di_ty));
- return opaque_di_ty;
+ try o.debug_type_map.put(gpa, ty, debug_opaque_type);
+ return debug_opaque_type;
},
.Array => {
- const array_di_ty = dib.createArrayType(
+ const debug_array_type = try o.builder.debugArrayType(
+ Builder.String.empty, // Name
+ Builder.Metadata.none, // File
+ Builder.Metadata.none, // Scope
+ 0, // Line
+ try o.lowerDebugType(ty.childType(mod)),
ty.abiSize(mod) * 8,
ty.abiAlignment(mod).toByteUnits(0) * 8,
- try o.lowerDebugType(ty.childType(mod), resolve),
- @intCast(ty.arrayLen(mod)),
+ try o.builder.debugTuple(&.{
+ try o.builder.debugSubrange(
+ try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
+ try o.builder.debugConstant(try o.builder.intConst(.i64, ty.arrayLen(mod))),
+ ),
+ }),
);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(array_di_ty));
- return array_di_ty;
+ try o.debug_type_map.put(gpa, ty, debug_array_type);
+ return debug_array_type;
},
.Vector => {
const elem_ty = ty.elemType2(mod);
@@ -2255,146 +2172,136 @@ pub const Object = struct {
// @bitSizOf(elem) * len > @bitSizOf(vec).
// Neither gdb nor lldb seem to be able to display non-byte sized
// vectors properly.
- const elem_di_type = switch (elem_ty.zigTypeTag(mod)) {
+ const debug_elem_type = switch (elem_ty.zigTypeTag(mod)) {
.Int => blk: {
const info = elem_ty.intInfo(mod);
assert(info.bits != 0);
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const dwarf_encoding: c_uint = switch (info.signedness) {
- .signed => DW.ATE.signed,
- .unsigned => DW.ATE.unsigned,
+ const builder_name = try o.builder.string(name);
+ break :blk switch (info.signedness) {
+ .signed => try o.builder.debugSignedType(builder_name, info.bits),
+ .unsigned => try o.builder.debugUnsignedType(builder_name, info.bits),
};
- break :blk dib.createBasicType(name, info.bits, dwarf_encoding);
},
- .Bool => dib.createBasicType("bool", 1, DW.ATE.boolean),
- else => try o.lowerDebugType(ty.childType(mod), resolve),
+ .Bool => try o.builder.debugBoolType(
+ try o.builder.string("bool"),
+ 1,
+ ),
+ else => try o.lowerDebugType(ty.childType(mod)),
};
- const vector_di_ty = dib.createVectorType(
+ const debug_vector_type = try o.builder.debugArrayType(
+ Builder.String.empty, // Name
+ Builder.Metadata.none, // File
+ Builder.Metadata.none, // Scope
+ 0, // Line
+ debug_elem_type,
ty.abiSize(mod) * 8,
- @intCast(ty.abiAlignment(mod).toByteUnits(0) * 8),
- elem_di_type,
- ty.vectorLen(mod),
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(&.{
+ try o.builder.debugSubrange(
+ try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
+ try o.builder.debugConstant(try o.builder.intConst(.i64, ty.vectorLen(mod))),
+ ),
+ }),
);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(vector_di_ty));
- return vector_di_ty;
+
+ try o.debug_type_map.put(gpa, ty, debug_vector_type);
+ return debug_vector_type;
},
.Optional => {
const name = try o.allocTypeName(ty);
defer gpa.free(name);
const child_ty = ty.optionalChild(mod);
if (!child_ty.hasRuntimeBitsIgnoreComptime(mod)) {
- const di_bits = 8; // lldb cannot handle non-byte sized types
- const di_ty = dib.createBasicType(name, di_bits, DW.ATE.boolean);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
- return di_ty;
+ const debug_bool_type = try o.builder.debugBoolType(
+ try o.builder.string(name),
+ 8,
+ );
+ try o.debug_type_map.put(gpa, ty, debug_bool_type);
+ return debug_bool_type;
}
+
+ const debug_fwd_ref = try o.builder.debugForwardReference();
+
+ // Set as forward reference while the type is lowered in case it references itself
+ try o.debug_type_map.put(gpa, ty, debug_fwd_ref);
+
if (ty.optionalReprIsPayload(mod)) {
- const ptr_di_ty = try o.lowerDebugType(child_ty, resolve);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.init(ptr_di_ty, resolve));
- return ptr_di_ty;
- }
+ const debug_optional_type = try o.lowerDebugType(child_ty);
- const di_file: ?*llvm.DIFile = null;
- const line = 0;
- const compile_unit_scope = o.di_compile_unit.?.toScope();
- const fwd_decl = opt_fwd_decl orelse blk: {
- const fwd_decl = dib.createReplaceableCompositeType(
- DW.TAG.structure_type,
- name.ptr,
- compile_unit_scope,
- di_file,
- line,
- );
- gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
- if (resolve == .fwd) return fwd_decl;
- break :blk fwd_decl;
- };
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_optional_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_optional_type;
+
+ return debug_optional_type;
+ }
const non_null_ty = Type.u8;
const payload_size = child_ty.abiSize(mod);
const payload_align = child_ty.abiAlignment(mod);
const non_null_size = non_null_ty.abiSize(mod);
const non_null_align = non_null_ty.abiAlignment(mod);
+ const non_null_offset = non_null_align.forward(payload_size);
+
+ const debug_data_type = try o.builder.debugMemberType(
+ try o.builder.string("data"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(child_ty),
+ payload_size * 8,
+ payload_align.toByteUnits(0) * 8,
+ 0, // Offset
+ );
- var offset: u64 = 0;
- offset += payload_size;
- offset = non_null_align.forward(offset);
- const non_null_offset = offset;
-
- const fields: [2]*llvm.DIType = .{
- dib.createMemberType(
- fwd_decl.toScope(),
- "data",
- di_file,
- line,
- payload_size * 8, // size in bits
- payload_align.toByteUnits(0) * 8, // align in bits
- 0, // offset in bits
- 0, // flags
- try o.lowerDebugType(child_ty, resolve),
- ),
- dib.createMemberType(
- fwd_decl.toScope(),
- "some",
- di_file,
- line,
- non_null_size * 8, // size in bits
- non_null_align.toByteUnits(0) * 8, // align in bits
- non_null_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(non_null_ty, resolve),
- ),
- };
+ const debug_some_type = try o.builder.debugMemberType(
+ try o.builder.string("some"),
+ Builder.Metadata.none,
+ debug_fwd_ref,
+ 0,
+ try o.lowerDebugType(non_null_ty),
+ non_null_size * 8,
+ non_null_align.toByteUnits(0) * 8,
+ non_null_offset * 8,
+ );
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- di_file,
- line,
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- &fields,
- fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ const debug_optional_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(&.{
+ debug_data_type,
+ debug_some_type,
+ }),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_optional_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_optional_type;
+
+ return debug_optional_type;
},
.ErrorUnion => {
const payload_ty = ty.errorUnionPayload(mod);
if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
- const err_set_di_ty = try o.lowerDebugType(Type.anyerror, resolve);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(err_set_di_ty));
- return err_set_di_ty;
+ // TODO: Maybe remove?
+ const debug_error_union_type = try o.lowerDebugType(Type.anyerror);
+ try o.debug_type_map.put(gpa, ty, debug_error_union_type);
+ return debug_error_union_type;
}
+
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const di_file: ?*llvm.DIFile = null;
- const line = 0;
- const compile_unit_scope = o.di_compile_unit.?.toScope();
- const fwd_decl = opt_fwd_decl orelse blk: {
- const fwd_decl = dib.createReplaceableCompositeType(
- DW.TAG.structure_type,
- name.ptr,
- compile_unit_scope,
- di_file,
- line,
- );
- gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
- if (resolve == .fwd) return fwd_decl;
- break :blk fwd_decl;
- };
const error_size = Type.anyerror.abiSize(mod);
const error_align = Type.anyerror.abiAlignment(mod);
@@ -2417,59 +2324,55 @@ pub const Object = struct {
error_offset = error_align.forward(payload_size);
}
- var fields: [2]*llvm.DIType = undefined;
- fields[error_index] = dib.createMemberType(
- fwd_decl.toScope(),
- "tag",
- di_file,
- line,
- error_size * 8, // size in bits
- error_align.toByteUnits(0) * 8, // align in bits
- error_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(Type.anyerror, resolve),
+ const debug_fwd_ref = try o.builder.debugForwardReference();
+
+ var fields: [2]Builder.Metadata = undefined;
+ fields[error_index] = try o.builder.debugMemberType(
+ try o.builder.string("tag"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(Type.anyerror),
+ error_size * 8,
+ error_align.toByteUnits(0) * 8,
+ error_offset * 8,
);
- fields[payload_index] = dib.createMemberType(
- fwd_decl.toScope(),
- "value",
- di_file,
- line,
- payload_size * 8, // size in bits
- payload_align.toByteUnits(0) * 8, // align in bits
- payload_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(payload_ty, resolve),
+ fields[payload_index] = try o.builder.debugMemberType(
+ try o.builder.string("value"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(payload_ty),
+ payload_size * 8,
+ payload_align.toByteUnits(0) * 8,
+ payload_offset * 8,
);
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- di_file,
- line,
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- &fields,
- fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ const debug_error_union_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Sope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(&fields),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_error_union_type);
+
+ try o.debug_type_map.put(gpa, ty, debug_error_union_type);
+ return debug_error_union_type;
},
.ErrorSet => {
- // TODO make this a proper enum with all the error codes in it.
- // will need to consider how to take incremental compilation into account.
- const di_ty = dib.createBasicType("anyerror", 16, DW.ATE.unsigned);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
- return di_ty;
+ const debug_error_set = try o.builder.debugUnsignedType(
+ try o.builder.string("anyerror"),
+ 16,
+ );
+ try o.debug_type_map.put(gpa, ty, debug_error_set);
+ return debug_error_set;
},
.Struct => {
- const compile_unit_scope = o.di_compile_unit.?.toScope();
const name = try o.allocTypeName(ty);
defer gpa.free(name);
@@ -2477,40 +2380,28 @@ pub const Object = struct {
const backing_int_ty = struct_type.backingIntType(ip).*;
if (backing_int_ty != .none) {
const info = Type.fromInterned(backing_int_ty).intInfo(mod);
- const dwarf_encoding: c_uint = switch (info.signedness) {
- .signed => DW.ATE.signed,
- .unsigned => DW.ATE.unsigned,
+ const builder_name = try o.builder.string(name);
+ const debug_int_type = switch (info.signedness) {
+ .signed => try o.builder.debugSignedType(builder_name, ty.abiSize(mod) * 8),
+ .unsigned => try o.builder.debugUnsignedType(builder_name, ty.abiSize(mod) * 8),
};
- const di_bits = ty.abiSize(mod) * 8; // lldb cannot handle non-byte sized types
- const di_ty = dib.createBasicType(name, di_bits, dwarf_encoding);
- gop.value_ptr.* = AnnotatedDITypePtr.initFull(di_ty);
- return di_ty;
+ try o.debug_type_map.put(gpa, ty, debug_int_type);
+ return debug_int_type;
}
}
- const fwd_decl = opt_fwd_decl orelse blk: {
- const fwd_decl = dib.createReplaceableCompositeType(
- DW.TAG.structure_type,
- name.ptr,
- compile_unit_scope,
- null, // file
- 0, // line
- );
- gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
- if (resolve == .fwd) return fwd_decl;
- break :blk fwd_decl;
- };
-
switch (ip.indexToKey(ty.toIntern())) {
.anon_struct_type => |tuple| {
- var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
- defer di_fields.deinit(gpa);
+ var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};
+ defer fields.deinit(gpa);
- try di_fields.ensureUnusedCapacity(gpa, tuple.types.len);
+ try fields.ensureUnusedCapacity(gpa, tuple.types.len);
comptime assert(struct_layout_version == 2);
var offset: u64 = 0;
+ const debug_fwd_ref = try o.builder.debugForwardReference();
+
for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(mod)) continue;
@@ -2525,38 +2416,33 @@ pub const Object = struct {
try std.fmt.allocPrintZ(gpa, "{d}", .{i});
defer if (tuple.names.len == 0) gpa.free(field_name);
- try di_fields.append(gpa, dib.createMemberType(
- fwd_decl.toScope(),
- field_name,
- null, // file
- 0, // line
- field_size * 8, // size in bits
- field_align.toByteUnits(0) * 8, // align in bits
- field_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(Type.fromInterned(field_ty), resolve),
+ fields.appendAssumeCapacity(try o.builder.debugMemberType(
+ try o.builder.string(field_name),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0,
+ try o.lowerDebugType(Type.fromInterned(field_ty)),
+ field_size * 8,
+ field_align.toByteUnits(0) * 8,
+ field_offset * 8,
));
}
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- null, // file
- 0, // line
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- di_fields.items.ptr,
- @intCast(di_fields.items.len),
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ const debug_struct_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(fields.items),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type);
+
+ try o.debug_type_map.put(gpa, ty, debug_struct_type);
+ return debug_struct_type;
},
.struct_type => |struct_type| {
if (!struct_type.haveFieldTypes(ip)) {
@@ -2568,12 +2454,9 @@ pub const Object = struct {
// rather than changing the frontend to unnecessarily resolve the
// struct field types.
const owner_decl_index = ty.getOwnerDecl(mod);
- const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
- dib.replaceTemporary(fwd_decl, struct_di_ty);
- // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(struct_di_ty));
- return struct_di_ty;
+ const debug_struct_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
+ try o.debug_type_map.put(gpa, ty, debug_struct_type);
+ return debug_struct_type;
}
},
else => {},
@@ -2581,20 +2464,22 @@ pub const Object = struct {
if (!ty.hasRuntimeBitsIgnoreComptime(mod)) {
const owner_decl_index = ty.getOwnerDecl(mod);
- const struct_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
- dib.replaceTemporary(fwd_decl, struct_di_ty);
- // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(struct_di_ty));
- return struct_di_ty;
+ const debug_struct_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
+ try o.debug_type_map.put(gpa, ty, debug_struct_type);
+ return debug_struct_type;
}
const struct_type = mod.typeToStruct(ty).?;
- var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
- defer di_fields.deinit(gpa);
+ var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};
+ defer fields.deinit(gpa);
+
+ try fields.ensureUnusedCapacity(gpa, struct_type.field_types.len);
+
+ const debug_fwd_ref = try o.builder.debugForwardReference();
- try di_fields.ensureUnusedCapacity(gpa, struct_type.field_types.len);
+ // Set as forward reference while the type is lowered in case it references itself
+ try o.debug_type_map.put(gpa, ty, debug_fwd_ref);
comptime assert(struct_layout_version == 2);
var it = struct_type.iterateRuntimeOrder(ip);
@@ -2612,103 +2497,88 @@ pub const Object = struct {
const field_name = struct_type.fieldName(ip, field_index).unwrap() orelse
try ip.getOrPutStringFmt(gpa, "{d}", .{field_index});
- const field_di_ty = try o.lowerDebugType(field_ty, resolve);
-
- try di_fields.append(gpa, dib.createMemberType(
- fwd_decl.toScope(),
- ip.stringToSlice(field_name),
- null, // file
- 0, // line
- field_size * 8, // size in bits
- field_align.toByteUnits(0) * 8, // align in bits
- field_offset * 8, // offset in bits
- 0, // flags
- field_di_ty,
+ fields.appendAssumeCapacity(try o.builder.debugMemberType(
+ try o.builder.string(ip.stringToSlice(field_name)),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(field_ty),
+ field_size * 8,
+ field_align.toByteUnits(0) * 8,
+ field_offset * 8,
));
}
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- null, // file
- 0, // line
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- di_fields.items.ptr,
- @intCast(di_fields.items.len),
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ const debug_struct_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(fields.items),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_struct_type;
+
+ return debug_struct_type;
},
.Union => {
- const compile_unit_scope = o.di_compile_unit.?.toScope();
const owner_decl_index = ty.getOwnerDecl(mod);
const name = try o.allocTypeName(ty);
defer gpa.free(name);
- const fwd_decl = opt_fwd_decl orelse blk: {
- const fwd_decl = dib.createReplaceableCompositeType(
- DW.TAG.structure_type,
- name.ptr,
- o.di_compile_unit.?.toScope(),
- null, // file
- 0, // line
- );
- gop.value_ptr.* = AnnotatedDITypePtr.initFwd(fwd_decl);
- if (resolve == .fwd) return fwd_decl;
- break :blk fwd_decl;
- };
-
const union_type = ip.indexToKey(ty.toIntern()).union_type;
if (!union_type.haveFieldTypes(ip) or !ty.hasRuntimeBitsIgnoreComptime(mod)) {
- const union_di_ty = try o.makeEmptyNamespaceDIType(owner_decl_index);
- dib.replaceTemporary(fwd_decl, union_di_ty);
- // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(union_di_ty));
- return union_di_ty;
+ const debug_union_type = try o.makeEmptyNamespaceDebugType(owner_decl_index);
+ try o.debug_type_map.put(gpa, ty, debug_union_type);
+ return debug_union_type;
}
const union_obj = ip.loadUnionType(union_type);
const layout = mod.getUnionLayout(union_obj);
+ const debug_fwd_ref = try o.builder.debugForwardReference();
+
+ // Set as forward reference while the type is lowered in case it references itself
+ try o.debug_type_map.put(gpa, ty, debug_fwd_ref);
+
if (layout.payload_size == 0) {
- const tag_di_ty = try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), resolve);
- const di_fields = [_]*llvm.DIType{tag_di_ty};
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- null, // file
- 0, // line
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- &di_fields,
- di_fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ const debug_union_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(
+ &.{try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty))},
+ ),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` via `makeEmptyNamespaceDIType`
- // means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_union_type;
+
+ return debug_union_type;
}
- var di_fields: std.ArrayListUnmanaged(*llvm.DIType) = .{};
- defer di_fields.deinit(gpa);
+ var fields: std.ArrayListUnmanaged(Builder.Metadata) = .{};
+ defer fields.deinit(gpa);
- try di_fields.ensureUnusedCapacity(gpa, union_obj.field_names.len);
+ try fields.ensureUnusedCapacity(gpa, union_obj.field_names.len);
+
+ const debug_union_fwd_ref = if (layout.tag_size == 0)
+ debug_fwd_ref
+ else
+ try o.builder.debugForwardReference();
for (0..union_obj.field_names.len) |field_index| {
const field_ty = union_obj.field_types.get(ip)[field_index];
@@ -2717,18 +2587,16 @@ pub const Object = struct {
const field_size = Type.fromInterned(field_ty).abiSize(mod);
const field_align = mod.unionFieldNormalAlignment(union_obj, @intCast(field_index));
- const field_di_ty = try o.lowerDebugType(Type.fromInterned(field_ty), resolve);
const field_name = union_obj.field_names.get(ip)[field_index];
- di_fields.appendAssumeCapacity(dib.createMemberType(
- fwd_decl.toScope(),
- ip.stringToSlice(field_name),
- null, // file
- 0, // line
- field_size * 8, // size in bits
- field_align.toByteUnits(0) * 8, // align in bits
- 0, // offset in bits
- 0, // flags
- field_di_ty,
+ fields.appendAssumeCapacity(try o.builder.debugMemberType(
+ try o.builder.string(ip.stringToSlice(field_name)),
+ Builder.Metadata.none, // File
+ debug_union_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(Type.fromInterned(field_ty)),
+ field_size * 8,
+ field_align.toByteUnits(0) * 8,
+ 0, // Offset
));
}
@@ -2739,25 +2607,25 @@ pub const Object = struct {
break :name union_name_buf.?;
};
- const union_di_ty = dib.createUnionType(
- compile_unit_scope,
- union_name.ptr,
- null, // file
- 0, // line
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- di_fields.items.ptr,
- @intCast(di_fields.items.len),
- 0, // run time lang
- "", // unique id
+ const debug_union_type = try o.builder.debugUnionType(
+ try o.builder.string(union_name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(fields.items),
);
+ o.builder.debugForwardReferenceSetType(debug_union_fwd_ref, debug_union_type);
+
if (layout.tag_size == 0) {
- dib.replaceTemporary(fwd_decl, union_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(union_di_ty));
- return union_di_ty;
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_union_type;
+
+ return debug_union_type;
}
var tag_offset: u64 = undefined;
@@ -2770,81 +2638,80 @@ pub const Object = struct {
tag_offset = layout.tag_align.forward(layout.payload_size);
}
- const tag_di = dib.createMemberType(
- fwd_decl.toScope(),
- "tag",
- null, // file
- 0, // line
+ const debug_tag_type = try o.builder.debugMemberType(
+ try o.builder.string("tag"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty)),
layout.tag_size * 8,
layout.tag_align.toByteUnits(0) * 8,
- tag_offset * 8, // offset in bits
- 0, // flags
- try o.lowerDebugType(Type.fromInterned(union_obj.enum_tag_ty), resolve),
+ tag_offset * 8,
);
- const payload_di = dib.createMemberType(
- fwd_decl.toScope(),
- "payload",
- null, // file
- 0, // line
- layout.payload_size * 8, // size in bits
+ const debug_payload_type = try o.builder.debugMemberType(
+ try o.builder.string("payload"),
+ Builder.Metadata.none, // File
+ debug_fwd_ref,
+ 0, // Line
+ debug_union_type,
+ layout.payload_size * 8,
layout.payload_align.toByteUnits(0) * 8,
- payload_offset * 8, // offset in bits
- 0, // flags
- union_di_ty,
+ payload_offset * 8,
);
- const full_di_fields: [2]*llvm.DIType =
+ const full_fields: [2]Builder.Metadata =
if (layout.tag_align.compare(.gte, layout.payload_align))
- .{ tag_di, payload_di }
+ .{ debug_tag_type, debug_payload_type }
else
- .{ payload_di, tag_di };
-
- const full_di_ty = dib.createStructType(
- compile_unit_scope,
- name.ptr,
- null, // file
- 0, // line
- ty.abiSize(mod) * 8, // size in bits
- ty.abiAlignment(mod).toByteUnits(0) * 8, // align in bits
- 0, // flags
- null, // derived from
- &full_di_fields,
- full_di_fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ .{ debug_payload_type, debug_tag_type };
+
+ const debug_tagged_union_type = try o.builder.debugStructType(
+ try o.builder.string(name),
+ Builder.Metadata.none, // File
+ o.debug_compile_unit, // Scope
+ 0, // Line
+ Builder.Metadata.none, // Underlying type
+ ty.abiSize(mod) * 8,
+ ty.abiAlignment(mod).toByteUnits(0) * 8,
+ try o.builder.debugTuple(&full_fields),
);
- dib.replaceTemporary(fwd_decl, full_di_ty);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(full_di_ty));
- return full_di_ty;
+
+ o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_tagged_union_type);
+
+ // Set to real type now that it has been lowered fully
+ const map_ptr = o.debug_type_map.getPtr(ty) orelse unreachable;
+ map_ptr.* = debug_tagged_union_type;
+
+ return debug_tagged_union_type;
},
.Fn => {
const fn_info = mod.typeToFunc(ty).?;
- var param_di_types = std.ArrayList(*llvm.DIType).init(gpa);
- defer param_di_types.deinit();
+ var debug_param_types = std.ArrayList(Builder.Metadata).init(gpa);
+ defer debug_param_types.deinit();
+
+ try debug_param_types.ensureUnusedCapacity(3 + fn_info.param_types.len);
// Return type goes first.
if (Type.fromInterned(fn_info.return_type).hasRuntimeBitsIgnoreComptime(mod)) {
const sret = firstParamSRet(fn_info, mod);
- const di_ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);
- try param_di_types.append(try o.lowerDebugType(di_ret_ty, resolve));
+ const ret_ty = if (sret) Type.void else Type.fromInterned(fn_info.return_type);
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ret_ty));
if (sret) {
const ptr_ty = try mod.singleMutPtrType(Type.fromInterned(fn_info.return_type));
- try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty));
}
} else {
- try param_di_types.append(try o.lowerDebugType(Type.void, resolve));
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void));
}
if (Type.fromInterned(fn_info.return_type).isError(mod) and
o.module.comp.config.any_error_tracing)
{
const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType());
- try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty));
}
for (0..fn_info.param_types.len) |i| {
@@ -2853,20 +2720,18 @@ pub const Object = struct {
if (isByRef(param_ty, mod)) {
const ptr_ty = try mod.singleMutPtrType(param_ty);
- try param_di_types.append(try o.lowerDebugType(ptr_ty, resolve));
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty));
} else {
- try param_di_types.append(try o.lowerDebugType(param_ty, resolve));
+ debug_param_types.appendAssumeCapacity(try o.lowerDebugType(param_ty));
}
}
- const fn_di_ty = dib.createSubroutineType(
- param_di_types.items.ptr,
- @intCast(param_di_types.items.len),
- 0,
+ const debug_function_type = try o.builder.debugSubroutineType(
+ try o.builder.debugTuple(debug_param_types.items),
);
- // The recursive call to `lowerDebugType` means we can't use `gop` anymore.
- try o.di_type_map.put(gpa, ty.toIntern(), AnnotatedDITypePtr.initFull(fn_di_ty));
- return fn_di_ty;
+
+ try o.debug_type_map.put(gpa, ty, debug_function_type);
+ return debug_function_type;
},
.ComptimeInt => unreachable,
.ComptimeFloat => unreachable,
@@ -2880,39 +2745,30 @@ pub const Object = struct {
}
}
- fn namespaceToDebugScope(o: *Object, namespace_index: InternPool.NamespaceIndex) !*llvm.DIScope {
+ fn namespaceToDebugScope(o: *Object, namespace_index: InternPool.NamespaceIndex) !Builder.Metadata {
const mod = o.module;
const namespace = mod.namespacePtr(namespace_index);
- if (namespace.parent == .none) {
- const di_file = try o.getDIFile(o.gpa, namespace.file_scope);
- return di_file.toScope();
- }
- const di_type = try o.lowerDebugType(namespace.ty, .fwd);
- return di_type.toScope();
+ if (namespace.parent == .none) return try o.getDebugFile(namespace.file_scope);
+
+ const gop = try o.debug_unresolved_namespace_scopes.getOrPut(o.gpa, namespace_index);
+
+ if (!gop.found_existing) gop.value_ptr.* = try o.builder.debugForwardReference();
+
+ return gop.value_ptr.*;
}
- /// This is to be used instead of void for debug info types, to avoid tripping
- /// Assertion `!isa<DIType>(Scope) && "shouldn't make a namespace scope for a type"'
- /// when targeting CodeView (Windows).
- fn makeEmptyNamespaceDIType(o: *Object, decl_index: InternPool.DeclIndex) !*llvm.DIType {
+ fn makeEmptyNamespaceDebugType(o: *Object, decl_index: InternPool.DeclIndex) !Builder.Metadata {
const mod = o.module;
const decl = mod.declPtr(decl_index);
- const fields: [0]*llvm.DIType = .{};
- const di_scope = try o.namespaceToDebugScope(decl.src_namespace);
- return o.di_builder.?.createStructType(
- di_scope,
- mod.intern_pool.stringToSlice(decl.name), // TODO use fully qualified name
- try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope),
+ return o.builder.debugStructType(
+ try o.builder.string(mod.intern_pool.stringToSlice(decl.name)), // TODO use fully qualified name
+ try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope),
+ try o.namespaceToDebugScope(decl.src_namespace),
decl.src_line + 1,
- 0, // size in bits
- 0, // align in bits
- 0, // flags
- null, // derived from
- undefined, // TODO should be able to pass &fields,
- fields.len,
- 0, // run time lang
- null, // vtable holder
- "", // unique id
+ Builder.Metadata.none,
+ 0,
+ 0,
+ .none,
);
}
@@ -4822,26 +4678,32 @@ pub const DeclGen = struct {
else => try o.lowerValue(init_val),
}, &o.builder);
- if (o.di_builder) |dib| {
- const di_file =
- try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope);
-
- const line_number = decl.src_line + 1;
- const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
- const di_global = dib.createGlobalVariableExpression(
- di_file.toScope(),
- mod.intern_pool.stringToSlice(decl.name),
- variable_index.name(&o.builder).slice(&o.builder).?,
- di_file,
- line_number,
- try o.lowerDebugType(decl.ty, .full),
- is_internal_linkage,
- );
+ const line_number = decl.src_line + 1;
+ const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
- try o.di_map.put(o.gpa, dg.decl, di_global.getVariable().toNode());
- if (!is_internal_linkage or decl.isExtern(mod))
- variable_index.toLlvm(&o.builder).attachMetaData(di_global);
- }
+ if (dg.object.builder.strip) return;
+
+ const debug_file = try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope);
+
+ const debug_global_var = try o.builder.debugGlobalVar(
+ try o.builder.string(mod.intern_pool.stringToSlice(decl.name)), // Name
+ variable_index.name(&o.builder), // Linkage name
+ debug_file, // File
+ debug_file, // Scope
+ line_number,
+ try o.lowerDebugType(decl.ty),
+ variable_index,
+ .{ .local = is_internal_linkage },
+ );
+
+ const debug_expression = try o.builder.debugExpression(&.{});
+
+ const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
+ debug_global_var,
+ debug_expression,
+ );
+
+ try o.debug_globals.append(o.gpa, debug_global_var_expression);
}
}
};
@@ -4852,19 +4714,23 @@ pub const FuncGen = struct {
air: Air,
liveness: Liveness,
wip: Builder.WipFunction,
- di_scope: ?if (build_options.have_llvm) *llvm.DIScope else noreturn,
- di_file: ?if (build_options.have_llvm) *llvm.DIFile else noreturn,
+
+ file: Builder.Metadata,
+ subprogram: Builder.Metadata,
+ current_scope: Builder.Metadata,
+
+ inlined: std.ArrayListUnmanaged(struct {
+ base_line: u32,
+ location: Builder.Metadata,
+ scope: Builder.Metadata,
+ }) = .{},
+
+ scope_stack: std.ArrayListUnmanaged(Builder.Metadata) = .{},
+
base_line: u32,
prev_dbg_line: c_uint,
prev_dbg_column: c_uint,
- /// Stack of locations where a call was inlined.
- dbg_inlined: std.ArrayListUnmanaged(if (build_options.have_llvm) DbgState else void) = .{},
-
- /// Stack of `DILexicalBlock`s. dbg_block instructions cannot happend accross
- /// dbg_inline instructions so no special handling there is required.
- dbg_block_stack: std.ArrayListUnmanaged(if (build_options.have_llvm) *llvm.DIScope else void) = .{},
-
/// This stores the LLVM values used in a function, such that they can be referred to
/// in other instructions. This table is cleared before every function is generated.
func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, Builder.Value),
@@ -4905,8 +4771,8 @@ pub const FuncGen = struct {
fn deinit(self: *FuncGen) void {
self.wip.deinit();
- self.dbg_inlined.deinit(self.gpa);
- self.dbg_block_stack.deinit(self.gpa);
+ self.scope_stack.deinit(self.gpa);
+ self.inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
}
@@ -5515,9 +5381,6 @@ pub const FuncGen = struct {
// a different LLVM type than the usual one. We solve this here at the callsite
// by using our canonical type, then loading it if necessary.
const alignment = return_type.abiAlignment(mod).toLlvm();
- if (o.builder.useLibLlvm())
- assert(o.target_data.abiSizeOfType(abi_ret_ty.toLlvm(&o.builder)) >=
- o.target_data.abiSizeOfType(llvm_ret_ty.toLlvm(&o.builder)));
const rp = try self.buildAlloca(abi_ret_ty, alignment);
_ = try self.wip.store(.normal, call, rp, alignment);
return if (isByRef(return_type, mod))
@@ -6675,42 +6538,48 @@ pub const FuncGen = struct {
}
fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
- const di_scope = self.di_scope orelse return .none;
+ if (self.wip.builder.strip) return .none;
const dbg_stmt = self.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
self.prev_dbg_line = @intCast(self.base_line + dbg_stmt.line + 1);
self.prev_dbg_column = @intCast(dbg_stmt.column + 1);
- const inlined_at = if (self.dbg_inlined.items.len > 0)
- self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
+ const inlined_at = if (self.inlined.items.len > 0)
+ self.inlined.items[self.inlined.items.len - 1].location
else
- null;
- self.wip.llvm.builder.setCurrentDebugLocation(
- self.prev_dbg_line,
- self.prev_dbg_column,
- di_scope,
- inlined_at,
- );
+ Builder.Metadata.none;
+
+ self.wip.current_debug_location = .{
+ .line = self.prev_dbg_line,
+ .column = self.prev_dbg_column,
+ .scope = self.current_scope,
+ .inlined_at = inlined_at,
+ };
+
return .none;
}
fn airDbgInlineBegin(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ if (self.wip.builder.strip or true) return .none;
const o = self.dg.object;
- const dib = o.di_builder orelse return .none;
- const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
-
const zcu = o.module;
+
+ const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const func = zcu.funcInfo(ty_fn.func);
const decl_index = func.owner_decl;
const decl = zcu.declPtr(decl_index);
const namespace = zcu.namespacePtr(decl.src_namespace);
const owner_mod = namespace.file_scope.mod;
- const di_file = try o.getDIFile(self.gpa, zcu.namespacePtr(decl.src_namespace).file_scope);
- self.di_file = di_file;
- const line_number = decl.src_line + 1;
- const cur_debug_location = self.wip.llvm.builder.getCurrentDebugLocation2();
- try self.dbg_inlined.append(self.gpa, .{
- .loc = @ptrCast(cur_debug_location),
- .scope = self.di_scope.?,
+ self.file = try o.getDebugFile(namespace.file_scope);
+
+ const line_number = decl.src_line + 1;
+ try self.inlined.append(self.gpa, .{
+ .location = if (self.wip.current_debug_location) |location| try self.wip.builder.debugLocation(
+ location.scope,
+ location.line,
+ location.column,
+ location.inlined_at,
+ ) else .none,
+ .scope = self.current_scope,
.base_line = self.base_line,
});
@@ -6721,91 +6590,108 @@ pub const FuncGen = struct {
.param_types = &.{},
.return_type = .void_type,
});
- const fn_di_ty = try o.lowerDebugType(fn_ty, .full);
- const subprogram = dib.createFunction(
- di_file.toScope(),
- zcu.intern_pool.stringToSlice(decl.name),
- zcu.intern_pool.stringToSlice(fqn),
- di_file,
+
+ const subprogram = try o.builder.debugSubprogram(
+ self.file,
+ try o.builder.string(zcu.intern_pool.stringToSlice(decl.name)),
+ try o.builder.string(zcu.intern_pool.stringToSlice(fqn)),
line_number,
- fn_di_ty,
- is_internal_linkage,
- true, // is definition
- line_number + func.lbrace_line, // scope line
- llvm.DIFlags.StaticMember,
- owner_mod.optimize_mode != .Debug,
- null, // decl_subprogram
+ line_number + func.lbrace_line,
+ try o.lowerDebugType(fn_ty),
+ .{
+ .optimized = owner_mod.optimize_mode != .Debug,
+ .local = is_internal_linkage,
+ .definition = true,
+ .debug_info_flags = llvm.DIFlags.StaticMember,
+ },
+ o.debug_compile_unit,
);
- const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
- self.di_scope = lexical_block.toScope();
+ const lexical_block = try o.builder.debugLexicalBlock(
+ subprogram,
+ self.file,
+ line_number,
+ 1,
+ );
+ self.current_scope = lexical_block;
self.base_line = decl.src_line;
return .none;
}
- fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ fn airDbgInlineEnd(self: *FuncGen, inst: Air.Inst.Index) Allocator.Error!Builder.Value {
+ if (self.wip.builder.strip or true) return .none;
const o = self.dg.object;
- if (o.di_builder == null) return .none;
+
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = o.module;
const decl = mod.funcOwnerDeclPtr(ty_fn.func);
- const di_file = try o.getDIFile(self.gpa, mod.namespacePtr(decl.src_namespace).file_scope);
- self.di_file = di_file;
- const old = self.dbg_inlined.pop();
- self.di_scope = old.scope;
+ self.file = try o.getDebugFile(mod.namespacePtr(decl.src_namespace).file_scope);
+
+ const old = self.inlined.pop();
+ self.current_scope = old.scope;
self.base_line = old.base_line;
return .none;
}
- fn airDbgBlockBegin(self: *FuncGen) !Builder.Value {
+ fn airDbgBlockBegin(self: *FuncGen) Allocator.Error!Builder.Value {
+ if (self.wip.builder.strip) return .none;
const o = self.dg.object;
- const dib = o.di_builder orelse return .none;
- const old_scope = self.di_scope.?;
- try self.dbg_block_stack.append(self.gpa, old_scope);
- const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
- self.di_scope = lexical_block.toScope();
+
+ try self.scope_stack.append(self.gpa, self.current_scope);
+
+ const old = self.current_scope;
+ self.current_scope = try o.builder.debugLexicalBlock(
+ self.file,
+ old,
+ self.prev_dbg_line,
+ self.prev_dbg_column,
+ );
return .none;
}
fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
- const o = self.dg.object;
- if (o.di_builder == null) return .none;
- self.di_scope = self.dbg_block_stack.pop();
+ if (self.wip.builder.strip) return .none;
+ self.current_scope = self.scope_stack.pop();
return .none;
}
fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ if (self.wip.builder.strip) return .none;
const o = self.dg.object;
const mod = o.module;
- const dib = o.di_builder orelse return .none;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
const name = self.air.nullTerminatedString(pl_op.payload);
const ptr_ty = self.typeOf(pl_op.operand);
- const di_local_var = dib.createAutoVariable(
- self.di_scope.?,
- name.ptr,
- self.di_file.?,
+ const debug_local_var = try o.builder.debugLocalVar(
+ try o.builder.string(name),
+ self.file,
+ self.current_scope,
self.prev_dbg_line,
- try o.lowerDebugType(ptr_ty.childType(mod), .full),
- true, // always preserve
- 0, // flags
+ try o.lowerDebugType(ptr_ty.childType(mod)),
);
- const inlined_at = if (self.dbg_inlined.items.len > 0)
- self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
- else
- null;
- const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
- const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
- _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
+
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.declare",
+ &.{},
+ &.{
+ (try self.wip.debugValue(operand)).toValue(),
+ debug_local_var.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
+
return .none;
}
fn airDbgVarVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ if (self.wip.builder.strip) return .none;
const o = self.dg.object;
- const dib = o.di_builder orelse return .none;
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = try self.resolveInst(pl_op.operand);
const operand_ty = self.typeOf(pl_op.operand);
@@ -6813,32 +6699,58 @@ pub const FuncGen = struct {
if (needDbgVarWorkaround(o)) return .none;
- const di_local_var = dib.createAutoVariable(
- self.di_scope.?,
- name.ptr,
- self.di_file.?,
+ const debug_local_var = try o.builder.debugLocalVar(
+ try o.builder.string(name),
+ self.file,
+ self.current_scope,
self.prev_dbg_line,
- try o.lowerDebugType(operand_ty, .full),
- true, // always preserve
- 0, // flags
+ try o.lowerDebugType(operand_ty),
);
- const inlined_at = if (self.dbg_inlined.items.len > 0)
- self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
- else
- null;
- const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
- const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
+
const zcu = o.module;
const owner_mod = self.dg.ownerModule();
if (isByRef(operand_ty, zcu)) {
- _ = dib.insertDeclareAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.declare",
+ &.{},
+ &.{
+ (try self.wip.debugValue(operand)).toValue(),
+ debug_local_var.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
} else if (owner_mod.optimize_mode == .Debug) {
const alignment = operand_ty.abiAlignment(zcu).toLlvm();
const alloca = try self.buildAlloca(operand.typeOfWip(&self.wip), alignment);
_ = try self.wip.store(.normal, operand, alloca, alignment);
- _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.declare",
+ &.{},
+ &.{
+ (try self.wip.debugValue(alloca)).toValue(),
+ debug_local_var.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
} else {
- _ = dib.insertDbgValueIntrinsicAtEnd(operand.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.value",
+ &.{},
+ &.{
+ (try self.wip.debugValue(operand)).toValue(),
+ debug_local_var.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
}
return .none;
}
@@ -8860,41 +8772,80 @@ pub const FuncGen = struct {
const arg_val = self.args[self.arg_index];
self.arg_index += 1;
+ if (self.wip.builder.strip) return arg_val;
+
const inst_ty = self.typeOfIndex(inst);
- if (o.di_builder) |dib| {
- if (needDbgVarWorkaround(o)) return arg_val;
-
- const src_index = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.src_index;
- const func_index = self.dg.decl.getOwnedFunctionIndex();
- const func = mod.funcInfo(func_index);
- const lbrace_line = mod.declPtr(func.owner_decl).src_line + func.lbrace_line + 1;
- const lbrace_col = func.lbrace_column + 1;
- const di_local_var = dib.createParameterVariable(
- self.di_scope.?,
- mod.getParamName(func_index, src_index).ptr, // TODO test 0 bit args
- self.di_file.?,
- lbrace_line,
- try o.lowerDebugType(inst_ty, .full),
- true, // always preserve
- 0, // flags
- @intCast(self.arg_index), // includes +1 because 0 is return type
- );
+ if (needDbgVarWorkaround(o)) return arg_val;
+
+ const src_index = self.air.instructions.items(.data)[@intFromEnum(inst)].arg.src_index;
+ const func_index = self.dg.decl.getOwnedFunctionIndex();
+ const func = mod.funcInfo(func_index);
+ const lbrace_line = mod.declPtr(func.owner_decl).src_line + func.lbrace_line + 1;
+ const lbrace_col = func.lbrace_column + 1;
+
+ const debug_parameter = try o.builder.debugParameter(
+ try o.builder.string(mod.getParamName(func_index, src_index)),
+ self.file,
+ self.current_scope,
+ lbrace_line,
+ try o.lowerDebugType(inst_ty),
+ @intCast(self.arg_index),
+ );
- const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
- const insert_block = self.wip.cursor.block.toLlvm(&self.wip);
- const owner_mod = self.dg.ownerModule();
- if (isByRef(inst_ty, mod)) {
- _ = dib.insertDeclareAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
- } else if (owner_mod.optimize_mode == .Debug) {
- const alignment = inst_ty.abiAlignment(mod).toLlvm();
- const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
- _ = try self.wip.store(.normal, arg_val, alloca, alignment);
- _ = dib.insertDeclareAtEnd(alloca.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
- } else {
- _ = dib.insertDbgValueIntrinsicAtEnd(arg_val.toLlvm(&self.wip), di_local_var, debug_loc, insert_block);
- }
+ const old_location = self.wip.current_debug_location;
+ self.wip.current_debug_location = .{
+ .line = lbrace_line,
+ .column = lbrace_col,
+ .scope = self.current_scope,
+ .inlined_at = Builder.Metadata.none,
+ };
+
+ const owner_mod = self.dg.ownerModule();
+ if (isByRef(inst_ty, mod)) {
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.declare",
+ &.{},
+ &.{
+ (try self.wip.debugValue(arg_val)).toValue(),
+ debug_parameter.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
+ } else if (owner_mod.optimize_mode == .Debug) {
+ const alignment = inst_ty.abiAlignment(mod).toLlvm();
+ const alloca = try self.buildAlloca(arg_val.typeOfWip(&self.wip), alignment);
+ _ = try self.wip.store(.normal, arg_val, alloca, alignment);
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.declare",
+ &.{},
+ &.{
+ (try self.wip.debugValue(alloca)).toValue(),
+ debug_parameter.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
+ } else {
+ _ = try self.wip.callIntrinsic(
+ .normal,
+ .none,
+ .@"dbg.value",
+ &.{},
+ &.{
+ (try self.wip.debugValue(arg_val)).toValue(),
+ debug_parameter.toValue(),
+ (try o.builder.debugExpression(&.{})).toValue(),
+ },
+ "",
+ );
}
+ self.wip.current_debug_location = old_location;
return arg_val;
}
@@ -8932,7 +8883,7 @@ pub const FuncGen = struct {
alignment: Builder.Alignment,
) Allocator.Error!Builder.Value {
const target = self.dg.object.module.getTarget();
- return buildAllocaInner(&self.wip, self.di_scope != null, llvm_ty, alignment, target);
+ return buildAllocaInner(&self.wip, llvm_ty, alignment, target);
}
// Workaround for https://github.com/ziglang/zig/issues/16392
@@ -11716,45 +11667,6 @@ const struct_layout_version = 2;
// https://github.com/llvm/llvm-project/issues/56585/ is fixed
const optional_layout_version = 3;
-/// We use the least significant bit of the pointer address to tell us
-/// whether the type is fully resolved. Types that are only fwd declared
-/// have the LSB flipped to a 1.
-const AnnotatedDITypePtr = enum(usize) {
- null,
- _,
-
- fn initFwd(di_type: *llvm.DIType) AnnotatedDITypePtr {
- const addr = @intFromPtr(di_type);
- assert(@as(u1, @truncate(addr)) == 0);
- return @enumFromInt(addr | 1);
- }
-
- fn initFull(di_type: *llvm.DIType) AnnotatedDITypePtr {
- const addr = @intFromPtr(di_type);
- return @enumFromInt(addr);
- }
-
- fn init(di_type: *llvm.DIType, resolve: Object.DebugResolveStatus) AnnotatedDITypePtr {
- const addr = @intFromPtr(di_type);
- const bit = @intFromBool(resolve == .fwd);
- return @enumFromInt(addr | bit);
- }
-
- fn toDIType(self: AnnotatedDITypePtr) *llvm.DIType {
- switch (self) {
- .null => unreachable,
- _ => return @ptrFromInt(@intFromEnum(self) & ~@as(usize, 1)),
- }
- }
-
- fn isFwdOnly(self: AnnotatedDITypePtr) bool {
- switch (self) {
- .null => unreachable,
- _ => return @as(u1, @truncate(@intFromEnum(self))) != 0,
- }
- }
-};
-
const lt_errors_fn_name = "__zig_lt_errors_len";
/// Without this workaround, LLVM crashes with "unknown codeview register H1"
@@ -11778,7 +11690,6 @@ fn compilerRtIntBits(bits: u16) u16 {
fn buildAllocaInner(
wip: *Builder.WipFunction,
- di_scope_non_null: bool,
llvm_ty: Builder.Type,
alignment: Builder.Alignment,
target: std.Target,
@@ -11787,19 +11698,15 @@ fn buildAllocaInner(
const alloca = blk: {
const prev_cursor = wip.cursor;
- const prev_debug_location = if (wip.builder.useLibLlvm())
- wip.llvm.builder.getCurrentDebugLocation2()
- else
- undefined;
+ const prev_debug_location = wip.current_debug_location;
defer {
wip.cursor = prev_cursor;
if (wip.cursor.block == .entry) wip.cursor.instruction += 1;
- if (wip.builder.useLibLlvm() and di_scope_non_null)
- wip.llvm.builder.setCurrentDebugLocation2(prev_debug_location);
+ wip.current_debug_location = prev_debug_location;
}
wip.cursor = .{ .block = .entry };
- if (wip.builder.useLibLlvm()) wip.llvm.builder.clearCurrentDebugLocation();
+ wip.current_debug_location = null;
break :blk try wip.alloca(.normal, llvm_ty, .none, alignment, address_space, "");
};