diff options
| author | Veikka Tuominen <git@vexu.eu> | 2022-03-15 18:27:09 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-03-16 10:53:41 +0200 |
| commit | d83a26f068f42c6f9cafd25b7038b70553a496d8 (patch) | |
| tree | 016bc2d9fa343ceac3a1b1f0fd6971dde706a1e4 /src/codegen | |
| parent | 03438118369605df178f4bfdb5b1a8ad6a349be7 (diff) | |
| download | zig-d83a26f068f42c6f9cafd25b7038b70553a496d8.tar.gz zig-d83a26f068f42c6f9cafd25b7038b70553a496d8.zip | |
stage2 llvm: keep track of inlined functions
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/c.zig | 7 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 78 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 8 |
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; |
