| author | |
| committer | |
| log | 49c0bb1f33044658909cae4351d931af497ee4e5 |
| tree | abf9ecce7f08db5b5f92ed30e3fc3f40b926acc3 |
| parent | d4a7a9ac4cf64ef6bf0b1aed16282c3d8b47b431 |
| parent | d83a26f068f42c6f9cafd25b7038b70553a496d8 |
| signature |
Add debug info for inlined calls16 files changed, 277 insertions(+), 12 deletions(-)
src/Air.zig+8-1| ... | ... | @@ -7,7 +7,6 @@ const std = @import("std"); |
| 7 | 7 | const builtin = @import("builtin"); |
| 8 | 8 | const Value = @import("value.zig").Value; |
| 9 | 9 | const Type = @import("type.zig").Type; |
| 10 | const Module = @import("Module.zig"); | |
| 11 | 10 | const assert = std.debug.assert; |
| 12 | 11 | const Air = @This(); |
| 13 | 12 | |
| ... | ... | @@ -327,6 +326,12 @@ pub const Inst = struct { |
| 327 | 326 | /// Result type is always void. |
| 328 | 327 | /// Uses the `dbg_stmt` field. |
| 329 | 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 | 335 | /// Marks the beginning of a local variable. The operand is a pointer pointing |
| 331 | 336 | /// to the storage for the variable. The local may be a const or a var. |
| 332 | 337 | /// Result type is always void. |
| ... | ... | @@ -971,6 +976,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type { |
| 971 | 976 | |
| 972 | 977 | .breakpoint, |
| 973 | 978 | .dbg_stmt, |
| 979 | .dbg_inline_begin, | |
| 980 | .dbg_inline_end, | |
| 974 | 981 | .dbg_var_ptr, |
| 975 | 982 | .dbg_var_val, |
| 976 | 983 | .store, |
src/AstGen.zig+17| ... | ... | @@ -5148,6 +5148,7 @@ fn ifExpr( |
| 5148 | 5148 | else |
| 5149 | 5149 | false; |
| 5150 | 5150 | |
| 5151 | try emitDbgNode(parent_gz, if_full.ast.cond_expr); | |
| 5151 | 5152 | const cond: struct { |
| 5152 | 5153 | inst: Zir.Inst.Ref, |
| 5153 | 5154 | bool_bit: Zir.Inst.Ref, |
| ... | ... | @@ -5458,6 +5459,7 @@ fn whileExpr( |
| 5458 | 5459 | else |
| 5459 | 5460 | false; |
| 5460 | 5461 | |
| 5462 | try emitDbgNode(parent_gz, while_full.ast.cond_expr); | |
| 5461 | 5463 | const cond: struct { |
| 5462 | 5464 | inst: Zir.Inst.Ref, |
| 5463 | 5465 | bool_bit: Zir.Inst.Ref, |
| ... | ... | @@ -5678,6 +5680,8 @@ fn forExpr( |
| 5678 | 5680 | else |
| 5679 | 5681 | false; |
| 5680 | 5682 | |
| 5683 | try emitDbgNode(parent_gz, for_full.ast.cond_expr); | |
| 5684 | ||
| 5681 | 5685 | const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none; |
| 5682 | 5686 | const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr); |
| 5683 | 5687 | const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr); |
| ... | ... | @@ -7810,6 +7814,19 @@ fn callExpr( |
| 7810 | 7814 | break :blk .auto; |
| 7811 | 7815 | }; |
| 7812 | 7816 | |
| 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 | 7830 | assert(callee != .none); |
| 7814 | 7831 | assert(node != 0); |
| 7815 | 7832 |
src/Liveness.zig+2| ... | ... | @@ -314,6 +314,8 @@ fn analyzeInst( |
| 314 | 314 | .const_ty, |
| 315 | 315 | .breakpoint, |
| 316 | 316 | .dbg_stmt, |
| 317 | .dbg_inline_begin, | |
| 318 | .dbg_inline_end, | |
| 317 | 319 | .unreach, |
| 318 | 320 | .fence, |
| 319 | 321 | .ret_addr, |
src/Sema.zig+37| ... | ... | @@ -4639,6 +4639,10 @@ fn analyzeCall( |
| 4639 | 4639 | // comptime state. |
| 4640 | 4640 | var should_memoize = true; |
| 4641 | 4641 | |
| 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 | 4646 | // This will have return instructions analyzed as break instructions to |
| 4643 | 4647 | // the block_inst above. Here we are performing "comptime/inline semantic analysis" |
| 4644 | 4648 | // for a function body, which means we must map the parameter ZIR instructions to |
| ... | ... | @@ -4658,6 +4662,7 @@ fn analyzeCall( |
| 4658 | 4662 | const param_body = sema.code.extra[extra.end..][0..extra.data.body_len]; |
| 4659 | 4663 | const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst); |
| 4660 | 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 | 4666 | const arg_src = call_src; // TODO: better source location |
| 4662 | 4667 | const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src); |
| 4663 | 4668 | try sema.inst_map.putNoClobber(gpa, inst, casted_arg); |
| ... | ... | @@ -4685,6 +4690,7 @@ fn analyzeCall( |
| 4685 | 4690 | .param_anytype, .param_anytype_comptime => { |
| 4686 | 4691 | // No coercion needed. |
| 4687 | 4692 | const uncasted_arg = uncasted_args[arg_i]; |
| 4693 | new_fn_info.param_types[arg_i] = sema.typeOf(uncasted_arg); | |
| 4688 | 4694 | try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg); |
| 4689 | 4695 | |
| 4690 | 4696 | if (is_comptime_call) { |
| ... | ... | @@ -4735,6 +4741,7 @@ fn analyzeCall( |
| 4735 | 4741 | } |
| 4736 | 4742 | break :blk bare_return_type; |
| 4737 | 4743 | }; |
| 4744 | new_fn_info.return_type = fn_ret_ty; | |
| 4738 | 4745 | const parent_fn_ret_ty = sema.fn_ret_ty; |
| 4739 | 4746 | sema.fn_ret_ty = fn_ret_ty; |
| 4740 | 4747 | defer sema.fn_ret_ty = parent_fn_ret_ty; |
| ... | ... | @@ -4757,6 +4764,11 @@ fn analyzeCall( |
| 4757 | 4764 | } |
| 4758 | 4765 | } |
| 4759 | 4766 | |
| 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 | 4772 | const result = result: { |
| 4761 | 4773 | sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) { |
| 4762 | 4774 | error.ComptimeReturn => break :result inlining.comptime_result, |
| ... | ... | @@ -4771,6 +4783,10 @@ fn analyzeCall( |
| 4771 | 4783 | break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges); |
| 4772 | 4784 | }; |
| 4773 | 4785 | |
| 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 | 4790 | if (should_memoize and is_comptime_call) { |
| 4775 | 4791 | const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result); |
| 4776 | 4792 | |
| ... | ... | @@ -5175,6 +5191,27 @@ fn instantiateGenericCall( |
| 5175 | 5191 | return func_inst; |
| 5176 | 5192 | } |
| 5177 | 5193 | |
| 5194 | fn 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 | ||
| 5178 | 5215 | fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 5179 | 5216 | _ = block; |
| 5180 | 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 | 649 | .dbg_var_val, |
| 650 | 650 | => try self.airDbgVar(inst), |
| 651 | 651 | |
| 652 | .dbg_inline_begin, | |
| 653 | .dbg_inline_end, | |
| 654 | => try self.airDbgInline(inst), | |
| 655 | ||
| 652 | 656 | .call => try self.airCall(inst, .auto), |
| 653 | 657 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 654 | 658 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -2715,6 +2719,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2715 | 2719 | return self.finishAirBookkeeping(); |
| 2716 | 2720 | } |
| 2717 | 2721 | |
| 2722 | fn 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 | ||
| 2718 | 2730 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 2719 | 2731 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2720 | 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 | 646 | .dbg_var_val, |
| 647 | 647 | => try self.airDbgVar(inst), |
| 648 | 648 | |
| 649 | .dbg_inline_begin, | |
| 650 | .dbg_inline_end, | |
| 651 | => try self.airDbgInline(inst), | |
| 652 | ||
| 649 | 653 | .call => try self.airCall(inst, .auto), |
| 650 | 654 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 651 | 655 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -2835,6 +2839,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 2835 | 2839 | return self.finishAirBookkeeping(); |
| 2836 | 2840 | } |
| 2837 | 2841 | |
| 2842 | fn 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 | ||
| 2838 | 2850 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 2839 | 2851 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 2840 | 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 | 613 | .dbg_var_val, |
| 614 | 614 | => try self.airDbgVar(inst), |
| 615 | 615 | |
| 616 | .dbg_inline_begin, | |
| 617 | .dbg_inline_end, | |
| 618 | => try self.airDbgInline(inst), | |
| 619 | ||
| 616 | 620 | .call => try self.airCall(inst, .auto), |
| 617 | 621 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 618 | 622 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -1640,6 +1644,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 1640 | 1644 | return self.finishAirBookkeeping(); |
| 1641 | 1645 | } |
| 1642 | 1646 | |
| 1647 | fn 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 | ||
| 1643 | 1655 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 1644 | 1656 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 1645 | 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 | 1227 | |
| 1228 | 1228 | // TODO |
| 1229 | 1229 | .dbg_stmt, |
| 1230 | .dbg_inline_begin, | |
| 1231 | .dbg_inline_end, | |
| 1230 | 1232 | .dbg_var_ptr, |
| 1231 | 1233 | .dbg_var_val, |
| 1232 | 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 | 730 | .dbg_var_val, |
| 731 | 731 | => try self.airDbgVar(inst), |
| 732 | 732 | |
| 733 | .dbg_inline_begin, | |
| 734 | .dbg_inline_end, | |
| 735 | => try self.airDbgInline(inst), | |
| 736 | ||
| 733 | 737 | .call => try self.airCall(inst, .auto), |
| 734 | 738 | .call_always_tail => try self.airCall(inst, .always_tail), |
| 735 | 739 | .call_never_tail => try self.airCall(inst, .never_tail), |
| ... | ... | @@ -3670,6 +3674,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void { |
| 3670 | 3674 | return self.finishAirBookkeeping(); |
| 3671 | 3675 | } |
| 3672 | 3676 | |
| 3677 | fn 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 | ||
| 3673 | 3685 | fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void { |
| 3674 | 3686 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 3675 | 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 | 1726 | .dbg_var_val, |
| 1727 | 1727 | => try airDbgVar(f, inst), |
| 1728 | 1728 | |
| 1729 | .dbg_inline_begin, | |
| 1730 | .dbg_inline_end, | |
| 1731 | => try airDbgInline(f, inst), | |
| 1732 | ||
| 1729 | 1733 | .call => try airCall(f, inst, .auto), |
| 1730 | 1734 | .call_always_tail => try airCall(f, inst, .always_tail), |
| 1731 | 1735 | .call_never_tail => try airCall(f, inst, .never_tail), |
| ... | ... | @@ -2660,6 +2664,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2660 | 2664 | return CValue.none; |
| 2661 | 2665 | } |
| 2662 | 2666 | |
| 2667 | fn 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 | ||
| 2663 | 2675 | fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2664 | 2676 | const pl_op = f.air.instructions.items(.data)[inst].pl_op; |
| 2665 | 2677 | const name = f.air.nullTerminatedString(pl_op.payload); |
src/codegen/llvm.zig+88-7| ... | ... | @@ -620,7 +620,8 @@ pub const Object = struct { |
| 620 | 620 | |
| 621 | 621 | llvm_func.fnSetSubprogram(subprogram); |
| 622 | 622 | |
| 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 | } |
| 625 | 626 | |
| 626 | 627 | var fg: FuncGen = .{ |
| ... | ... | @@ -639,6 +640,7 @@ pub const Object = struct { |
| 639 | 640 | .single_threaded = module.comp.bin_file.options.single_threaded, |
| 640 | 641 | .di_scope = di_scope, |
| 641 | 642 | .di_file = di_file, |
| 643 | .base_line = dg.decl.src_line, | |
| 642 | 644 | .prev_dbg_line = 0, |
| 643 | 645 | .prev_dbg_column = 0, |
| 644 | 646 | }; |
| ... | ... | @@ -1754,11 +1756,14 @@ pub const DeclGen = struct { |
| 1754 | 1756 | /// Note that this can be called before the function's semantic analysis has |
| 1755 | 1757 | /// completed, so if any attributes rely on that, they must be done in updateFunc, not here. |
| 1756 | 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 | 1763 | const gop = try dg.object.decl_map.getOrPut(dg.gpa, decl); |
| 1758 | 1764 | if (gop.found_existing) return gop.value_ptr.*; |
| 1759 | 1765 | |
| 1760 | 1766 | assert(decl.has_tv); |
| 1761 | const zig_fn_type = decl.ty; | |
| 1762 | 1767 | const fn_info = zig_fn_type.fnInfo(); |
| 1763 | 1768 | const target = dg.module.getTarget(); |
| 1764 | 1769 | const sret = firstParamSRet(fn_info, target); |
| ... | ... | @@ -3207,9 +3212,13 @@ pub const FuncGen = struct { |
| 3207 | 3212 | builder: *const llvm.Builder, |
| 3208 | 3213 | di_scope: ?*llvm.DIScope, |
| 3209 | 3214 | di_file: ?*llvm.DIFile, |
| 3215 | base_line: u32, | |
| 3210 | 3216 | prev_dbg_line: c_uint, |
| 3211 | 3217 | prev_dbg_column: c_uint, |
| 3212 | 3218 | |
| 3219 | /// Stack of locations where a call was inlined. | |
| 3220 | dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{}, | |
| 3221 | ||
| 3213 | 3222 | /// This stores the LLVM values used in a function, such that they can be referred to |
| 3214 | 3223 | /// in other instructions. This table is cleared before every function is generated. |
| 3215 | 3224 | func_inst_table: std.AutoHashMapUnmanaged(Air.Inst.Ref, *const llvm.Value), |
| ... | ... | @@ -3237,11 +3246,13 @@ pub const FuncGen = struct { |
| 3237 | 3246 | |
| 3238 | 3247 | single_threaded: bool, |
| 3239 | 3248 | |
| 3249 | const DbgState = struct { loc: *llvm.DILocation, scope: *llvm.DIScope, base_line: u32 }; | |
| 3240 | 3250 | const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock); |
| 3241 | 3251 | const BreakValues = std.ArrayListUnmanaged(*const llvm.Value); |
| 3242 | 3252 | |
| 3243 | 3253 | fn deinit(self: *FuncGen) void { |
| 3244 | 3254 | self.builder.dispose(); |
| 3255 | self.dbg_inlined.deinit(self.gpa); | |
| 3245 | 3256 | self.func_inst_table.deinit(self.gpa); |
| 3246 | 3257 | self.blocks.deinit(self.gpa); |
| 3247 | 3258 | } |
| ... | ... | @@ -3460,6 +3471,8 @@ pub const FuncGen = struct { |
| 3460 | 3471 | .const_ty => unreachable, |
| 3461 | 3472 | .unreach => self.airUnreach(inst), |
| 3462 | 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 | 3476 | .dbg_var_ptr => try self.airDbgVarPtr(inst), |
| 3464 | 3477 | .dbg_var_val => try self.airDbgVarVal(inst), |
| 3465 | 3478 | // zig fmt: on |
| ... | ... | @@ -4175,9 +4188,69 @@ pub const FuncGen = struct { |
| 4175 | 4188 | fn airDbgStmt(self: *FuncGen, inst: Air.Inst.Index) ?*const llvm.Value { |
| 4176 | 4189 | const di_scope = self.di_scope orelse return null; |
| 4177 | 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 | 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 | 4254 | return null; |
| 4182 | 4255 | } |
| 4183 | 4256 | |
| ... | ... | @@ -4197,7 +4270,11 @@ pub const FuncGen = struct { |
| 4197 | 4270 | true, // always preserve |
| 4198 | 4271 | 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 | 4278 | const insert_block = self.builder.getInsertBlock(); |
| 4202 | 4279 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); |
| 4203 | 4280 | return null; |
| ... | ... | @@ -4219,7 +4296,11 @@ pub const FuncGen = struct { |
| 4219 | 4296 | true, // always preserve |
| 4220 | 4297 | 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 | 4304 | const insert_block = self.builder.getInsertBlock(); |
| 4224 | 4305 | if (isByRef(operand_ty)) { |
| 4225 | 4306 | _ = dib.insertDeclareAtEnd(operand, di_local_var, debug_loc, insert_block); |
| ... | ... | @@ -5481,7 +5562,7 @@ pub const FuncGen = struct { |
| 5481 | 5562 | self.arg_index, // includes +1 because 0 is return type |
| 5482 | 5563 | ); |
| 5483 | 5564 | |
| 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 | 5566 | const insert_block = self.builder.getInsertBlock(); |
| 5486 | 5567 | if (isByRef(inst_ty)) { |
| 5487 | 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 | 839 | pub const buildExactSDiv = LLVMBuildExactSDiv; |
| 840 | 840 | extern fn LLVMBuildExactSDiv(*const Builder, LHS: *const Value, RHS: *const Value, Name: [*:0]const u8) *const Value; |
| 841 | 841 | |
| 842 | pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation; | |
| 843 | extern fn ZigLLVMSetCurrentDebugLocation(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope) void; | |
| 842 | pub const setCurrentDebugLocation = ZigLLVMSetCurrentDebugLocation2; | |
| 843 | extern fn ZigLLVMSetCurrentDebugLocation2(builder: *const Builder, line: c_uint, column: c_uint, scope: *DIScope, inlined_at: ?*DILocation) void; | |
| 844 | 844 | |
| 845 | 845 | pub const clearCurrentDebugLocation = ZigLLVMClearCurrentDebugLocation; |
| 846 | 846 | extern fn ZigLLVMClearCurrentDebugLocation(builder: *const Builder) void; |
| ... | ... | @@ -1479,8 +1479,8 @@ pub const DISubprogram = opaque { |
| 1479 | 1479 | extern fn ZigLLVMSubprogramReplaceLinkageName(subprogram: *DISubprogram, linkage_name: *MDString) void; |
| 1480 | 1480 | }; |
| 1481 | 1481 | |
| 1482 | pub const getDebugLoc = ZigLLVMGetDebugLoc; | |
| 1483 | extern fn ZigLLVMGetDebugLoc(line: c_uint, col: c_uint, scope: *DIScope) *DILocation; | |
| 1482 | pub const getDebugLoc = ZigLLVMGetDebugLoc2; | |
| 1483 | extern fn ZigLLVMGetDebugLoc2(line: c_uint, col: c_uint, scope: *DIScope, inlined_at: ?*DILocation) *DILocation; | |
| 1484 | 1484 | |
| 1485 | 1485 | pub const DIBuilder = opaque { |
| 1486 | 1486 | pub const dispose = ZigLLVMDisposeDIBuilder; |
src/print_air.zig+8| ... | ... | @@ -242,6 +242,8 @@ const Writer = struct { |
| 242 | 242 | .constant => try w.writeConstant(s, inst), |
| 243 | 243 | .assembly => try w.writeAssembly(s, inst), |
| 244 | 244 | .dbg_stmt => try w.writeDbgStmt(s, inst), |
| 245 | ||
| 246 | .dbg_inline_begin, .dbg_inline_end => try w.writeDbgInline(s, inst), | |
| 245 | 247 | .aggregate_init => try w.writeAggregateInit(s, inst), |
| 246 | 248 | .union_init => try w.writeUnionInit(s, inst), |
| 247 | 249 | .br => try w.writeBr(s, inst), |
| ... | ... | @@ -552,6 +554,12 @@ const Writer = struct { |
| 552 | 554 | try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); |
| 553 | 555 | } |
| 554 | 556 | |
| 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 | 563 | fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| 556 | 564 | const pl_op = w.air.instructions.items(.data)[inst].pl_op; |
| 557 | 565 | try w.writeOperand(s, inst, 0, pl_op.operand); |
src/type.zig+30| ... | ... | @@ -486,6 +486,36 @@ pub const Type = extern union { |
| 486 | 486 | |
| 487 | 487 | .pointer => return self.castTag(.pointer).?.*, |
| 488 | 488 | |
| 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 | 519 | else => unreachable, |
| 490 | 520 | } |
| 491 | 521 | } |
src/zig_llvm.cpp+17| ... | ... | @@ -799,6 +799,15 @@ void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, |
| 799 | 799 | unwrap(builder)->SetCurrentDebugLocation(debug_loc); |
| 800 | 800 | } |
| 801 | 801 | |
| 802 | void 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 | ||
| 802 | 811 | void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder) { |
| 803 | 812 | unwrap(builder)->SetCurrentDebugLocation(DebugLoc()); |
| 804 | 813 | } |
| ... | ... | @@ -1025,6 +1034,14 @@ ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScop |
| 1025 | 1034 | return reinterpret_cast<ZigLLVMDILocation*>(debug_loc.get()); |
| 1026 | 1035 | } |
| 1027 | 1036 | |
| 1037 | ZigLLVMDILocation *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 | ||
| 1028 | 1045 | void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state) { |
| 1029 | 1046 | if (on_state) { |
| 1030 | 1047 | FastMathFlags fmf; |
src/zig_llvm.h+4| ... | ... | @@ -232,6 +232,8 @@ ZIG_EXTERN_C void ZigLLVMSetModuleCodeModel(LLVMModuleRef module, LLVMCodeModel |
| 232 | 232 | |
| 233 | 233 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, |
| 234 | 234 | unsigned int line, unsigned int column, struct ZigLLVMDIScope *scope); |
| 235 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation2(LLVMBuilderRef builder, unsigned int line, | |
| 236 | unsigned int column, ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at); | |
| 235 | 237 | ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder); |
| 236 | 238 | |
| 237 | 239 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block); |
| ... | ... | @@ -290,6 +292,8 @@ ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder); |
| 290 | 292 | |
| 291 | 293 | ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, |
| 292 | 294 | struct ZigLLVMDIScope *scope); |
| 295 | ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc2(unsigned line, unsigned col, | |
| 296 | ZigLLVMDIScope *scope, ZigLLVMDILocation *inlined_at); | |
| 293 | 297 | |
| 294 | 298 | ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dib, |
| 295 | 299 | LLVMValueRef storage, struct ZigLLVMDILocalVariable *var_info, |