Merge pull request #11222 from Vexu/dbg_block

stage2: add debug info for payload captures + inline function parameters
This commit is contained in:
Andrew Kelley 2022-03-19 16:05:22 -04:00 committed by GitHub
commit a318aeed9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 296 additions and 74 deletions

View File

@ -326,6 +326,10 @@ pub const Inst = struct {
/// Result type is always void.
/// Uses the `dbg_stmt` field.
dbg_stmt,
/// Marks the beginning of a semantic scope for debug info variables.
dbg_block_begin,
/// Marks the end of a semantic scope for debug info variables.
dbg_block_end,
/// 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,
@ -990,6 +994,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_block_begin,
.dbg_block_end,
.dbg_var_ptr,
.dbg_var_val,
.store,

View File

@ -2052,6 +2052,10 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
const tree = astgen.tree;
const node_tags = tree.nodes.items(.tag);
if (statements.len == 0) return;
try gz.addDbgBlockBegin();
var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
defer block_arena.deinit();
const block_arena_allocator = block_arena.allocator();
@ -2105,6 +2109,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
}
}
try gz.addDbgBlockEnd();
try genDefers(gz, parent_scope, scope, .normal_only);
try checkUsed(gz, parent_scope, scope);
}
@ -2527,6 +2533,7 @@ fn genDefers(
gz.in_defer = true;
defer gz.in_defer = prev_in_defer;
var local_val_scope: Scope.LocalVal = undefined;
try gz.addDbgBlockBegin();
const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {
const ident_name = try astgen.identAsString(payload_token);
local_val_scope = .{
@ -2537,9 +2544,11 @@ fn genDefers(
.token_src = payload_token,
.id_cat = .@"capture",
};
try gz.addDbgVar(.dbg_var_val, ident_name, err_code);
break :blk &local_val_scope.base;
};
try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node);
try gz.addDbgBlockEnd();
},
.normal_only => continue,
}
@ -2665,14 +2674,7 @@ fn varDecl(
} else .none;
const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
if (!gz.force_comptime) {
_ = try gz.add(.{ .tag = .dbg_var_val, .data = .{
.str_op = .{
.str = ident_name,
.operand = init_inst,
},
} });
}
try gz.addDbgVar(.dbg_var_val, ident_name, init_inst);
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
@ -2766,14 +2768,7 @@ fn varDecl(
else
init_inst;
if (!gz.force_comptime) {
_ = try gz.add(.{ .tag = .dbg_var_val, .data = .{
.str_op = .{
.str = ident_name,
.operand = coerced_init,
},
} });
}
try gz.addDbgVar(.dbg_var_val, ident_name, coerced_init);
const sub_scope = try block_arena.create(Scope.LocalVal);
sub_scope.* = .{
@ -2810,14 +2805,7 @@ fn varDecl(
}
const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node);
if (!gz.force_comptime) {
_ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{
.str_op = .{
.str = ident_name,
.operand = const_ptr,
},
} });
}
try gz.addDbgVar(.dbg_var_ptr, ident_name, const_ptr);
const sub_scope = try block_arena.create(Scope.LocalPtr);
sub_scope.* = .{
@ -2883,14 +2871,7 @@ fn varDecl(
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
}
if (!gz.force_comptime) {
_ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{
.str_op = .{
.str = ident_name,
.operand = var_data.alloc,
},
} });
}
try gz.addDbgVar(.dbg_var_ptr, ident_name, var_data.alloc);
const sub_scope = try block_arena.create(Scope.LocalPtr);
sub_scope.* = .{
@ -5187,6 +5168,7 @@ fn ifExpr(
var payload_val_scope: Scope.LocalVal = undefined;
try then_scope.addDbgBlockBegin();
const then_sub_scope = s: {
if (if_full.error_token != null) {
if (if_full.payload_token) |payload_token| {
@ -5209,6 +5191,7 @@ fn ifExpr(
.token_src = payload_token,
.id_cat = .@"capture",
};
try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &then_scope.base;
@ -5233,6 +5216,7 @@ fn ifExpr(
.token_src = ident_token,
.id_cat = .@"capture",
};
try then_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &then_scope.base;
@ -5244,6 +5228,7 @@ fn ifExpr(
block_scope.break_count += 1;
}
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
try then_scope.addDbgBlockEnd();
// We hold off on the break instructions as well as copying the then/else
// instructions into place until we know whether to keep store_to_block_ptr
// instructions or not.
@ -5256,6 +5241,7 @@ fn ifExpr(
src: Ast.Node.Index,
result: Zir.Inst.Ref,
} = if (else_node != 0) blk: {
try else_scope.addDbgBlockBegin();
const sub_scope = s: {
if (if_full.error_token) |error_token| {
const tag: Zir.Inst.Tag = if (payload_is_ref)
@ -5276,6 +5262,7 @@ fn ifExpr(
.token_src = error_token,
.id_cat = .@"capture",
};
try else_scope.addDbgVar(.dbg_var_val, ident_name, payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &else_scope.base;
@ -5286,6 +5273,7 @@ fn ifExpr(
block_scope.break_count += 1;
}
try checkUsed(parent_gz, &else_scope.base, sub_scope);
try else_scope.addDbgBlockEnd();
break :blk .{
.src = else_node,
.result = e,
@ -5501,6 +5489,8 @@ fn whileExpr(
then_scope.instructions_top = GenZir.unstacked_top;
defer then_scope.unstack();
var dbg_var_name: ?u32 = null;
var dbg_var_inst: Zir.Inst.Ref = undefined;
var payload_inst: Zir.Inst.Index = 0;
var payload_val_scope: Scope.LocalVal = undefined;
const then_sub_scope = s: {
@ -5527,6 +5517,8 @@ fn whileExpr(
.token_src = payload_token,
.id_cat = .@"capture",
};
dbg_var_name = ident_name;
dbg_var_inst = indexToRef(payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &then_scope.base;
@ -5552,6 +5544,8 @@ fn whileExpr(
.token_src = ident_token,
.id_cat = .@"capture",
};
dbg_var_name = ident_name;
dbg_var_inst = indexToRef(payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &then_scope.base;
@ -5562,9 +5556,14 @@ fn whileExpr(
// are no jumps to it. This happens when the last statement of a while body is noreturn
// and there are no `continue` statements.
// Tracking issue: https://github.com/ziglang/zig/issues/9185
try then_scope.addDbgBlockBegin();
if (dbg_var_name) |some| {
try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
}
if (while_full.ast.cont_expr != 0) {
_ = try expr(&loop_scope, then_sub_scope, .{ .ty = .void_type }, while_full.ast.cont_expr);
}
try then_scope.addDbgBlockEnd();
const repeat_tag: Zir.Inst.Tag = if (is_inline) .repeat_inline else .repeat;
_ = try loop_scope.addNode(repeat_tag, node);
@ -5580,9 +5579,15 @@ fn whileExpr(
// done adding instructions to loop_scope, can now stack then_scope
then_scope.instructions_top = then_scope.instructions.items.len;
if (payload_inst != 0) try then_scope.instructions.append(astgen.gpa, payload_inst);
try then_scope.addDbgBlockBegin();
if (dbg_var_name) |some| {
try then_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
}
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
try then_scope.addDbgBlockEnd();
var else_scope = parent_gz.makeSubBlock(&continue_scope.base);
defer else_scope.unstack();
@ -5592,6 +5597,7 @@ fn whileExpr(
src: Ast.Node.Index,
result: Zir.Inst.Ref,
} = if (else_node != 0) blk: {
try else_scope.addDbgBlockBegin();
const sub_scope = s: {
if (while_full.error_token) |error_token| {
const tag: Zir.Inst.Tag = if (payload_is_ref)
@ -5612,6 +5618,7 @@ fn whileExpr(
.token_src = error_token,
.id_cat = .@"capture",
};
try else_scope.addDbgVar(.dbg_var_val, ident_name, else_payload_inst);
break :s &payload_val_scope.base;
} else {
break :s &else_scope.base;
@ -5622,6 +5629,7 @@ fn whileExpr(
loop_scope.break_count += 1;
}
try checkUsed(parent_gz, &else_scope.base, sub_scope);
try else_scope.addDbgBlockEnd();
break :blk .{
.src = else_node,
.result = e,
@ -5743,6 +5751,7 @@ fn forExpr(
then_scope.markAsLoopBody(loop_scope);
defer then_scope.unstack();
try then_scope.addDbgBlockBegin();
var payload_val_scope: Scope.LocalVal = undefined;
var index_scope: Scope.LocalPtr = undefined;
const then_sub_scope = blk: {
@ -5767,6 +5776,7 @@ fn forExpr(
.token_src = ident,
.id_cat = .@"capture",
};
try then_scope.addDbgVar(.dbg_var_val, name_str_index, payload_inst);
payload_sub_scope = &payload_val_scope.base;
} else if (is_ptr) {
return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{});
@ -5793,11 +5803,13 @@ fn forExpr(
.maybe_comptime = is_inline,
.id_cat = .@"loop index capture",
};
try then_scope.addDbgVar(.dbg_var_val, index_name, index_ptr);
break :blk &index_scope.base;
};
const then_result = try expr(&then_scope, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
try then_scope.addDbgBlockEnd();
var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
defer else_scope.unstack();
@ -6016,6 +6028,8 @@ fn switchExpr(
const is_multi_case = case.ast.values.len > 1 or
(case.ast.values.len == 1 and node_tags[case.ast.values[0]] == .switch_range);
var dbg_var_name: ?u32 = null;
var dbg_var_inst: Zir.Inst.Ref = undefined;
var capture_inst: Zir.Inst.Index = 0;
var capture_val_scope: Scope.LocalVal = undefined;
const sub_scope = blk: {
@ -6075,6 +6089,8 @@ fn switchExpr(
.token_src = payload_token,
.id_cat = .@"capture",
};
dbg_var_name = capture_name;
dbg_var_inst = indexToRef(capture_inst);
break :blk &capture_val_scope.base;
};
@ -6130,8 +6146,13 @@ fn switchExpr(
defer case_scope.unstack();
if (capture_inst != 0) try case_scope.instructions.append(gpa, capture_inst);
try case_scope.addDbgBlockBegin();
if (dbg_var_name) |some| {
try case_scope.addDbgVar(.dbg_var_val, some, dbg_var_inst);
}
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_loc, case.ast.target_expr);
try checkUsed(parent_gz, &case_scope.base, sub_scope);
try case_scope.addDbgBlockEnd();
if (!parent_gz.refIsNoReturn(case_result)) {
block_scope.break_count += 1;
_ = try case_scope.addBreak(.@"break", switch_block, case_result);
@ -10829,6 +10850,45 @@ const GenZir = struct {
}
}
fn addDbgVar(gz: *GenZir, tag: Zir.Inst.Tag, name: u32, inst: Zir.Inst.Ref) !void {
if (gz.force_comptime) return;
_ = try gz.add(.{ .tag = tag, .data = .{
.str_op = .{
.str = name,
.operand = inst,
},
} });
}
fn addDbgBlockBegin(gz: *GenZir) !void {
if (gz.force_comptime) return;
_ = try gz.add(.{ .tag = .extended, .data = .{
.extended = .{ .opcode = .dbg_block_begin, .small = undefined, .operand = undefined },
} });
}
fn addDbgBlockEnd(gz: *GenZir) !void {
if (gz.force_comptime) return;
const gpa = gz.astgen.gpa;
const tags = gz.astgen.instructions.items(.tag);
const data = gz.astgen.instructions.items(.data);
const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
// remove dbg_block_begin immediately followed by dbg_block_end
if (tags[last_inst] == .extended and data[last_inst].extended.opcode == .dbg_block_begin) {
_ = gz.instructions.pop();
return;
}
const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
try gz.astgen.instructions.append(gpa, .{ .tag = .extended, .data = .{
.extended = .{ .opcode = .dbg_block_end, .small = undefined, .operand = undefined },
} });
try gz.instructions.insert(gpa, gz.instructions.items.len - 1, new_index);
}
/// Control flow does not fall through the "then" block of a loop; it continues
/// back to the while condition. This prevents `rvalue` from
/// adding an invalid store to the result location of `then_scope`.

View File

@ -316,6 +316,8 @@ fn analyzeInst(
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_block_begin,
.dbg_block_end,
.unreach,
.fence,
.ret_addr,

View File

@ -618,6 +618,8 @@ fn analyzeBodyInner(
crash_info.push();
defer crash_info.pop();
var dbg_block_begins: u32 = 0;
// We use a while(true) loop here to avoid a redundant way of breaking out of
// the loop. The only way to break out of the loop is with a `noreturn`
// instruction.
@ -792,7 +794,6 @@ fn analyzeBodyInner(
.@"resume" => try sema.zirResume(block, inst),
.@"await" => try sema.zirAwait(block, inst, false),
.await_nosuspend => try sema.zirAwait(block, inst, true),
.extended => try sema.zirExtended(block, inst),
.array_base_ptr => try sema.zirArrayBasePtr(block, inst),
.field_base_ptr => try sema.zirFieldBasePtr(block, inst),
@ -854,6 +855,55 @@ fn analyzeBodyInner(
.panic => break sema.zirPanic(block, inst),
// zig fmt: on
.extended => ext: {
const extended = datas[inst].extended;
break :ext switch (extended.opcode) {
// zig fmt: off
.func => try sema.zirFuncExtended( block, extended, inst),
.variable => try sema.zirVarExtended( block, extended),
.struct_decl => try sema.zirStructDecl( block, extended, inst),
.enum_decl => try sema.zirEnumDecl( block, extended),
.union_decl => try sema.zirUnionDecl( block, extended, inst),
.opaque_decl => try sema.zirOpaqueDecl( block, extended),
.ret_ptr => try sema.zirRetPtr( block, extended),
.ret_type => try sema.zirRetType( block, extended),
.this => try sema.zirThis( block, extended),
.ret_addr => try sema.zirRetAddr( block, extended),
.builtin_src => try sema.zirBuiltinSrc( block, extended),
.error_return_trace => try sema.zirErrorReturnTrace( block, extended),
.frame => try sema.zirFrame( block, extended),
.frame_address => try sema.zirFrameAddress( block, extended),
.alloc => try sema.zirAllocExtended( block, extended),
.builtin_extern => try sema.zirBuiltinExtern( block, extended),
.@"asm" => try sema.zirAsm( block, extended),
.typeof_peer => try sema.zirTypeofPeer( block, extended),
.compile_log => try sema.zirCompileLog( block, extended),
.add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.shl_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.c_undef => try sema.zirCUndef( block, extended),
.c_include => try sema.zirCInclude( block, extended),
.c_define => try sema.zirCDefine( block, extended),
.wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
.wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
.prefetch => try sema.zirPrefetch( block, extended),
// zig fmt: on
.dbg_block_begin => {
dbg_block_begins += 1;
try sema.zirDbgBlockBegin(block);
i += 1;
continue;
},
.dbg_block_end => {
dbg_block_begins -= 1;
try sema.zirDbgBlockEnd(block);
i += 1;
continue;
},
};
},
// Instructions that we know can *never* be noreturn based solely on
// their tag. We avoid needlessly checking if they are noreturn and
// continue the loop.
@ -1179,6 +1229,19 @@ fn analyzeBodyInner(
i += 1;
} else unreachable;
// balance out dbg_block_begins in case of early noreturn
const noreturn_inst = block.instructions.popOrNull();
while (dbg_block_begins > 0) {
dbg_block_begins -= 1;
if (block.is_comptime or sema.mod.comp.bin_file.options.strip) continue;
_ = try block.addInst(.{
.tag = .dbg_block_end,
.data = undefined,
});
}
if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
if (!wip_captures.finalized) {
try wip_captures.finalize();
block.wip_capture_scope = parent_capture_scope;
@ -1187,43 +1250,6 @@ fn analyzeBodyInner(
return result;
}
fn zirExtended(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const extended = sema.code.instructions.items(.data)[inst].extended;
switch (extended.opcode) {
// zig fmt: off
.func => return sema.zirFuncExtended( block, extended, inst),
.variable => return sema.zirVarExtended( block, extended),
.struct_decl => return sema.zirStructDecl( block, extended, inst),
.enum_decl => return sema.zirEnumDecl( block, extended),
.union_decl => return sema.zirUnionDecl( block, extended, inst),
.opaque_decl => return sema.zirOpaqueDecl( block, extended),
.ret_ptr => return sema.zirRetPtr( block, extended),
.ret_type => return sema.zirRetType( block, extended),
.this => return sema.zirThis( block, extended),
.ret_addr => return sema.zirRetAddr( block, extended),
.builtin_src => return sema.zirBuiltinSrc( block, extended),
.error_return_trace => return sema.zirErrorReturnTrace( block, extended),
.frame => return sema.zirFrame( block, extended),
.frame_address => return sema.zirFrameAddress( block, extended),
.alloc => return sema.zirAllocExtended( block, extended),
.builtin_extern => return sema.zirBuiltinExtern( block, extended),
.@"asm" => return sema.zirAsm( block, extended),
.typeof_peer => return sema.zirTypeofPeer( block, extended),
.compile_log => return sema.zirCompileLog( block, extended),
.add_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
.sub_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
.mul_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
.shl_with_overflow => return sema.zirOverflowArithmetic(block, extended, extended.opcode),
.c_undef => return sema.zirCUndef( block, extended),
.c_include => return sema.zirCInclude( block, extended),
.c_define => return sema.zirCDefine( block, extended),
.wasm_memory_size => return sema.zirWasmMemorySize( block, extended),
.wasm_memory_grow => return sema.zirWasmMemoryGrow( block, extended),
.prefetch => return sema.zirPrefetch( block, extended),
// zig fmt: on
}
}
pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) Air.Inst.Ref {
var i: usize = @enumToInt(zir_ref);
@ -4241,6 +4267,24 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
});
}
fn zirDbgBlockBegin(sema: *Sema, block: *Block) CompileError!void {
if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
_ = try block.addInst(.{
.tag = .dbg_block_begin,
.data = undefined,
});
}
fn zirDbgBlockEnd(sema: *Sema, block: *Block) CompileError!void {
if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
_ = try block.addInst(.{
.tag = .dbg_block_end,
.data = undefined,
});
}
fn zirDbgVar(
sema: *Sema,
block: *Block,
@ -4251,6 +4295,17 @@ fn zirDbgVar(
const str_op = sema.code.instructions.items(.data)[inst].str_op;
const operand = sema.resolveInst(str_op.operand);
const name = str_op.getStr(sema.code);
try sema.addDbgVar(block, operand, air_tag, name);
}
fn addDbgVar(
sema: *Sema,
block: *Block,
operand: Air.Inst.Ref,
air_tag: Air.Inst.Tag,
name: []const u8,
) CompileError!void {
const operand_ty = sema.typeOf(operand);
switch (air_tag) {
.dbg_var_ptr => {
@ -4261,7 +4316,6 @@ fn zirDbgVar(
},
else => unreachable,
}
const name = str_op.getStr(sema.code);
// Add the name to the AIR.
const name_extra_index = @intCast(u32, sema.air_extra.items.len);
@ -4817,6 +4871,25 @@ 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);
for (fn_info.param_body) |param| switch (zir_tags[param]) {
.param, .param_comptime => {
const inst_data = sema.code.instructions.items(.data)[param].pl_tok;
const extra = sema.code.extraData(Zir.Inst.Param, inst_data.payload_index);
const param_name = sema.code.nullTerminatedString(extra.data.name);
const inst = sema.inst_map.get(param).?;
try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
},
.param_anytype, .param_anytype_comptime => {
const inst_data = sema.code.instructions.items(.data)[param].str_tok;
const param_name = inst_data.get(sema.code);
const inst = sema.inst_map.get(param).?;
try sema.addDbgVar(&child_block, inst, .dbg_var_val, param_name);
},
else => continue,
};
}
const result = result: {
@ -5250,7 +5323,9 @@ fn emitDbgInline(
new_func_ty: Type,
tag: Air.Inst.Tag,
) CompileError!void {
// No change of file; no dbg_inline needed.
if (sema.mod.comp.bin_file.options.strip) return;
// Recursive inline call; 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));

View File

@ -1646,6 +1646,10 @@ pub const Inst = struct {
/// The `@prefetch` builtin.
/// `operand` is payload index to `BinNode`.
prefetch,
/// Marks the beginning of a semantic scope for debug info variables.
dbg_block_begin,
/// Marks the end of a semantic scope for debug info variables.
dbg_block_end,
pub const InstData = struct {
opcode: Extended,

View File

@ -654,6 +654,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_end,
=> try self.airDbgInline(inst),
.dbg_block_begin,
.dbg_block_end,
=> try self.airDbgBlock(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),
@ -2731,6 +2735,11 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}
fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
// TODO emit debug info lexical block
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);

View File

@ -644,6 +644,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_end,
=> try self.airDbgInline(inst),
.dbg_block_begin,
.dbg_block_end,
=> try self.airDbgBlock(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),
@ -2948,6 +2952,11 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}
fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
// TODO emit debug info lexical block
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);

View File

@ -618,6 +618,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_end,
=> try self.airDbgInline(inst),
.dbg_block_begin,
.dbg_block_end,
=> try self.airDbgBlock(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),
@ -1653,6 +1657,11 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}
fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
// TODO emit debug info lexical block
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);

View File

@ -1330,6 +1330,8 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_block_begin,
.dbg_block_end,
.dbg_var_ptr,
.dbg_var_val,
=> WValue.none,

View File

@ -735,6 +735,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
.dbg_inline_end,
=> try self.airDbgInline(inst),
.dbg_block_begin,
.dbg_block_end,
=> try self.airDbgBlock(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),
@ -3683,6 +3687,11 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, .dead, .{ .none, .none, .none });
}
fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
// TODO emit debug info lexical block
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);

View File

@ -1786,6 +1786,10 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.dbg_inline_end,
=> try airDbgInline(f, inst),
.dbg_block_begin,
.dbg_block_end,
=> CValue{ .none = {} },
.call => try airCall(f, inst, .auto),
.call_always_tail => try airCall(f, inst, .always_tail),
.call_never_tail => try airCall(f, inst, .never_tail),

View File

@ -3220,6 +3220,10 @@ pub const FuncGen = struct {
/// Stack of locations where a call was inlined.
dbg_inlined: std.ArrayListUnmanaged(DbgState) = .{},
/// Stack of `DILexicalBlock`s. dbg_block instructions cannot happend accross
/// dbg_inline instructions so no special handling there is required.
dbg_block_stack: std.ArrayListUnmanaged(*llvm.DIScope) = .{},
/// 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),
@ -3254,6 +3258,7 @@ pub const FuncGen = struct {
fn deinit(self: *FuncGen) void {
self.builder.dispose();
self.dbg_inlined.deinit(self.gpa);
self.dbg_block_stack.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
}
@ -3475,6 +3480,8 @@ pub const FuncGen = struct {
.dbg_stmt => self.airDbgStmt(inst),
.dbg_inline_begin => try self.airDbgInlineBegin(inst),
.dbg_inline_end => try self.airDbgInlineEnd(inst),
.dbg_block_begin => try self.airDbgBlockBegin(),
.dbg_block_end => try self.airDbgBlockEnd(),
.dbg_var_ptr => try self.airDbgVarPtr(inst),
.dbg_var_val => try self.airDbgVarVal(inst),
// zig fmt: on
@ -4256,6 +4263,21 @@ pub const FuncGen = struct {
return null;
}
fn airDbgBlockBegin(self: *FuncGen) !?*const llvm.Value {
const dib = self.dg.object.di_builder orelse return null;
const old_scope = self.di_scope.?;
try self.dbg_block_stack.append(self.gpa, old_scope);
const lexical_block = dib.createLexicalBlock(old_scope, self.di_file.?, self.prev_dbg_line, self.prev_dbg_column);
self.di_scope = lexical_block.toScope();
return null;
}
fn airDbgBlockEnd(self: *FuncGen) !?*const llvm.Value {
if (self.dg.object.di_builder == null) return null;
self.di_scope = self.dbg_block_stack.pop();
return null;
}
fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
const dib = self.dg.object.di_builder orelse return null;
const pl_op = self.air.instructions.items(.data)[inst].pl_op;

View File

@ -272,6 +272,8 @@ const Writer = struct {
.mul_with_overflow,
.shl_with_overflow,
=> try w.writeOverflow(s, inst),
.dbg_block_begin, .dbg_block_end => {},
}
}
@ -384,8 +386,8 @@ const Writer = struct {
}
fn writeShuffle(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
const extra = w.air.extraData(Air.Shuffle, pl_op.payload).data;
const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
const extra = w.air.extraData(Air.Shuffle, ty_pl.payload).data;
try w.writeOperand(s, inst, 0, extra.a);
try s.writeAll(", ");

View File

@ -463,6 +463,10 @@ const Writer = struct {
.builtin_src,
=> try self.writeExtNode(stream, extended),
.dbg_block_begin,
.dbg_block_end,
=> try stream.writeAll("))"),
.@"asm" => try self.writeAsm(stream, extended),
.func => try self.writeFuncExtended(stream, extended),
.variable => try self.writeVarExtended(stream, extended),

View File

@ -427,6 +427,7 @@ test "packed struct 24bits" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.cpu.arch == .wasm32) return error.SkipZigTest; // TODO
if (builtin.cpu.arch == .arm) return error.SkipZigTest; // TODO
comptime {
try expect(@sizeOf(Foo24Bits) == 4);
@ -979,6 +980,7 @@ test "tuple assigned to variable" {
test "comptime struct field" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.stage2_arch == .arm) return error.SkipZigTest; // TODO
const T = struct {
a: i32,

View File

@ -173,6 +173,7 @@ test "while with optional as condition with else" {
}
test "while with error union condition" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
@ -289,6 +290,7 @@ test "while bool 2 break statements and an else" {
}
test "while optional 2 break statements and an else" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
@ -307,6 +309,7 @@ test "while optional 2 break statements and an else" {
}
test "while error 2 break statements and an else" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO