aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig12
-rw-r--r--src/codegen/llvm.zig95
-rw-r--r--src/codegen/llvm/bindings.zig8
3 files changed, 104 insertions, 11 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 05ceb30379..358e7354dd 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1726,6 +1726,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.dbg_var_val,
=> try airDbgVar(f, inst),
+ .dbg_inline_begin,
+ .dbg_inline_end,
+ => try airDbgInline(f, inst),
+
.call => try airCall(f, inst, .auto),
.call_always_tail => try airCall(f, inst, .always_tail),
.call_never_tail => try airCall(f, inst, .never_tail),
@@ -2660,6 +2664,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue.none;
}
+fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
+ const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
+ const writer = f.object.writer();
+ const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
+ try writer.print("/* dbg func:{s} */\n", .{function.owner_decl.name});
+ return CValue.none;
+}
+
fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const name = f.air.nullTerminatedString(pl_op.payload);
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index c4b381f6d6..9321b26e15 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -620,7 +620,8 @@ pub const Object = struct {
llvm_func.fnSetSubprogram(subprogram);
- di_scope = subprogram.toScope();
+ const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file.?, line_number, 1);
+ di_scope = lexical_block.toScope();
}
var fg: FuncGen = .{
@@ -639,6 +640,7 @@ pub const Object = struct {
.single_threaded = module.comp.bin_file.options.single_threaded,
.di_scope = di_scope,
.di_file = di_file,
+ .base_line = dg.decl.src_line,
.prev_dbg_line = 0,
.prev_dbg_column = 0,
};
@@ -1754,11 +1756,14 @@ pub const DeclGen = struct {
/// Note that this can be called before the function's semantic analysis has
/// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value {
+ return dg.resolveLlvmFunctionExtra(decl, decl.ty);
+ }
+
+ fn resolveLlvmFunctionExtra(dg: *DeclGen, decl: *Module.Decl, zig_fn_type: Type) !*const llvm.Value {
const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl);
if (gop.found_existing) return gop.value_ptr.*;
assert(decl.has_tv);
- const zig_fn_type = decl.ty;
const fn_info = zig_fn_type.fnInfo();
const target = dg.module.getTarget();
const sret = firstParamSRet(fn_info, target);
@@ -3207,9 +3212,13 @@ pub const FuncGen = struct {
builder: *const llvm.Builder,
di_scope: ?*llvm.DIScope,
di_file: ?*llvm.DIFile,
+ 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(DbgState) = .{},
+
/// 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, *const llvm.Value),
@@ -3237,11 +3246,13 @@ pub const FuncGen = struct {
single_threaded: bool,
+ const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
fn deinit(self: *FuncGen) void {
self.builder.dispose();
+ self.dbg_inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
}
@@ -3460,6 +3471,8 @@ pub const FuncGen = struct {
.const_ty => unreachable,
.unreach => self.airUnreach(inst),
.dbg_stmt => self.airDbgStmt(inst),
+ .dbg_inline_begin => try self.airDbgInline(inst, true),
+ .dbg_inline_end => try self.airDbgInline(inst, false),
.dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst),
// zig fmt: on
@@ -4175,9 +4188,69 @@ pub const FuncGen = struct {
fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value {
const di_scope = self.di_scope orelse return null;
const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
- self.prev_dbg_line = @intCast(c_uint, self.dg.decl.src_line + dbg_stmt.line + 1);
+ self.prev_dbg_line = @intCast(c_uint, self.base_line + dbg_stmt.line + 1);
self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1);
- self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope);
+ const inlined_at = if (self.dbg_inlined.items.len > 0)
+ self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
+ else
+ null;
+ self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
+ return null;
+ }
+
+ fn airDbgInline(self: *FuncGen, inst: Air.Inst.Index, start: bool) !?*const llvm.Value {
+ const dib = self.dg.object.di_builder orelse return null;
+ const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
+
+ const func = self.air.values[ty_pl.payload].castTag(.function).?.data;
+ const decl = func.owner_decl;
+ const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
+ self.di_file = di_file;
+ const line_number = decl.src_line + 1;
+ const cur_debug_location = self.builder.getCurrentDebugLocation2();
+ if (start) {
+ try self.dbg_inlined.append(self.gpa, .{
+ .loc = @ptrCast(*llvm.DILocation, cur_debug_location),
+ .scope = self.di_scope.?,
+ .base_line = self.base_line,
+ });
+ } else {
+ const old = self.dbg_inlined.pop();
+ self.di_scope = old.scope;
+ self.base_line = old.base_line;
+ return null;
+ }
+
+ const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator());
+ const fqn = try decl.getFullyQualifiedName(self.gpa);
+ defer self.gpa.free(fqn);
+ const fn_info = fn_ty.fnInfo();
+
+ const is_internal_linkage = !self.dg.module.decl_exports.contains(decl);
+ const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
+ llvm.DIFlags.NoReturn
+ else
+ 0;
+ const subprogram = dib.createFunction(
+ di_file.toScope(),
+ decl.name,
+ fqn,
+ di_file,
+ line_number,
+ try self.dg.object.lowerDebugType(fn_ty, .full),
+ is_internal_linkage,
+ true, // is definition
+ line_number + func.lbrace_line, // scope line
+ llvm.DIFlags.StaticMember | noret_bit,
+ self.dg.module.comp.bin_file.options.optimize_mode != .Debug,
+ null, // decl_subprogram
+ );
+
+ try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode());
+
+ const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
+ self.di_scope = lexical_block.toScope();
+ self.base_line = decl.src_line;
return null;
}
@@ -4197,7 +4270,11 @@ pub const FuncGen = struct {
true, // always preserve
0, // flags
);
- const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);
+ 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.builder.getInsertBlock();
_ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
return null;
@@ -4219,7 +4296,11 @@ pub const FuncGen = struct {
true, // always preserve
0, // flags
);
- const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);
+ 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.builder.getInsertBlock();
if (isByRef(operand_ty)) {
_ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
@@ -5481,7 +5562,7 @@ pub const FuncGen = struct {
self.arg_index, // includes +1 because 0 is return type
);
- const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?);
+ const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
const insert_block = self.builder.getInsertBlock();
if (isByRef(inst_ty)) {
_ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index c54d226f66..a6c53fddce 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -839,8 +839,8 @@ pub const Builder = opaque {
pub const buildExactSDiv = LLVMBuildExactSDiv;
extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
- pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;
- extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope) void;
+ pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation2;
+ extern fn ZigLLVMSetCurrentDebugLocation2(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope, inlined_at: ?*DILocation) void;
pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;
@@ -1479,8 +1479,8 @@ pub const DISubprogram = opaque {
extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void;
};
-pub const getDebugLoc = ZigLLVMGetDebugLoc;
-extern fn ZigLLVMGetDebugLoc(line: c_uint, col: c_uint, scope: *DIScope) *DILocation;
+pub const getDebugLoc = ZigLLVMGetDebugLoc2;
+extern fn ZigLLVMGetDebugLoc2(line: c_uint, col: c_uint, scope: *DIScope, inlined_at: ?*DILocation) *DILocation;
pub const DIBuilder = opaque {
pub const dispose = ZigLLVMDisposeDIBuilder;