authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-16 20:40:16+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-16 20:40:16+02:00
log49c0bb1f33044658909cae4351d931af497ee4e5
treeabf9ecce7f08db5b5f92ed30e3fc3f40b926acc3
parentd4a7a9ac4cf64ef6bf0b1aed16282c3d8b47b431
parentd83a26f068f42c6f9cafd25b7038b70553a496d8
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11177 from Vexu/dbg_func

Add debug info for inlined calls

16 files changed, 277 insertions(+), 12 deletions(-)

src/Air.zig+8-1
...@@ -7,7 +7,6 @@ const std = @import("std");...@@ -7,7 +7,6 @@ const std = @import("std");
7const builtin = @import("builtin");7const builtin = @import("builtin");
8const Value = @import("value.zig").Value;8const Value = @import("value.zig").Value;
9const Type = @import("type.zig").Type;9const Type = @import("type.zig").Type;
10const Module = @import("Module.zig");
11const assert = std.debug.assert;10const assert = std.debug.assert;
12const Air = @This();11const Air = @This();
1312
...@@ -327,6 +326,12 @@ pub const Inst = struct {...@@ -327,6 +326,12 @@ pub const Inst = struct {
327 /// Result type is always void.326 /// Result type is always void.
328 /// Uses the `dbg_stmt` field.327 /// Uses the `dbg_stmt` field.
329 dbg_stmt,328 dbg_stmt,
329 /// Marks the start of an inline call.
330 /// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
331 dbg_inline_begin,
332 /// Marks the end of an inline call.
333 /// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
334 dbg_inline_end,
330 /// Marks the beginning of a local variable. The operand is a pointer pointing335 /// Marks the beginning of a local variable. The operand is a pointer pointing
331 /// to the storage for the variable. The local may be a const or a var.336 /// to the storage for the variable. The local may be a const or a var.
332 /// Result type is always void.337 /// Result type is always void.
...@@ -971,6 +976,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {...@@ -971,6 +976,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
971976
972 .breakpoint,977 .breakpoint,
973 .dbg_stmt,978 .dbg_stmt,
979 .dbg_inline_begin,
980 .dbg_inline_end,
974 .dbg_var_ptr,981 .dbg_var_ptr,
975 .dbg_var_val,982 .dbg_var_val,
976 .store,983 .store,
src/AstGen.zig+17
...@@ -5148,6 +5148,7 @@ fn ifExpr(...@@ -5148,6 +5148,7 @@ fn ifExpr(
5148 else5148 else
5149 false;5149 false;
51505150
5151 try emitDbgNode(parent_gz, if_full.ast.cond_expr);
5151 const cond: struct {5152 const cond: struct {
5152 inst: Zir.Inst.Ref,5153 inst: Zir.Inst.Ref,
5153 bool_bit: Zir.Inst.Ref,5154 bool_bit: Zir.Inst.Ref,
...@@ -5458,6 +5459,7 @@ fn whileExpr(...@@ -5458,6 +5459,7 @@ fn whileExpr(
5458 else5459 else
5459 false;5460 false;
54605461
5462 try emitDbgNode(parent_gz, while_full.ast.cond_expr);
5461 const cond: struct {5463 const cond: struct {
5462 inst: Zir.Inst.Ref,5464 inst: Zir.Inst.Ref,
5463 bool_bit: Zir.Inst.Ref,5465 bool_bit: Zir.Inst.Ref,
...@@ -5678,6 +5680,8 @@ fn forExpr(...@@ -5678,6 +5680,8 @@ fn forExpr(
5678 else5680 else
5679 false;5681 false;
56805682
5683 try emitDbgNode(parent_gz, for_full.ast.cond_expr);
5684
5681 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;5685 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
5682 const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr);5686 const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr);
5683 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);5687 const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
...@@ -7810,6 +7814,19 @@ fn callExpr(...@@ -7810,6 +7814,19 @@ fn callExpr(
7810 break :blk .auto;7814 break :blk .auto;
7811 };7815 };
78127816
7817 {
7818 astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]);
7819 const line = astgen.source_line - gz.decl_line;
7820 const column = astgen.source_column;
7821
7822 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
7823 .dbg_stmt = .{
7824 .line = line,
7825 .column = column,
7826 },
7827 } });
7828 }
7829
7813 assert(callee != .none);7830 assert(callee != .none);
7814 assert(node != 0);7831 assert(node != 0);
78157832
src/Liveness.zig+2
...@@ -314,6 +314,8 @@ fn analyzeInst(...@@ -314,6 +314,8 @@ fn analyzeInst(
314 .const_ty,314 .const_ty,
315 .breakpoint,315 .breakpoint,
316 .dbg_stmt,316 .dbg_stmt,
317 .dbg_inline_begin,
318 .dbg_inline_end,
317 .unreach,319 .unreach,
318 .fence,320 .fence,
319 .ret_addr,321 .ret_addr,
src/Sema.zig+37
...@@ -4639,6 +4639,10 @@ fn analyzeCall(...@@ -4639,6 +4639,10 @@ fn analyzeCall(
4639 // comptime state.4639 // comptime state.
4640 var should_memoize = true;4640 var should_memoize = true;
46414641
4642 var new_fn_info = module_fn.owner_decl.ty.fnInfo();
4643 new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len);
4644 new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr;
4645
4642 // This will have return instructions analyzed as break instructions to4646 // This will have return instructions analyzed as break instructions to
4643 // the block_inst above. Here we are performing "comptime/inline semantic analysis"4647 // the block_inst above. Here we are performing "comptime/inline semantic analysis"
4644 // for a function body, which means we must map the parameter ZIR instructions to4648 // for a function body, which means we must map the parameter ZIR instructions to
...@@ -4658,6 +4662,7 @@ fn analyzeCall(...@@ -4658,6 +4662,7 @@ fn analyzeCall(
4658 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];4662 const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
4659 const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst);4663 const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst);
4660 const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);4664 const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);
4665 new_fn_info.param_types[arg_i] = param_ty;
4661 const arg_src = call_src; // TODO: better source location4666 const arg_src = call_src; // TODO: better source location
4662 const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);4667 const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);
4663 try sema.inst_map.putNoClobber(gpa, inst, casted_arg);4668 try sema.inst_map.putNoClobber(gpa, inst, casted_arg);
...@@ -4685,6 +4690,7 @@ fn analyzeCall(...@@ -4685,6 +4690,7 @@ fn analyzeCall(
4685 .param_anytype, .param_anytype_comptime => {4690 .param_anytype, .param_anytype_comptime => {
4686 // No coercion needed.4691 // No coercion needed.
4687 const uncasted_arg = uncasted_args[arg_i];4692 const uncasted_arg = uncasted_args[arg_i];
4693 new_fn_info.param_types[arg_i] = sema.typeOf(uncasted_arg);
4688 try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg);4694 try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg);
46894695
4690 if (is_comptime_call) {4696 if (is_comptime_call) {
...@@ -4735,6 +4741,7 @@ fn analyzeCall(...@@ -4735,6 +4741,7 @@ fn analyzeCall(
4735 }4741 }
4736 break :blk bare_return_type;4742 break :blk bare_return_type;
4737 };4743 };
4744 new_fn_info.return_type = fn_ret_ty;
4738 const parent_fn_ret_ty = sema.fn_ret_ty;4745 const parent_fn_ret_ty = sema.fn_ret_ty;
4739 sema.fn_ret_ty = fn_ret_ty;4746 sema.fn_ret_ty = fn_ret_ty;
4740 defer sema.fn_ret_ty = parent_fn_ret_ty;4747 defer sema.fn_ret_ty = parent_fn_ret_ty;
...@@ -4757,6 +4764,11 @@ fn analyzeCall(...@@ -4757,6 +4764,11 @@ fn analyzeCall(
4757 }4764 }
4758 }4765 }
47594766
4767 const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
4768 if (!is_comptime_call) {
4769 try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
4770 }
4771
4760 const result = result: {4772 const result = result: {
4761 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {4773 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
4762 error.ComptimeReturn => break :result inlining.comptime_result,4774 error.ComptimeReturn => break :result inlining.comptime_result,
...@@ -4771,6 +4783,10 @@ fn analyzeCall(...@@ -4771,6 +4783,10 @@ fn analyzeCall(
4771 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);4783 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
4772 };4784 };
47734785
4786 if (!is_comptime_call) {
4787 try sema.emitDbgInline(block, module_fn, parent_func.?, parent_func.?.owner_decl.ty, .dbg_inline_end);
4788 }
4789
4774 if (should_memoize and is_comptime_call) {4790 if (should_memoize and is_comptime_call) {
4775 const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result);4791 const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result);
47764792
...@@ -5175,6 +5191,27 @@ fn instantiateGenericCall(...@@ -5175,6 +5191,27 @@ fn instantiateGenericCall(
5175 return func_inst;5191 return func_inst;
5176}5192}
51775193
5194fn emitDbgInline(
5195 sema: *Sema,
5196 block: *Block,
5197 old_func: *Module.Fn,
5198 new_func: *Module.Fn,
5199 new_func_ty: Type,
5200 tag: Air.Inst.Tag,
5201) CompileError!void {
5202 // No change of file; no dbg_inline needed.
5203 if (old_func == new_func) return;
5204
5205 try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func));
5206 _ = try block.addInst(.{
5207 .tag = tag,
5208 .data = .{ .ty_pl = .{
5209 .ty = try sema.addType(new_func_ty),
5210 .payload = @intCast(u32, sema.air_values.items.len - 1),
5211 } },
5212 });
5213}
5214
5178fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5215fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5179 _ = block;5216 _ = block;
5180 const tracy = trace(@src());5217 const tracy = trace(@src());
src/arch/aarch64/CodeGen.zig+12
...@@ -649,6 +649,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -649,6 +649,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
649 .dbg_var_val,649 .dbg_var_val,
650 => try self.airDbgVar(inst),650 => try self.airDbgVar(inst),
651651
652 .dbg_inline_begin,
653 .dbg_inline_end,
654 => try self.airDbgInline(inst),
655
652 .call => try self.airCall(inst, .auto),656 .call => try self.airCall(inst, .auto),
653 .call_always_tail => try self.airCall(inst, .always_tail),657 .call_always_tail => try self.airCall(inst, .always_tail),
654 .call_never_tail => try self.airCall(inst, .never_tail),658 .call_never_tail => try self.airCall(inst, .never_tail),
...@@ -2715,6 +2719,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -2715,6 +2719,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
2715 return self.finishAirBookkeeping();2719 return self.finishAirBookkeeping();
2716}2720}
27172721
2722fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
2723 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2724 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
2725 // TODO emit debug info for function change
2726 _ = function;
2727 return self.finishAir(inst, .dead, .{ .none, .none, .none });
2728}
2729
2718fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {2730fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
2719 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2731 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2720 const name = self.air.nullTerminatedString(pl_op.payload);2732 const name = self.air.nullTerminatedString(pl_op.payload);
src/arch/arm/CodeGen.zig+12
...@@ -646,6 +646,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -646,6 +646,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
646 .dbg_var_val,646 .dbg_var_val,
647 => try self.airDbgVar(inst),647 => try self.airDbgVar(inst),
648648
649 .dbg_inline_begin,
650 .dbg_inline_end,
651 => try self.airDbgInline(inst),
652
649 .call => try self.airCall(inst, .auto),653 .call => try self.airCall(inst, .auto),
650 .call_always_tail => try self.airCall(inst, .always_tail),654 .call_always_tail => try self.airCall(inst, .always_tail),
651 .call_never_tail => try self.airCall(inst, .never_tail),655 .call_never_tail => try self.airCall(inst, .never_tail),
...@@ -2835,6 +2839,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -2835,6 +2839,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
2835 return self.finishAirBookkeeping();2839 return self.finishAirBookkeeping();
2836}2840}
28372841
2842fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
2843 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2844 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
2845 // TODO emit debug info for function change
2846 _ = function;
2847 return self.finishAir(inst, .dead, .{ .none, .none, .none });
2848}
2849
2838fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {2850fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
2839 const pl_op = self.air.instructions.items(.data)[inst].pl_op;2851 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2840 const name = self.air.nullTerminatedString(pl_op.payload);2852 const name = self.air.nullTerminatedString(pl_op.payload);
src/arch/riscv64/CodeGen.zig+12
...@@ -613,6 +613,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -613,6 +613,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
613 .dbg_var_val,613 .dbg_var_val,
614 => try self.airDbgVar(inst),614 => try self.airDbgVar(inst),
615615
616 .dbg_inline_begin,
617 .dbg_inline_end,
618 => try self.airDbgInline(inst),
619
616 .call => try self.airCall(inst, .auto),620 .call => try self.airCall(inst, .auto),
617 .call_always_tail => try self.airCall(inst, .always_tail),621 .call_always_tail => try self.airCall(inst, .always_tail),
618 .call_never_tail => try self.airCall(inst, .never_tail),622 .call_never_tail => try self.airCall(inst, .never_tail),
...@@ -1640,6 +1644,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -1640,6 +1644,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
1640 return self.finishAirBookkeeping();1644 return self.finishAirBookkeeping();
1641}1645}
16421646
1647fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
1648 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
1649 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
1650 // TODO emit debug info for function change
1651 _ = function;
1652 return self.finishAir(inst, .dead, .{ .none, .none, .none });
1653}
1654
1643fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {1655fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
1644 const pl_op = self.air.instructions.items(.data)[inst].pl_op;1656 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1645 const name = self.air.nullTerminatedString(pl_op.payload);1657 const name = self.air.nullTerminatedString(pl_op.payload);
src/arch/wasm/CodeGen.zig+2
...@@ -1227,6 +1227,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {...@@ -1227,6 +1227,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
12271227
1228 // TODO1228 // TODO
1229 .dbg_stmt,1229 .dbg_stmt,
1230 .dbg_inline_begin,
1231 .dbg_inline_end,
1230 .dbg_var_ptr,1232 .dbg_var_ptr,
1231 .dbg_var_val,1233 .dbg_var_val,
1232 => WValue.none,1234 => WValue.none,
src/arch/x86_64/CodeGen.zig+12
...@@ -730,6 +730,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -730,6 +730,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
730 .dbg_var_val,730 .dbg_var_val,
731 => try self.airDbgVar(inst),731 => try self.airDbgVar(inst),
732732
733 .dbg_inline_begin,
734 .dbg_inline_end,
735 => try self.airDbgInline(inst),
736
733 .call => try self.airCall(inst, .auto),737 .call => try self.airCall(inst, .auto),
734 .call_always_tail => try self.airCall(inst, .always_tail),738 .call_always_tail => try self.airCall(inst, .always_tail),
735 .call_never_tail => try self.airCall(inst, .never_tail),739 .call_never_tail => try self.airCall(inst, .never_tail),
...@@ -3670,6 +3674,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {...@@ -3670,6 +3674,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
3670 return self.finishAirBookkeeping();3674 return self.finishAirBookkeeping();
3671}3675}
36723676
3677fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
3678 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3679 const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
3680 // TODO emit debug info for function change
3681 _ = function;
3682 return self.finishAir(inst, .dead, .{ .none, .none, .none });
3683}
3684
3673fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {3685fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
3674 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3686 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3675 const name = self.air.nullTerminatedString(pl_op.payload);3687 const name = self.air.nullTerminatedString(pl_op.payload);
src/codegen/c.zig+12
...@@ -1726,6 +1726,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1726,6 +1726,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1726 .dbg_var_val,1726 .dbg_var_val,
1727 => try airDbgVar(f, inst),1727 => try airDbgVar(f, inst),
17281728
1729 .dbg_inline_begin,
1730 .dbg_inline_end,
1731 => try airDbgInline(f, inst),
1732
1729 .call => try airCall(f, inst, .auto),1733 .call => try airCall(f, inst, .auto),
1730 .call_always_tail => try airCall(f, inst, .always_tail),1734 .call_always_tail => try airCall(f, inst, .always_tail),
1731 .call_never_tail => try airCall(f, inst, .never_tail),1735 .call_never_tail => try airCall(f, inst, .never_tail),
...@@ -2660,6 +2664,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -2660,6 +2664,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
2660 return CValue.none;2664 return CValue.none;
2661}2665}
26622666
2667fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
2668 const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
2669 const writer = f.object.writer();
2670 const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
2671 try writer.print("/* dbg func:{s} */\n", .{function.owner_decl.name});
2672 return CValue.none;
2673}
2674
2663fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {2675fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
2664 const pl_op = f.air.instructions.items(.data)[inst].pl_op;2676 const pl_op = f.air.instructions.items(.data)[inst].pl_op;
2665 const name = f.air.nullTerminatedString(pl_op.payload);2677 const name = f.air.nullTerminatedString(pl_op.payload);
src/codegen/llvm.zig+88-7
...@@ -620,7 +620,8 @@ pub const Object = struct {...@@ -620,7 +620,8 @@ pub const Object = struct {
620620
621 llvm_func.fnSetSubprogram(subprogram);621 llvm_func.fnSetSubprogram(subprogram);
622622
623 di_scope = subprogram.toScope();623 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file.?, line_number, 1);
624 di_scope = lexical_block.toScope();
624 }625 }
625626
626 var fg: FuncGen = .{627 var fg: FuncGen = .{
...@@ -639,6 +640,7 @@ pub const Object = struct {...@@ -639,6 +640,7 @@ pub const Object = struct {
639 .single_threaded = module.comp.bin_file.options.single_threaded,640 .single_threaded = module.comp.bin_file.options.single_threaded,
640 .di_scope = di_scope,641 .di_scope = di_scope,
641 .di_file = di_file,642 .di_file = di_file,
643 .base_line = dg.decl.src_line,
642 .prev_dbg_line = 0,644 .prev_dbg_line = 0,
643 .prev_dbg_column = 0,645 .prev_dbg_column = 0,
644 };646 };
...@@ -1754,11 +1756,14 @@ pub const DeclGen = struct {...@@ -1754,11 +1756,14 @@ pub const DeclGen = struct {
1754 /// Note that this can be called before the function's semantic analysis has1756 /// Note that this can be called before the function's semantic analysis has
1755 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.1757 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
1756 fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value {1758 fn resolveLlvmFunction(dg: *DeclGen, decl: *Module.Decl) !*const llvm.Value {
1759 return dg.resolveLlvmFunctionExtra(decl, decl.ty);
1760 }
1761
1762 fn resolveLlvmFunctionExtra(dg: *DeclGen, decl: *Module.Decl, zig_fn_type: Type) !*const llvm.Value {
1757 const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl);1763 const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl);
1758 if (gop.found_existing) return gop.value_ptr.*;1764 if (gop.found_existing) return gop.value_ptr.*;
17591765
1760 assert(decl.has_tv);1766 assert(decl.has_tv);
1761 const zig_fn_type = decl.ty;
1762 const fn_info = zig_fn_type.fnInfo();1767 const fn_info = zig_fn_type.fnInfo();
1763 const target = dg.module.getTarget();1768 const target = dg.module.getTarget();
1764 const sret = firstParamSRet(fn_info, target);1769 const sret = firstParamSRet(fn_info, target);
...@@ -3207,9 +3212,13 @@ pub const FuncGen = struct {...@@ -3207,9 +3212,13 @@ pub const FuncGen = struct {
3207 builder: *const llvm.Builder,3212 builder: *const llvm.Builder,
3208 di_scope: ?*llvm.DIScope,3213 di_scope: ?*llvm.DIScope,
3209 di_file: ?*llvm.DIFile,3214 di_file: ?*llvm.DIFile,
3215 base_line: u32,
3210 prev_dbg_line: c_uint,3216 prev_dbg_line: c_uint,
3211 prev_dbg_column: c_uint,3217 prev_dbg_column: c_uint,
32123218
3219 /// Stack of locations where a call was inlined.
3220 dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
3221
3213 /// This stores the LLVM values used in a function, such that they can be referred to3222 /// This stores the LLVM values used in a function, such that they can be referred to
3214 /// in other instructions. This table is cleared before every function is generated.3223 /// in other instructions. This table is cleared before every function is generated.
3215 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *const llvm.Value),3224 func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *const llvm.Value),
...@@ -3237,11 +3246,13 @@ pub const FuncGen = struct {...@@ -3237,11 +3246,13 @@ pub const FuncGen = struct {
32373246
3238 single_threaded: bool,3247 single_threaded: bool,
32393248
3249 const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 };
3240 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);3250 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
3241 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);3251 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
32423252
3243 fn deinit(self: *FuncGen) void {3253 fn deinit(self: *FuncGen) void {
3244 self.builder.dispose();3254 self.builder.dispose();
3255 self.dbg_inlined.deinit(self.gpa);
3245 self.func_inst_table.deinit(self.gpa);3256 self.func_inst_table.deinit(self.gpa);
3246 self.blocks.deinit(self.gpa);3257 self.blocks.deinit(self.gpa);
3247 }3258 }
...@@ -3460,6 +3471,8 @@ pub const FuncGen = struct {...@@ -3460,6 +3471,8 @@ pub const FuncGen = struct {
3460 .const_ty => unreachable,3471 .const_ty => unreachable,
3461 .unreach => self.airUnreach(inst),3472 .unreach => self.airUnreach(inst),
3462 .dbg_stmt => self.airDbgStmt(inst),3473 .dbg_stmt => self.airDbgStmt(inst),
3474 .dbg_inline_begin => try self.airDbgInline(inst, true),
3475 .dbg_inline_end => try self.airDbgInline(inst, false),
3463 .dbg_var_ptr => try self.airDbgVarPtr(inst),3476 .dbg_var_ptr => try self.airDbgVarPtr(inst),
3464 .dbg_var_val => try self.airDbgVarVal(inst),3477 .dbg_var_val => try self.airDbgVarVal(inst),
3465 // zig fmt: on3478 // zig fmt: on
...@@ -4175,9 +4188,69 @@ pub const FuncGen = struct {...@@ -4175,9 +4188,69 @@ pub const FuncGen = struct {
4175 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value {4188 fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value {
4176 const di_scope = self.di_scope orelse return null;4189 const di_scope = self.di_scope orelse return null;
4177 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;4190 const dbg_stmt = self.air.instructions.items(.data)[inst].dbg_stmt;
4178 self.prev_dbg_line = @intCast(c_uint, self.dg.decl.src_line + dbg_stmt.line + 1);4191 self.prev_dbg_line = @intCast(c_uint, self.base_line + dbg_stmt.line + 1);
4179 self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1);4192 self.prev_dbg_column = @intCast(c_uint, dbg_stmt.column + 1);
4180 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope);4193 const inlined_at = if (self.dbg_inlined.items.len > 0)
4194 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
4195 else
4196 null;
4197 self.builder.setCurrentDebugLocation(self.prev_dbg_line, self.prev_dbg_column, di_scope, inlined_at);
4198 return null;
4199 }
4200
4201 fn airDbgInline(self: *FuncGen, inst: Air.Inst.Index, start: bool) !?*const llvm.Value {
4202 const dib = self.dg.object.di_builder orelse return null;
4203 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
4204
4205 const func = self.air.values[ty_pl.payload].castTag(.function).?.data;
4206 const decl = func.owner_decl;
4207 const di_file = try self.dg.object.getDIFile(self.gpa, decl.src_namespace.file_scope);
4208 self.di_file = di_file;
4209 const line_number = decl.src_line + 1;
4210 const cur_debug_location = self.builder.getCurrentDebugLocation2();
4211 if (start) {
4212 try self.dbg_inlined.append(self.gpa, .{
4213 .loc = @ptrCast(*llvm.DILocation, cur_debug_location),
4214 .scope = self.di_scope.?,
4215 .base_line = self.base_line,
4216 });
4217 } else {
4218 const old = self.dbg_inlined.pop();
4219 self.di_scope = old.scope;
4220 self.base_line = old.base_line;
4221 return null;
4222 }
4223
4224 const fn_ty = try self.air.getRefType(ty_pl.ty).copy(self.dg.object.type_map_arena.allocator());
4225 const fqn = try decl.getFullyQualifiedName(self.gpa);
4226 defer self.gpa.free(fqn);
4227 const fn_info = fn_ty.fnInfo();
4228
4229 const is_internal_linkage = !self.dg.module.decl_exports.contains(decl);
4230 const noret_bit: c_uint = if (fn_info.return_type.isNoReturn())
4231 llvm.DIFlags.NoReturn
4232 else
4233 0;
4234 const subprogram = dib.createFunction(
4235 di_file.toScope(),
4236 decl.name,
4237 fqn,
4238 di_file,
4239 line_number,
4240 try self.dg.object.lowerDebugType(fn_ty, .full),
4241 is_internal_linkage,
4242 true, // is definition
4243 line_number + func.lbrace_line, // scope line
4244 llvm.DIFlags.StaticMember | noret_bit,
4245 self.dg.module.comp.bin_file.options.optimize_mode != .Debug,
4246 null, // decl_subprogram
4247 );
4248
4249 try self.dg.object.di_map.put(self.gpa, decl, subprogram.toNode());
4250
4251 const lexical_block = dib.createLexicalBlock(subprogram.toScope(), di_file, line_number, 1);
4252 self.di_scope = lexical_block.toScope();
4253 self.base_line = decl.src_line;
4181 return null;4254 return null;
4182 }4255 }
41834256
...@@ -4197,7 +4270,11 @@ pub const FuncGen = struct {...@@ -4197,7 +4270,11 @@ pub const FuncGen = struct {
4197 true, // always preserve4270 true, // always preserve
4198 0, // flags4271 0, // flags
4199 );4272 );
4200 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);4273 const inlined_at = if (self.dbg_inlined.items.len > 0)
4274 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
4275 else
4276 null;
4277 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
4201 const insert_block = self.builder.getInsertBlock();4278 const insert_block = self.builder.getInsertBlock();
4202 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);4279 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
4203 return null;4280 return null;
...@@ -4219,7 +4296,11 @@ pub const FuncGen = struct {...@@ -4219,7 +4296,11 @@ pub const FuncGen = struct {
4219 true, // always preserve4296 true, // always preserve
4220 0, // flags4297 0, // flags
4221 );4298 );
4222 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?);4299 const inlined_at = if (self.dbg_inlined.items.len > 0)
4300 self.dbg_inlined.items[self.dbg_inlined.items.len - 1].loc
4301 else
4302 null;
4303 const debug_loc = llvm.getDebugLoc(self.prev_dbg_line, self.prev_dbg_column, self.di_scope.?, inlined_at);
4223 const insert_block = self.builder.getInsertBlock();4304 const insert_block = self.builder.getInsertBlock();
4224 if (isByRef(operand_ty)) {4305 if (isByRef(operand_ty)) {
4225 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);4306 _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block);
...@@ -5481,7 +5562,7 @@ pub const FuncGen = struct {...@@ -5481,7 +5562,7 @@ pub const FuncGen = struct {
5481 self.arg_index, // includes +1 because 0 is return type5562 self.arg_index, // includes +1 because 0 is return type
5482 );5563 );
54835564
5484 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?);5565 const debug_loc = llvm.getDebugLoc(lbrace_line, lbrace_col, self.di_scope.?, null);
5485 const insert_block = self.builder.getInsertBlock();5566 const insert_block = self.builder.getInsertBlock();
5486 if (isByRef(inst_ty)) {5567 if (isByRef(inst_ty)) {
5487 _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);5568 _ = dib.insertDeclareAtEnd(arg_val, di_local_var, debug_loc, insert_block);
src/codegen/llvm/bindings.zig+4-4
...@@ -839,8 +839,8 @@ pub const Builder = opaque {...@@ -839,8 +839,8 @@ pub const Builder = opaque {
839 pub const buildExactSDiv = LLVMBuildExactSDiv;839 pub const buildExactSDiv = LLVMBuildExactSDiv;
840 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;840 extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value;
841841
842 pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation;842 pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation2;
843 extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope) void;843 extern fn ZigLLVMSetCurrentDebugLocation2(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope, inlined_at: ?*DILocation) void;
844844
845 pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;845 pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation;
846 extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;846 extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void;
...@@ -1479,8 +1479,8 @@ pub const DISubprogram = opaque {...@@ -1479,8 +1479,8 @@ pub const DISubprogram = opaque {
1479 extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void;1479 extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void;
1480};1480};
14811481
1482pub const getDebugLoc = ZigLLVMGetDebugLoc;1482pub const getDebugLoc = ZigLLVMGetDebugLoc2;
1483extern fn ZigLLVMGetDebugLoc(line: c_uint, col: c_uint, scope: *DIScope) *DILocation;1483extern fn ZigLLVMGetDebugLoc2(line: c_uint, col: c_uint, scope: *DIScope, inlined_at: ?*DILocation) *DILocation;
14841484
1485pub const DIBuilder = opaque {1485pub const DIBuilder = opaque {
1486 pub const dispose = ZigLLVMDisposeDIBuilder;1486 pub const dispose = ZigLLVMDisposeDIBuilder;
src/print_air.zig+8
...@@ -242,6 +242,8 @@ const Writer = struct {...@@ -242,6 +242,8 @@ const Writer = struct {
242 .constant => try w.writeConstant(s, inst),242 .constant => try w.writeConstant(s, inst),
243 .assembly => try w.writeAssembly(s, inst),243 .assembly => try w.writeAssembly(s, inst),
244 .dbg_stmt => try w.writeDbgStmt(s, inst),244 .dbg_stmt => try w.writeDbgStmt(s, inst),
245
246 .dbg_inline_begin, .dbg_inline_end => try w.writeDbgInline(s, inst),
245 .aggregate_init => try w.writeAggregateInit(s, inst),247 .aggregate_init => try w.writeAggregateInit(s, inst),
246 .union_init => try w.writeUnionInit(s, inst),248 .union_init => try w.writeUnionInit(s, inst),
247 .br => try w.writeBr(s, inst),249 .br => try w.writeBr(s, inst),
...@@ -552,6 +554,12 @@ const Writer = struct {...@@ -552,6 +554,12 @@ const Writer = struct {
552 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });554 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
553 }555 }
554556
557 fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
558 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
559 const function = w.air.values[ty_pl.payload].castTag(.function).?.data;
560 try s.print("{s}", .{function.owner_decl.name});
561 }
562
555 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {563 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
556 const pl_op = w.air.instructions.items(.data)[inst].pl_op;564 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
557 try w.writeOperand(s, inst, 0, pl_op.operand);565 try w.writeOperand(s, inst, 0, pl_op.operand);
src/type.zig+30
...@@ -486,6 +486,36 @@ pub const Type = extern union {...@@ -486,6 +486,36 @@ pub const Type = extern union {
486486
487 .pointer => return self.castTag(.pointer).?.*,487 .pointer => return self.castTag(.pointer).?.*,
488488
489 .optional_single_mut_pointer => return .{ .data = .{
490 .pointee_type = self.castPointer().?.data,
491 .sentinel = null,
492 .@"align" = 0,
493 .@"addrspace" = .generic,
494 .bit_offset = 0,
495 .host_size = 0,
496 .@"allowzero" = false,
497 .mutable = true,
498 .@"volatile" = false,
499 .size = .One,
500 } },
501 .optional_single_const_pointer => return .{ .data = .{
502 .pointee_type = self.castPointer().?.data,
503 .sentinel = null,
504 .@"align" = 0,
505 .@"addrspace" = .generic,
506 .bit_offset = 0,
507 .host_size = 0,
508 .@"allowzero" = false,
509 .mutable = false,
510 .@"volatile" = false,
511 .size = .One,
512 } },
513 .optional => {
514 var buf: Payload.ElemType = undefined;
515 const child_type = self.optionalChild(&buf);
516 return child_type.ptrInfo();
517 },
518
489 else => unreachable,519 else => unreachable,
490 }520 }
491 }521 }
src/zig_llvm.cpp+17
...@@ -799,6 +799,15 @@ void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,...@@ -799,6 +799,15 @@ void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,
799 unwrap(builder)->SetCurrentDebugLocation(debug_loc);799 unwrap(builder)->SetCurrentDebugLocation(debug_loc);
800}800}
801801
802void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
803 unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at)
804{
805 DIScope* di_scope = reinterpret_cast<DIScope*>(scope);
806 DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, column, di_scope,
807 reinterpret_cast<DILocation *>(inlined_at), false);
808 unwrap(builder)->SetCurrentDebugLocation(debug_loc);
809}
810
802void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder) {811void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder) {
803 unwrap(builder)->SetCurrentDebugLocation(DebugLoc());812 unwrap(builder)->SetCurrentDebugLocation(DebugLoc());
804}813}
...@@ -1025,6 +1034,14 @@ ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScop...@@ -1025,6 +1034,14 @@ ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScop
1025 return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get());1034 return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get());
1026}1035}
10271036
1037ZigLLVMDILocation *ZigLLVMGetDebugLoc2(unsigned line, unsigned col, ZigLLVMDIScope *scope,
1038 ZigLLVMDILocation *inlined_at) {
1039 DIScope* di_scope = reinterpret_cast<DIScope*>(scope);
1040 DebugLoc debug_loc = DILocation::get(di_scope->getContext(), line, col, di_scope,
1041 reinterpret_cast<DILocation *>(inlined_at), false);
1042 return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get());
1043}
1044
1028void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {1045void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) {
1029 if (on_state) {1046 if (on_state) {
1030 FastMathFlags fmf;1047 FastMathFlags fmf;
src/zig_llvm.h+4
...@@ -232,6 +232,8 @@ ZIG_EXTERN_C void ZigLLVMSetModuleCodeModel(LLVMModuleRef module, LLVMCodeModel...@@ -232,6 +232,8 @@ ZIG_EXTERN_C void ZigLLVMSetModuleCodeModel(LLVMModuleRef module, LLVMCodeModel
232232
233ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,233ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder,
234 unsigned int line, unsigned int column, struct ZigLLVMDIScope *scope);234 unsigned int line, unsigned int column, struct ZigLLVMDIScope *scope);
235ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line,
236 unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at);
235ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);237ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
236238
237ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block);239ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block);
...@@ -290,6 +292,8 @@ ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);...@@ -290,6 +292,8 @@ ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
290292
291ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col,293ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col,
292 struct ZigLLVMDIScope *scope);294 struct ZigLLVMDIScope *scope);
295ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc2(unsigned line, unsigned col,
296 ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at);
293297
294ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dib,298ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dib,
295 LLVMValueRef storage, struct ZigLLVMDILocalVariable *var_info,299 LLVMValueRef storage, struct ZigLLVMDILocalVariable *var_info,