Skip to content

Add debug info for inlined calls #11177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ const std = @import("std");
const builtin = @import("builtin");
const Value = @import("value.zig").Value;
const Type = @import("type.zig").Type;
const Module = @import("Module.zig");
const assert = std.debug.assert;
const Air = @This();

Expand Down Expand Up @@ -327,6 +326,12 @@ pub const Inst = struct {
/// Result type is always void.
/// Uses the `dbg_stmt` field.
dbg_stmt,
/// Marks the start of an inline call.
/// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
dbg_inline_begin,
/// Marks the end of an inline call.
/// Uses `ty_pl` with the payload being the index of a Value.Function in air.values.
dbg_inline_end,
/// Marks the beginning of a local variable. The operand is a pointer pointing
/// to the storage for the variable. The local may be a const or a var.
/// Result type is always void.
Expand Down Expand Up @@ -971,6 +976,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {

.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
.dbg_var_val,
.store,
Expand Down
17 changes: 17 additions & 0 deletions src/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -5148,6 +5148,7 @@ fn ifExpr(
else
false;

try emitDbgNode(parent_gz, if_full.ast.cond_expr);
const cond: struct {
inst: Zir.Inst.Ref,
bool_bit: Zir.Inst.Ref,
Expand Down Expand Up @@ -5458,6 +5459,7 @@ fn whileExpr(
else
false;

try emitDbgNode(parent_gz, while_full.ast.cond_expr);
const cond: struct {
inst: Zir.Inst.Ref,
bool_bit: Zir.Inst.Ref,
Expand Down Expand Up @@ -5678,6 +5680,8 @@ fn forExpr(
else
false;

try emitDbgNode(parent_gz, for_full.ast.cond_expr);

const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
const array_ptr = try expr(parent_gz, scope, cond_rl, for_full.ast.cond_expr);
const len = try parent_gz.addUnNode(.indexable_ptr_len, array_ptr, for_full.ast.cond_expr);
Expand Down Expand Up @@ -7810,6 +7814,19 @@ fn callExpr(
break :blk .auto;
};

{
astgen.advanceSourceCursor(astgen.tree.tokens.items(.start)[call.ast.lparen]);
const line = astgen.source_line - gz.decl_line;
const column = astgen.source_column;

_ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
.dbg_stmt = .{
.line = line,
.column = column,
},
} });
}

assert(callee != .none);
assert(node != 0);

Expand Down
2 changes: 2 additions & 0 deletions src/Liveness.zig
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,8 @@ fn analyzeInst(
.const_ty,
.breakpoint,
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.unreach,
.fence,
.ret_addr,
Expand Down
37 changes: 37 additions & 0 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4639,6 +4639,10 @@ fn analyzeCall(
// comptime state.
var should_memoize = true;

var new_fn_info = module_fn.owner_decl.ty.fnInfo();
new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len);
new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr;

// This will have return instructions analyzed as break instructions to
// the block_inst above. Here we are performing "comptime/inline semantic analysis"
// for a function body, which means we must map the parameter ZIR instructions to
Expand All @@ -4658,6 +4662,7 @@ fn analyzeCall(
const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
const param_ty_inst = try sema.resolveBody(&child_block, param_body, inst);
const param_ty = try sema.analyzeAsType(&child_block, param_src, param_ty_inst);
new_fn_info.param_types[arg_i] = param_ty;
const arg_src = call_src; // TODO: better source location
const casted_arg = try sema.coerce(&child_block, param_ty, uncasted_args[arg_i], arg_src);
try sema.inst_map.putNoClobber(gpa, inst, casted_arg);
Expand Down Expand Up @@ -4685,6 +4690,7 @@ fn analyzeCall(
.param_anytype, .param_anytype_comptime => {
// No coercion needed.
const uncasted_arg = uncasted_args[arg_i];
new_fn_info.param_types[arg_i] = sema.typeOf(uncasted_arg);
try sema.inst_map.putNoClobber(gpa, inst, uncasted_arg);

if (is_comptime_call) {
Expand Down Expand Up @@ -4735,6 +4741,7 @@ fn analyzeCall(
}
break :blk bare_return_type;
};
new_fn_info.return_type = fn_ret_ty;
const parent_fn_ret_ty = sema.fn_ret_ty;
sema.fn_ret_ty = fn_ret_ty;
defer sema.fn_ret_ty = parent_fn_ret_ty;
Expand All @@ -4757,6 +4764,11 @@ fn analyzeCall(
}
}

const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
if (!is_comptime_call) {
try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
}

const result = result: {
sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
error.ComptimeReturn => break :result inlining.comptime_result,
Expand All @@ -4771,6 +4783,10 @@ fn analyzeCall(
break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
};

if (!is_comptime_call) {
try sema.emitDbgInline(block, module_fn, parent_func.?, parent_func.?.owner_decl.ty, .dbg_inline_end);
}

if (should_memoize and is_comptime_call) {
const result_val = try sema.resolveConstMaybeUndefVal(block, call_src, result);

Expand Down Expand Up @@ -5175,6 +5191,27 @@ fn instantiateGenericCall(
return func_inst;
}

fn emitDbgInline(
sema: *Sema,
block: *Block,
old_func: *Module.Fn,
new_func: *Module.Fn,
new_func_ty: Type,
tag: Air.Inst.Tag,
) CompileError!void {
// No change of file; no dbg_inline needed.
if (old_func == new_func) return;

try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func));
_ = try block.addInst(.{
.tag = tag,
.data = .{ .ty_pl = .{
.ty = try sema.addType(new_func_ty),
.payload = @intCast(u32, sema.air_values.items.len - 1),
} },
});
}

fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
_ = block;
const tracy = trace(@src());
Expand Down
12 changes: 12 additions & 0 deletions src/arch/aarch64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),

.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),

.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
Expand Down Expand Up @@ -2715,6 +2719,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}

fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change
_ = function;
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}

fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
Expand Down
12 changes: 12 additions & 0 deletions src/arch/arm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),

.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),

.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
Expand Down Expand Up @@ -2835,6 +2839,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}

fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change
_ = function;
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}

fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
Expand Down
12 changes: 12 additions & 0 deletions src/arch/riscv64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),

.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),

.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
Expand Down Expand Up @@ -1640,6 +1644,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}

fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change
_ = function;
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}

fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
Expand Down
2 changes: 2 additions & 0 deletions src/arch/wasm/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1227,6 +1227,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {

// TODO
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
.dbg_var_val,
=> WValue.none,
Expand Down
12 changes: 12 additions & 0 deletions src/arch/x86_64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_var_val,
=> try self.airDbgVar(inst),

.dbg_inline_begin,
.dbg_inline_end,
=> try self.airDbgInline(inst),

.call => try self.airCall(inst, .auto),
.call_always_tail => try self.airCall(inst, .always_tail),
.call_never_tail => try self.airCall(inst, .never_tail),
Expand Down Expand Up @@ -3670,6 +3674,14 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAirBookkeeping();
}

fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
const function = self.air.values[ty_pl.payload].castTag(.function).?.data;
// TODO emit debug info for function change
_ = function;
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}

fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
Expand Down
12 changes: 12 additions & 0 deletions src/codegen/c.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.dbg_var_val,
=> try airDbgVar(f, inst),

.dbg_inline_begin,
.dbg_inline_end,
=> try airDbgInline(f, inst),

.call => try airCall(f, inst, .auto),
.call_always_tail => try airCall(f, inst, .always_tail),
.call_never_tail => try airCall(f, inst, .never_tail),
Expand Down Expand Up @@ -2660,6 +2664,14 @@ fn airDbgStmt(f: *Function, inst: Air.Inst.Index) !CValue {
return CValue.none;
}

fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue {
const ty_pl = f.air.instructions.items(.data)[inst].ty_pl;
const writer = f.object.writer();
const function = f.air.values[ty_pl.payload].castTag(.function).?.data;
try writer.print("/* dbg func:{s} */\n", .{function.owner_decl.name});
return CValue.none;
}

fn airDbgVar(f: *Function, inst: Air.Inst.Index) !CValue {
const pl_op = f.air.instructions.items(.data)[inst].pl_op;
const name = f.air.nullTerminatedString(pl_op.payload);
Expand Down
Loading