aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-03-15 18:27:09 +0200
committerVeikka Tuominen <git@vexu.eu>2022-03-16 10:53:41 +0200
commitd83a26f068f42c6f9cafd25b7038b70553a496d8 (patch)
tree016bc2d9fa343ceac3a1b1f0fd6971dde706a1e4 /src/codegen
parent03438118369605df178f4bfdb5b1a8ad6a349be7 (diff)
downloadzig-d83a26f068f42c6f9cafd25b7038b70553a496d8.tar.gz
zig-d83a26f068f42c6f9cafd25b7038b70553a496d8.zip
stage2 llvm: keep track of inlined functions
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig7
-rw-r--r--src/codegen/llvm.zig78
-rw-r--r--src/codegen/llvm/bindings.zig8
3 files changed, 67 insertions, 26 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index c726f659a1..358e7354dd 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -1687,7 +1687,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.block => try airBlock(f, inst),
.bitcast => try airBitcast(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
- .dbg_func => try airDbgFunc(f, inst),
.intcast => try airIntCast(f, inst),
.trunc => try airTrunc(f, inst),
.bool_to_int => try airBoolToInt(f, inst),
@@ -1727,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),
@@ -2661,7 +2664,7 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue.none;
}
-fn airDbgFunc(f: *Function, inst: Air.Inst.Index) !CValue {
+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;
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index e8c527c112..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,
};
@@ -3210,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),
@@ -3240,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);
}
@@ -3463,7 +3471,8 @@ pub const FuncGen = struct {
.const_ty => unreachable,
.unreach => self.airUnreach(inst),
.dbg_stmt => self.airDbgStmt(inst),
- .dbg_func => try self.airDbgFunc(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
@@ -4179,24 +4188,44 @@ 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 airDbgFunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ 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 function = self.air.values[ty_pl.payload].castTag(.function).?.data;
- const decl = function.owner_decl;
+
+ 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 llvm_func = try self.dg.resolveLlvmFunctionExtra(decl, fn_ty);
+ const fqn = try decl.getFullyQualifiedName(self.gpa);
+ defer self.gpa.free(fqn);
const fn_info = fn_ty.fnInfo();
- const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
- const line_number = decl.src_line + 1;
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
@@ -4205,22 +4234,23 @@ pub const FuncGen = struct {
const subprogram = dib.createFunction(
di_file.toScope(),
decl.name,
- llvm_func.getValueName(),
+ fqn,
di_file,
line_number,
- try self.dg.lowerDebugType(fn_ty),
+ try self.dg.object.lowerDebugType(fn_ty, .full),
is_internal_linkage,
true, // is definition
- line_number + function.lbrace_line, // scope line
+ 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());
- llvm_func.fnSetSubprogram(subprogram);
+ try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode());
- self.di_scope = subprogram.toScope();
+ 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;
}
@@ -4240,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;
@@ -4262,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);
@@ -5524,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;