Commit 59447e5305
Changed files (18)
src
arch
aarch64
arm
riscv64
sparc64
wasm
x86_64
Liveness
test
behavior
src/arch/aarch64/CodeGen.zig
@@ -813,10 +813,6 @@ 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),
@@ -4634,11 +4630,6 @@ 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)[@intFromEnum(inst)].pl_op;
const operand = pl_op.operand;
@@ -5066,6 +5057,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
+ // TODO emit debug info lexical block
try self.genBody(body);
// relocations for `br` instructions
src/arch/arm/CodeGen.zig
@@ -799,10 +799,6 @@ 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),
@@ -4587,11 +4583,6 @@ 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)[@intFromEnum(inst)].pl_op;
const operand = pl_op.operand;
@@ -4997,6 +4988,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
+ // TODO emit debug info lexical block
try self.genBody(body);
// relocations for `br` instructions
src/arch/riscv64/CodeGen.zig
@@ -632,10 +632,6 @@ 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),
@@ -1894,11 +1890,6 @@ 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)[@intFromEnum(inst)].pl_op;
const name = self.air.nullTerminatedString(pl_op.payload);
@@ -2084,6 +2075,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
+ // TODO emit debug info lexical block
try self.genBody(body);
for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
src/arch/sparc64/CodeGen.zig
@@ -645,10 +645,6 @@ 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),
@@ -1146,6 +1142,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
+ // TODO emit debug info lexical block
try self.genBody(body);
// relocations for `bpcc` instructions
@@ -1655,11 +1652,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
return self.finishAir(inst, result, .{ ty_op.operand, .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 airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
const mod = self.bin_file.comp.module.?;
src/arch/wasm/CodeGen.zig
@@ -1913,8 +1913,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
// TODO
.dbg_inline_begin,
.dbg_inline_end,
- .dbg_block_begin,
- .dbg_block_end,
=> func.finishAir(inst, .none, &.{}),
.dbg_var_ptr => func.airDbgVar(inst, true),
src/arch/x86_64/CodeGen.zig
@@ -2106,10 +2106,6 @@ 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),
@@ -12976,12 +12972,6 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
self.finishAirBookkeeping();
}
-fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
- _ = inst;
- // TODO emit debug info lexical block
- self.finishAirBookkeeping();
-}
-
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
const operand = pl_op.operand;
@@ -13428,6 +13418,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
const extra = self.air.extraData(Air.Block, ty_pl.payload);
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
+ // TODO emit debug info lexical block
try self.genBody(body);
var block_data = self.blocks.fetchRemove(inst).?;
src/codegen/c.zig
@@ -3268,10 +3268,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.dbg_inline_end,
=> try airDbgInline(f, inst),
- .dbg_block_begin,
- .dbg_block_end,
- => .none,
-
.call => try airCall(f, inst, .auto),
.call_always_tail => .none,
.call_never_tail => try airCall(f, inst, .never_tail),
src/codegen/llvm.zig
@@ -4768,8 +4768,6 @@ pub const FuncGen = struct {
scope: Builder.Metadata,
}) = .{},
- scope_stack: std.ArrayListUnmanaged(Builder.Metadata) = .{},
-
base_line: u32,
prev_dbg_line: c_uint,
prev_dbg_column: c_uint,
@@ -4813,7 +4811,6 @@ pub const FuncGen = struct {
fn deinit(self: *FuncGen) void {
self.wip.deinit();
- self.scope_stack.deinit(self.gpa);
self.inlined.deinit(self.gpa);
self.func_inst_table.deinit(self.gpa);
self.blocks.deinit(self.gpa);
@@ -5112,8 +5109,6 @@ pub const FuncGen = struct {
.dbg_stmt => try 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),
@@ -5131,6 +5126,19 @@ pub const FuncGen = struct {
}
}
+ fn genBodyDebugScope(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
+ if (self.wip.strip) return self.genBody(body);
+ const old_scope = self.scope;
+ self.scope = try self.dg.object.builder.debugLexicalBlock(
+ old_scope,
+ self.file,
+ self.prev_dbg_line,
+ self.prev_dbg_column,
+ );
+ try self.genBody(body);
+ self.scope = old_scope;
+ }
+
pub const CallAttr = enum {
Auto,
NeverTail,
@@ -5820,7 +5828,7 @@ pub const FuncGen = struct {
const inst_ty = self.typeOfIndex(inst);
if (inst_ty.isNoReturn(mod)) {
- try self.genBody(body);
+ try self.genBodyDebugScope(body);
return .none;
}
@@ -5836,7 +5844,7 @@ pub const FuncGen = struct {
});
defer assert(self.blocks.remove(inst));
- try self.genBody(body);
+ try self.genBodyDebugScope(body);
self.wip.cursor = .{ .block = parent_bb };
@@ -6683,26 +6691,6 @@ pub const FuncGen = struct {
return .none;
}
- fn airDbgBlockBegin(self: *FuncGen) Allocator.Error!Builder.Value {
- const o = self.dg.object;
-
- try self.scope_stack.append(self.gpa, self.scope);
-
- const old = self.scope;
- self.scope = try o.builder.debugLexicalBlock(
- old,
- self.file,
- self.prev_dbg_line,
- self.prev_dbg_column,
- );
- return .none;
- }
-
- fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
- self.scope = self.scope_stack.pop();
- return .none;
- }
-
fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.dg.object;
const mod = o.module;
@@ -7488,7 +7476,7 @@ pub const FuncGen = struct {
for (body_tail[1..]) |body_inst| {
switch (air_tags[@intFromEnum(body_inst)]) {
.ret => return true,
- .dbg_stmt, .dbg_block_end => continue,
+ .dbg_stmt => continue,
else => return false,
}
}
src/codegen/spirv.zig
@@ -2322,8 +2322,6 @@ const DeclGen = struct {
.dbg_inline_begin => return self.airDbgInlineBegin(inst),
.dbg_inline_end => return self.airDbgInlineEnd(inst),
.dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst),
- .dbg_block_begin => return,
- .dbg_block_end => return,
.unwrap_errunion_err => try self.airErrUnionErr(inst),
.unwrap_errunion_payload => try self.airErrUnionPayload(inst),
src/Liveness/Verify.zig
@@ -48,8 +48,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
- .dbg_block_begin,
- .dbg_block_end,
.fence,
.ret_addr,
.frame_addr,
src/Air.zig
@@ -443,10 +443,6 @@ 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 the `ty_fn` field.
dbg_inline_begin,
@@ -1454,8 +1450,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
- .dbg_block_begin,
- .dbg_block_end,
.dbg_var_ptr,
.dbg_var_val,
.store,
@@ -1612,8 +1606,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
.@"try",
.try_ptr,
.dbg_stmt,
- .dbg_block_begin,
- .dbg_block_end,
.dbg_inline_begin,
.dbg_inline_end,
.dbg_var_ptr,
src/AstGen.zig
@@ -2445,8 +2445,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
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();
@@ -2518,8 +2516,6 @@ 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);
}
@@ -2804,8 +2800,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
- .dbg_block_begin,
- .dbg_block_end,
.ensure_result_used,
.ensure_result_non_error,
.ensure_err_union_payload_void,
@@ -3026,7 +3020,6 @@ fn deferStmt(
var opt_remapped_err_code: Zir.Inst.OptionalIndex = .none;
const have_err_code = scope_tag == .defer_error and payload_token != 0;
const sub_scope = if (!have_err_code) &defer_gen.base else blk: {
- try gz.addDbgBlockBegin();
const ident_name = try gz.astgen.identAsString(payload_token);
const remapped_err_code: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
opt_remapped_err_code = remapped_err_code.toOptional();
@@ -3052,7 +3045,6 @@ fn deferStmt(
};
_ = try unusedResultExpr(&defer_gen, sub_scope, expr_node);
try checkUsed(gz, scope, sub_scope);
- if (have_err_code) try gz.addDbgBlockEnd();
_ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);
// We must handle ref_table for remapped_err_code manually.
@@ -6245,7 +6237,6 @@ fn ifExpr(
var payload_val_scope: Scope.LocalVal = undefined;
- try then_scope.addDbgBlockBegin();
const then_node = if_full.ast.then_expr;
const then_sub_scope = s: {
if (if_full.error_token != null) {
@@ -6305,7 +6296,6 @@ fn ifExpr(
const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_info, then_node);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
if (!then_scope.endsWithNoReturn()) {
- try then_scope.addDbgBlockEnd();
_ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, then_node);
}
@@ -6319,7 +6309,6 @@ fn ifExpr(
const else_node = if_full.ast.else_expr;
if (else_node != 0) {
- try else_scope.addDbgBlockBegin();
const sub_scope = s: {
if (if_full.error_token) |error_token| {
const tag: Zir.Inst.Tag = if (payload_is_ref)
@@ -6347,7 +6336,6 @@ fn ifExpr(
}
};
const else_result = try expr(&else_scope, sub_scope, block_scope.break_result_info, else_node);
- try else_scope.addDbgBlockEnd();
if (!else_scope.endsWithNoReturn()) {
// As our last action before the break, "pop" the error trace if needed
if (do_err_trace)
@@ -6579,7 +6567,6 @@ fn whileExpr(
// done adding instructions to loop_scope, can now stack then_scope
then_scope.instructions_top = then_scope.instructions.items.len;
- try then_scope.addDbgBlockBegin();
const then_node = while_full.ast.then_expr;
if (opt_payload_inst.unwrap()) |payload_inst| {
try then_scope.instructions.append(astgen.gpa, payload_inst);
@@ -6593,7 +6580,6 @@ fn whileExpr(
if (while_full.ast.cont_expr != 0) {
_ = try unusedResultExpr(&then_scope, then_sub_scope, while_full.ast.cont_expr);
}
- try then_scope.addDbgBlockEnd();
continue_scope.instructions_top = continue_scope.instructions.items.len;
_ = try unusedResultExpr(&continue_scope, &continue_scope.base, then_node);
@@ -6610,7 +6596,6 @@ fn whileExpr(
const else_node = while_full.ast.else_expr;
if (else_node != 0) {
- try else_scope.addDbgBlockBegin();
const sub_scope = s: {
if (while_full.error_token) |error_token| {
const tag: Zir.Inst.Tag = if (payload_is_ref)
@@ -6647,7 +6632,6 @@ fn whileExpr(
}
try checkUsed(parent_gz, &else_scope.base, sub_scope);
- try else_scope.addDbgBlockEnd();
if (!else_scope.endsWithNoReturn()) {
_ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
}
@@ -6849,8 +6833,6 @@ fn forExpr(
var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
defer then_scope.unstack();
- try then_scope.addDbgBlockBegin();
-
const capture_scopes = try gpa.alloc(Scope.LocalVal, for_full.ast.inputs.len);
defer gpa.free(capture_scopes);
@@ -6916,7 +6898,6 @@ fn forExpr(
_ = try addEnsureResult(&then_scope, then_result, then_node);
try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
- try then_scope.addDbgBlockEnd();
const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
@@ -7149,8 +7130,6 @@ fn switchExprErrUnion(
case_scope.instructions_top = parent_gz.instructions.items.len;
defer case_scope.unstack();
- try case_scope.addDbgBlockBegin();
-
const unwrap_payload_tag: Zir.Inst.Tag = if (payload_is_ref)
.err_union_payload_unsafe_ptr
else
@@ -7173,7 +7152,6 @@ fn switchExprErrUnion(
catch_or_if_node,
),
};
- try case_scope.addDbgBlockEnd();
_ = try case_scope.addBreakWithSrcNode(
.@"break",
switch_block,
@@ -7184,7 +7162,6 @@ fn switchExprErrUnion(
.@"if" => {
var payload_val_scope: Scope.LocalVal = undefined;
- try case_scope.addDbgBlockBegin();
const then_node = if_full.ast.then_expr;
const then_sub_scope = s: {
assert(if_full.error_token != null);
@@ -7228,7 +7205,6 @@ fn switchExprErrUnion(
);
try checkUsed(parent_gz, &case_scope.base, then_sub_scope);
if (!case_scope.endsWithNoReturn()) {
- try case_scope.addDbgBlockEnd();
_ = try case_scope.addBreakWithSrcNode(
.@"break",
switch_block,
@@ -7407,7 +7383,6 @@ fn switchExprErrUnion(
if (do_err_trace and nodeMayAppendToErrorTrace(tree, operand_node))
_ = try case_scope.addSaveErrRetIndex(.always);
- try case_scope.addDbgBlockBegin();
if (dbg_var_name != .empty) {
try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
}
@@ -7421,7 +7396,6 @@ fn switchExprErrUnion(
try case_scope.addDbgVar(.dbg_var_val, err_name, err_inst.toRef());
any_uses_err_capture = true;
}
- try case_scope.addDbgBlockEnd();
if (!parent_gz.refIsNoReturn(case_result)) {
if (do_err_trace)
@@ -7868,7 +7842,6 @@ fn switchExpr(
case_scope.instructions_top = parent_gz.instructions.items.len;
defer case_scope.unstack();
- try case_scope.addDbgBlockBegin();
if (dbg_var_name != .empty) {
try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
}
@@ -7878,7 +7851,6 @@ fn switchExpr(
const target_expr_node = case.ast.target_expr;
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);
try checkUsed(parent_gz, &case_scope.base, sub_scope);
- try case_scope.addDbgBlockEnd();
if (!parent_gz.refIsNoReturn(case_result)) {
_ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);
}
@@ -13165,29 +13137,6 @@ const GenZir = struct {
},
} });
}
-
- fn addDbgBlockBegin(gz: *GenZir) !void {
- if (gz.is_comptime) return;
-
- _ = try gz.add(.{ .tag = .dbg_block_begin, .data = undefined });
- }
-
- fn addDbgBlockEnd(gz: *GenZir) !void {
- if (gz.is_comptime) return;
- const gpa = gz.astgen.gpa;
-
- const tags = gz.astgen.instructions.items(.tag);
- const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
- // remove dbg_block_begin immediately followed by dbg_block_end
- if (tags[@intFromEnum(last_inst)] == .dbg_block_begin) {
- _ = gz.instructions.pop();
- return;
- }
-
- const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
- try gz.astgen.instructions.append(gpa, .{ .tag = .dbg_block_end, .data = undefined });
- try gz.instructions.append(gpa, new_index);
- }
};
/// This can only be for short-lived references; the memory becomes invalidated
src/Liveness.zig
@@ -329,8 +329,6 @@ pub fn categorizeOperand(
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
- .dbg_block_begin,
- .dbg_block_end,
.unreach,
.ret_addr,
.frame_addr,
@@ -967,8 +965,6 @@ fn analyzeInst(
.dbg_stmt,
.dbg_inline_begin,
.dbg_inline_end,
- .dbg_block_begin,
- .dbg_block_end,
.fence,
.ret_addr,
.frame_addr,
src/print_air.zig
@@ -319,8 +319,6 @@ const Writer = struct {
.cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
.vector_store_elem => try w.writeVectorStoreElem(s, inst),
- .dbg_block_begin, .dbg_block_end => {},
-
.work_item_id,
.work_group_size,
.work_group_id,
src/print_zir.zig
@@ -510,10 +510,6 @@ const Writer = struct {
.dbg_stmt => try self.writeDbgStmt(stream, inst),
- .dbg_block_begin,
- .dbg_block_end,
- => try stream.writeAll(")"),
-
.closure_get => try self.writeInstNode(stream, inst),
.@"defer" => try self.writeDefer(stream, inst),
src/Sema.zig
@@ -364,6 +364,12 @@ pub const Block = struct {
c_import_buf: ?*std.ArrayList(u8) = null,
+ /// If not `null`, this boolean is set when a `dbg_var_ptr` or `dbg_var_val`
+ /// instruction is emitted. It signals that the innermost lexically
+ /// enclosing `block`/`block_inline` should be translated into a real AIR
+ /// `block` in order for codegen to match lexical scoping for debug vars.
+ need_debug_scope: ?*bool = null,
+
const ComptimeReason = union(enum) {
c_import: struct {
block: *Block,
@@ -482,6 +488,7 @@ pub const Block = struct {
.float_mode = parent.float_mode,
.c_import_buf = parent.c_import_buf,
.error_return_trace_index = parent.error_return_trace_index,
+ .need_debug_scope = parent.need_debug_scope,
};
}
@@ -986,8 +993,6 @@ 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.
@@ -1332,18 +1337,6 @@ fn analyzeBodyInner(
i += 1;
continue;
},
- .dbg_block_begin => {
- dbg_block_begins += 1;
- try zirDbgBlockBegin(block);
- i += 1;
- continue;
- },
- .dbg_block_end => {
- dbg_block_begins -= 1;
- try zirDbgBlockEnd(block);
- i += 1;
- continue;
- },
.ensure_err_union_payload_void => {
try sema.zirEnsureErrUnionPayloadVoid(block, inst);
i += 1;
@@ -1641,10 +1634,12 @@ fn analyzeBodyInner(
const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
const gpa = sema.gpa;
- const opt_break_data = b: {
+ const opt_break_data, const need_debug_scope = b: {
// Create a temporary child block so that this inline block is properly
// labeled for any .restore_err_ret_index instructions
var child_block = block.makeSubBlock();
+ var need_debug_scope = false;
+ child_block.need_debug_scope = &need_debug_scope;
// If this block contains a function prototype, we need to reset the
// current list of parameters and restore it later.
@@ -1665,7 +1660,11 @@ fn analyzeBodyInner(
child_block.instructions = block.instructions;
defer block.instructions = child_block.instructions;
- break :b try sema.analyzeBodyBreak(&child_block, inline_body);
+ const result = try sema.analyzeBodyBreak(&child_block, inline_body);
+ if (need_debug_scope) {
+ _ = try sema.ensurePostHoc(block, inst);
+ }
+ break :b .{ result, need_debug_scope };
};
// A runtime conditional branch that needs a post-hoc block to be
@@ -1686,28 +1685,22 @@ fn analyzeBodyInner(
// since it crosses a runtime branch.
// It may pass through our currently being analyzed block_inline or it
// may point directly to it. In the latter case, this modifies the
- // block that we are about to look up in the post_hoc_blocks map below.
+ // block that we looked up in the post_hoc_blocks map above.
try sema.addRuntimeBreak(block, break_data);
- } else {
- // Here the comptime control flow ends with noreturn; however
- // we have runtime control flow continuing after this block.
- // This branch is therefore handled by the `i += 1; continue;`
- // logic below.
}
try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]);
block.instructions.items.len = block_index;
- const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges);
+ const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges, need_debug_scope);
{
// Destroy the ad-hoc block entry so that it does not interfere with
// the next iteration of comptime control flow, if any.
labeled_block.destroy(gpa);
assert(sema.post_hoc_blocks.remove(new_block_inst));
}
- map.putAssumeCapacity(inst, block_result);
- i += 1;
- continue;
+
+ break :blk block_result;
}
const break_data = opt_break_data orelse break always_noreturn;
@@ -1860,19 +1853,6 @@ fn analyzeBodyInner(
i += 1;
};
- // balance out dbg_block_begins in case of early noreturn
- if (!block.is_comptime and !block.ownerModule().strip) {
- const noreturn_inst = block.instructions.popOrNull();
- while (dbg_block_begins > 0) {
- dbg_block_begins -= 1;
- _ = try block.addInst(.{
- .tag = .dbg_block_end,
- .data = undefined,
- });
- }
- if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
- }
-
// We may have overwritten the capture scope due to a `repeat` instruction where
// the body had a capture; restore it now.
block.wip_capture_scope = parent_capture_scope;
@@ -5757,7 +5737,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
);
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(loop_block.instructions.items));
}
- return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
+ return sema.analyzeBlockBody(parent_block, src, &child_block, merges, false);
}
fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -5945,13 +5925,31 @@ fn resolveBlockBody(
if (child_block.is_comptime) {
return sema.resolveBody(child_block, body, body_inst);
} else {
+ var need_debug_scope = false;
+ child_block.need_debug_scope = &need_debug_scope;
if (sema.analyzeBodyInner(child_block, body)) |_| {
- return sema.analyzeBlockBody(parent_block, src, child_block, merges);
+ return sema.analyzeBlockBody(parent_block, src, child_block, merges, need_debug_scope);
} else |err| switch (err) {
error.ComptimeBreak => {
// Comptime control flow is happening, however child_block may still contain
// runtime instructions which need to be copied to the parent block.
- try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
+ if (need_debug_scope and child_block.instructions.items.len > 0) {
+ // We need a runtime block for scoping reasons.
+ _ = try child_block.addBr(merges.block_inst, .void_value);
+ try parent_block.instructions.append(sema.gpa, merges.block_inst);
+ try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len +
+ child_block.instructions.items.len);
+ sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
+ .ty = .void_type,
+ .payload = sema.addExtraAssumeCapacity(Air.Block{
+ .body_len = @intCast(child_block.instructions.items.len),
+ }),
+ } };
+ sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
+ } else {
+ // We can copy instructions directly to the parent block.
+ try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
+ }
const break_inst = sema.comptime_break_inst;
const break_data = sema.code.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
@@ -5973,6 +5971,7 @@ fn analyzeBlockBody(
src: LazySrcLoc,
child_block: *Block,
merges: *Block.Merges,
+ need_debug_scope: bool,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -5987,25 +5986,57 @@ fn analyzeBlockBody(
if (merges.results.items.len == 0) {
// No need for a block instruction. We can put the new instructions
// directly into the parent block.
+ if (need_debug_scope) {
+ // The code following this block is unreachable, as the block has no
+ // merges, so we don't necessarily need to emit this as an AIR block.
+ // However, we need a block *somewhere* to make the scoping correct,
+ // so forward this request to the parent block.
+ if (parent_block.need_debug_scope) |ptr| ptr.* = true;
+ }
try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
return child_block.instructions.items[child_block.instructions.items.len - 1].toRef();
}
if (merges.results.items.len == 1) {
- const last_inst_index = child_block.instructions.items.len - 1;
- const last_inst = child_block.instructions.items[last_inst_index];
- if (sema.getBreakBlock(last_inst)) |br_block| {
- if (br_block == merges.block_inst) {
- // No need for a block instruction. We can put the new instructions directly
- // into the parent block. Here we omit the break instruction.
- const without_break = child_block.instructions.items[0..last_inst_index];
- try parent_block.instructions.appendSlice(gpa, without_break);
- return merges.results.items[0];
- }
+ // If the `break` is trailing, we may be able to elide the AIR block here
+ // by appending the new instructions directly to the parent block.
+ if (!need_debug_scope) {
+ const last_inst_index = child_block.instructions.items.len - 1;
+ const last_inst = child_block.instructions.items[last_inst_index];
+ if (sema.getBreakBlock(last_inst)) |br_block| {
+ if (br_block == merges.block_inst) {
+ // Great, the last instruction is the break! Put the instructions
+ // directly into the parent block.
+ try parent_block.instructions.appendSlice(gpa, child_block.instructions.items[0..last_inst_index]);
+ return merges.results.items[0];
+ }
+ }
+ }
+ // Okay, we need a runtime block. If the value is comptime-known, the
+ // block should just return void, and we return the merge result
+ // directly. Otherwise, we can defer to the logic below.
+ if (try sema.resolveValue(merges.results.items[0])) |result_val| {
+ // Create a block containing all instruction from the body.
+ try parent_block.instructions.append(gpa, merges.block_inst);
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
+ child_block.instructions.items.len);
+ sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
+ .ty = .void_type,
+ .payload = sema.addExtraAssumeCapacity(Air.Block{
+ .body_len = @intCast(child_block.instructions.items.len),
+ }),
+ } };
+ sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
+ // Rewrite the break to just give value {}; the value is
+ // comptime-known and will be returned directly.
+ sema.air_instructions.items(.data)[@intFromEnum(merges.br_list.items[0])].br.operand = .void_value;
+ return Air.internedToRef(result_val.toIntern());
}
}
// It is impossible to have the number of results be > 1 in a comptime scope.
assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
+ // Note that we'll always create an AIR block here, so `need_debug_scope` is irrelevant.
+
// Need to set the type and emit the Block instruction. This allows machine code generation
// to emit a jump instruction to after the block when it encounters the break.
try parent_block.instructions.append(gpa, merges.block_inst);
@@ -6383,24 +6414,6 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
});
}
-fn zirDbgBlockBegin(block: *Block) CompileError!void {
- if (block.is_comptime or block.ownerModule().strip) return;
-
- _ = try block.addInst(.{
- .tag = .dbg_block_begin,
- .data = undefined,
- });
-}
-
-fn zirDbgBlockEnd(block: *Block) CompileError!void {
- if (block.is_comptime or block.ownerModule().strip) return;
-
- _ = try block.addInst(.{
- .tag = .dbg_block_end,
- .data = undefined,
- });
-}
-
fn zirDbgVar(
sema: *Sema,
block: *Block,
@@ -6432,6 +6445,15 @@ fn addDbgVar(
if (try sema.typeRequiresComptime(val_ty)) return;
if (!(try sema.typeHasRuntimeBits(val_ty))) return;
+ // To ensure the lexical scoping is known to backends, this alloc must be
+ // within a real runtime block. We set a flag which communicates information
+ // to the closest lexically enclosing block:
+ // * If it is a `block_inline`, communicates to logic in `analyzeBodyInner`
+ // to create a post-hoc block.
+ // * Otherwise, communicates to logic in `resolveBlockBody` to create a
+ // real `block` instruction.
+ if (block.need_debug_scope) |ptr| ptr.* = true;
+
try sema.queueFullTypeResolution(operand_ty);
// Add the name to the AIR.
@@ -7585,7 +7607,7 @@ fn analyzeCall(
error.ComptimeReturn => break :result inlining.comptime_result,
else => |e| return e,
};
- break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
+ break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges, false);
};
if (!is_comptime_call and !block.is_typeof and
@@ -11528,7 +11550,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(true_instructions));
sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
- return sema.analyzeBlockBody(block, main_src, &child_block, merges);
+ return sema.analyzeBlockBody(block, main_src, &child_block, merges, false);
}
fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
@@ -12150,7 +12172,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
false,
);
- return sema.analyzeBlockBody(block, src, &child_block, merges);
+ return sema.analyzeBlockBody(block, src, &child_block, merges, false);
}
const SpecialProng = struct {
@@ -13163,8 +13185,6 @@ fn validateErrSetSwitch(
const tags = sema.code.instructions.items(.tag);
const datas = sema.code.instructions.items(.data);
for (else_case.body) |else_inst| switch (tags[@intFromEnum(else_inst)]) {
- .dbg_block_begin,
- .dbg_block_end,
.dbg_stmt,
.dbg_var_val,
.ret_type,
@@ -13416,8 +13436,6 @@ fn maybeErrorUnwrap(
.@"unreachable" => if (!block.wantSafety()) return false,
.err_union_code => if (!allow_err_code_inst) return false,
.save_err_ret_index,
- .dbg_block_begin,
- .dbg_block_end,
.dbg_stmt,
.str,
.as_node,
@@ -13430,10 +13448,7 @@ fn maybeErrorUnwrap(
for (body) |inst| {
const air_inst = switch (tags[@intFromEnum(inst)]) {
- .dbg_block_begin,
- .dbg_block_end,
- .err_union_code,
- => continue,
+ .err_union_code => continue,
.dbg_stmt => {
try sema.zirDbgStmt(block, inst);
continue;
@@ -13499,8 +13514,6 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I
const tags = sema.code.instructions.items(.tag);
const inst = for (body) |inst| {
switch (tags[@intFromEnum(inst)]) {
- .dbg_block_begin,
- .dbg_block_end,
.dbg_stmt,
.save_err_ret_index,
=> {},
@@ -19092,55 +19105,64 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
return try_inst;
}
+fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*LabeledBlock {
+ const gop = sema.inst_map.getOrPutAssumeCapacity(dest_block);
+ if (gop.found_existing) existing: {
+ // This may be a *result* from an earlier iteration of an inline loop.
+ // In this case, there will not be a post-hoc block entry, and we can
+ // continue with the logic below.
+ const new_block_inst = gop.value_ptr.*.toIndex() orelse break :existing;
+ return sema.post_hoc_blocks.get(new_block_inst) orelse break :existing;
+ }
+
+ try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
+
+ const new_block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
+ gop.value_ptr.* = new_block_inst.toRef();
+ try sema.air_instructions.append(sema.gpa, .{
+ .tag = .block,
+ .data = undefined,
+ });
+ const labeled_block = try sema.gpa.create(LabeledBlock);
+ labeled_block.* = .{
+ .label = .{
+ .zir_block = dest_block,
+ .merges = .{
+ .src_locs = .{},
+ .results = .{},
+ .br_list = .{},
+ .block_inst = new_block_inst,
+ },
+ },
+ .block = .{
+ .parent = block,
+ .sema = sema,
+ .src_decl = block.src_decl,
+ .namespace = block.namespace,
+ .wip_capture_scope = block.wip_capture_scope,
+ .instructions = .{},
+ .label = &labeled_block.label,
+ .inlining = block.inlining,
+ .is_comptime = block.is_comptime,
+ },
+ };
+ sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
+ return labeled_block;
+}
+
// A `break` statement is inside a runtime condition, but trying to
// break from an inline loop. In such case we must convert it to
// a runtime break.
fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void {
- const gop = sema.inst_map.getOrPutAssumeCapacity(break_data.block_inst);
- const labeled_block = if (!gop.found_existing) blk: {
- try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
-
- const new_block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
- gop.value_ptr.* = new_block_inst.toRef();
- try sema.air_instructions.append(sema.gpa, .{
- .tag = .block,
- .data = undefined,
- });
- const labeled_block = try sema.gpa.create(LabeledBlock);
- labeled_block.* = .{
- .label = .{
- .zir_block = break_data.block_inst,
- .merges = .{
- .src_locs = .{},
- .results = .{},
- .br_list = .{},
- .block_inst = new_block_inst,
- },
- },
- .block = .{
- .parent = child_block,
- .sema = sema,
- .src_decl = child_block.src_decl,
- .namespace = child_block.namespace,
- .wip_capture_scope = child_block.wip_capture_scope,
- .instructions = .{},
- .label = &labeled_block.label,
- .inlining = child_block.inlining,
- .is_comptime = child_block.is_comptime,
- },
- };
- sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
- break :blk labeled_block;
- } else blk: {
- const new_block_inst = gop.value_ptr.*.toIndex().?;
- const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?;
- break :blk labeled_block;
- };
+ const labeled_block = try sema.ensurePostHoc(child_block, break_data.block_inst);
const operand = try sema.resolveInst(break_data.operand);
const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand);
+
try labeled_block.label.merges.results.append(sema.gpa, operand);
try labeled_block.label.merges.br_list.append(sema.gpa, br_ref.toIndex().?);
+ try labeled_block.label.merges.src_locs.append(sema.gpa, null);
+
labeled_block.block.runtime_index.increment();
if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) {
labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop;
@@ -19481,8 +19503,10 @@ fn analyzeRet(
return error.ComptimeReturn;
}
// We are inlining a function call; rewrite the `ret` as a `break`.
+ const br_inst = try block.addBr(inlining.merges.block_inst, operand);
try inlining.merges.results.append(sema.gpa, operand);
- _ = try block.addBr(inlining.merges.block_inst, operand);
+ try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?);
+ try inlining.merges.src_locs.append(sema.gpa, operand_src);
return always_noreturn;
} else if (block.is_comptime) {
return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});
src/Zir.zig
@@ -392,10 +392,6 @@ pub const Inst = struct {
/// Same as `dbg_var_ptr` but the local is always a const and the operand
/// is the local's value.
dbg_var_val,
- /// 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,
/// Uses a name to identify a Decl and takes a pointer to it.
/// Uses the `str_tok` union field.
decl_ref,
@@ -1107,8 +1103,6 @@ pub const Inst = struct {
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
- .dbg_block_begin,
- .dbg_block_end,
.decl_ref,
.decl_val,
.load,
@@ -1335,8 +1329,6 @@ pub const Inst = struct {
.dbg_stmt,
.dbg_var_ptr,
.dbg_var_val,
- .dbg_block_begin,
- .dbg_block_end,
.ensure_result_used,
.ensure_result_non_error,
.ensure_err_union_payload_void,
@@ -1663,8 +1655,6 @@ pub const Inst = struct {
.dbg_stmt = .dbg_stmt,
.dbg_var_ptr = .str_op,
.dbg_var_val = .str_op,
- .dbg_block_begin = .tok,
- .dbg_block_end = .tok,
.decl_ref = .str_tok,
.decl_val = .str_tok,
.load = .un_node,
test/behavior/eval.zig
@@ -1714,3 +1714,21 @@ test "const with specified type initialized with typed array is comptime-known"
comptime assert(x[1] == 2);
comptime assert(x[2] == 3);
}
+
+test "block with comptime-known result but possible runtime exit is comptime-known" {
+ var t: bool = true;
+ _ = &t;
+
+ const a: comptime_int = a: {
+ if (!t) return error.TestFailed;
+ break :a 123;
+ };
+
+ const b: comptime_int = b: {
+ if (t) break :b 456;
+ return error.TestFailed;
+ };
+
+ comptime assert(a == 123);
+ comptime assert(b == 456);
+}