authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-24 04:29:42+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-26 13:20:45+00:00
log59447e53056d8fb6682b79accccffa176d0b44d1
treefef7809520fc67d519150592ea479576c9b289ca
parent031f23117dadd84b1e7189ee5b0f712eeb23ca1e
signaturelock-open Commit is signed but in an unrecognized format.

compiler: decide dbg_var scoping based on AIR blocks

This commit eliminates the `dbg_block_{begin,end}` instructions from both ZIR and AIR. Instead, lexical scoping of `dbg_var_{ptr,val}` instructions is decided based on the AIR block they exist within. This is a much more robust system, and also results in a huge drop in ZIR bytes - around 7% for Sema.zig. This required some enhancements to Sema to prevent elision of blocks when they are required for debug variable scoping. This can be observed by looking at the AIR for the following simple test program with and without `-fstrip`: ```zig export fn f() void { { var a: u32 = 0; _ = &a; } { var a: u32 = 0; _ = &a; } } ``` When `-fstrip` is passed, no AIR blocks are generated. When `-fno-strip` is passed, the ZIR blocks are lowered to true AIR blocks to give correct lexical scoping to the debug vars. The changes here incidentally reolve #19060. A corresponding behavior test has been added. Resolves: #19060

18 files changed, 187 insertions(+), 287 deletions(-)

src/Air.zig-8
......@@ -443,10 +443,6 @@ pub const Inst = struct {
443443 /// Result type is always void.
444444 /// Uses the `dbg_stmt` field.
445445 dbg_stmt,
446 /// Marks the beginning of a semantic scope for debug info variables.
447 dbg_block_begin,
448 /// Marks the end of a semantic scope for debug info variables.
449 dbg_block_end,
450446 /// Marks the start of an inline call.
451447 /// Uses the `ty_fn` field.
452448 dbg_inline_begin,
......@@ -1454,8 +1450,6 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
14541450 .dbg_stmt,
14551451 .dbg_inline_begin,
14561452 .dbg_inline_end,
1457 .dbg_block_begin,
1458 .dbg_block_end,
14591453 .dbg_var_ptr,
14601454 .dbg_var_val,
14611455 .store,
......@@ -1612,8 +1606,6 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
16121606 .@"try",
16131607 .try_ptr,
16141608 .dbg_stmt,
1615 .dbg_block_begin,
1616 .dbg_block_end,
16171609 .dbg_inline_begin,
16181610 .dbg_inline_end,
16191611 .dbg_var_ptr,
src/AstGen.zig-51
......@@ -2445,8 +2445,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
24452445
24462446 if (statements.len == 0) return;
24472447
2448 try gz.addDbgBlockBegin();
2449
24502448 var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa);
24512449 defer block_arena.deinit();
24522450 const block_arena_allocator = block_arena.allocator();
......@@ -2518,8 +2516,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
25182516 }
25192517 }
25202518
2521 try gz.addDbgBlockEnd();
2522
25232519 try genDefers(gz, parent_scope, scope, .normal_only);
25242520 try checkUsed(gz, parent_scope, scope);
25252521}
......@@ -2804,8 +2800,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
28042800 .dbg_stmt,
28052801 .dbg_var_ptr,
28062802 .dbg_var_val,
2807 .dbg_block_begin,
2808 .dbg_block_end,
28092803 .ensure_result_used,
28102804 .ensure_result_non_error,
28112805 .ensure_err_union_payload_void,
......@@ -3026,7 +3020,6 @@ fn deferStmt(
30263020 var opt_remapped_err_code: Zir.Inst.OptionalIndex = .none;
30273021 const have_err_code = scope_tag == .defer_error and payload_token != 0;
30283022 const sub_scope = if (!have_err_code) &defer_gen.base else blk: {
3029 try gz.addDbgBlockBegin();
30303023 const ident_name = try gz.astgen.identAsString(payload_token);
30313024 const remapped_err_code: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
30323025 opt_remapped_err_code = remapped_err_code.toOptional();
......@@ -3052,7 +3045,6 @@ fn deferStmt(
30523045 };
30533046 _ = try unusedResultExpr(&defer_gen, sub_scope, expr_node);
30543047 try checkUsed(gz, scope, sub_scope);
3055 if (have_err_code) try gz.addDbgBlockEnd();
30563048 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);
30573049
30583050 // We must handle ref_table for remapped_err_code manually.
......@@ -6245,7 +6237,6 @@ fn ifExpr(
62456237
62466238 var payload_val_scope: Scope.LocalVal = undefined;
62476239
6248 try then_scope.addDbgBlockBegin();
62496240 const then_node = if_full.ast.then_expr;
62506241 const then_sub_scope = s: {
62516242 if (if_full.error_token != null) {
......@@ -6305,7 +6296,6 @@ fn ifExpr(
63056296 const then_result = try expr(&then_scope, then_sub_scope, block_scope.break_result_info, then_node);
63066297 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
63076298 if (!then_scope.endsWithNoReturn()) {
6308 try then_scope.addDbgBlockEnd();
63096299 _ = try then_scope.addBreakWithSrcNode(.@"break", block, then_result, then_node);
63106300 }
63116301
......@@ -6319,7 +6309,6 @@ fn ifExpr(
63196309
63206310 const else_node = if_full.ast.else_expr;
63216311 if (else_node != 0) {
6322 try else_scope.addDbgBlockBegin();
63236312 const sub_scope = s: {
63246313 if (if_full.error_token) |error_token| {
63256314 const tag: Zir.Inst.Tag = if (payload_is_ref)
......@@ -6347,7 +6336,6 @@ fn ifExpr(
63476336 }
63486337 };
63496338 const else_result = try expr(&else_scope, sub_scope, block_scope.break_result_info, else_node);
6350 try else_scope.addDbgBlockEnd();
63516339 if (!else_scope.endsWithNoReturn()) {
63526340 // As our last action before the break, "pop" the error trace if needed
63536341 if (do_err_trace)
......@@ -6579,7 +6567,6 @@ fn whileExpr(
65796567 // done adding instructions to loop_scope, can now stack then_scope
65806568 then_scope.instructions_top = then_scope.instructions.items.len;
65816569
6582 try then_scope.addDbgBlockBegin();
65836570 const then_node = while_full.ast.then_expr;
65846571 if (opt_payload_inst.unwrap()) |payload_inst| {
65856572 try then_scope.instructions.append(astgen.gpa, payload_inst);
......@@ -6593,7 +6580,6 @@ fn whileExpr(
65936580 if (while_full.ast.cont_expr != 0) {
65946581 _ = try unusedResultExpr(&then_scope, then_sub_scope, while_full.ast.cont_expr);
65956582 }
6596 try then_scope.addDbgBlockEnd();
65976583
65986584 continue_scope.instructions_top = continue_scope.instructions.items.len;
65996585 _ = try unusedResultExpr(&continue_scope, &continue_scope.base, then_node);
......@@ -6610,7 +6596,6 @@ fn whileExpr(
66106596
66116597 const else_node = while_full.ast.else_expr;
66126598 if (else_node != 0) {
6613 try else_scope.addDbgBlockBegin();
66146599 const sub_scope = s: {
66156600 if (while_full.error_token) |error_token| {
66166601 const tag: Zir.Inst.Tag = if (payload_is_ref)
......@@ -6647,7 +6632,6 @@ fn whileExpr(
66476632 }
66486633
66496634 try checkUsed(parent_gz, &else_scope.base, sub_scope);
6650 try else_scope.addDbgBlockEnd();
66516635 if (!else_scope.endsWithNoReturn()) {
66526636 _ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
66536637 }
......@@ -6849,8 +6833,6 @@ fn forExpr(
68496833 var then_scope = parent_gz.makeSubBlock(&cond_scope.base);
68506834 defer then_scope.unstack();
68516835
6852 try then_scope.addDbgBlockBegin();
6853
68546836 const capture_scopes = try gpa.alloc(Scope.LocalVal, for_full.ast.inputs.len);
68556837 defer gpa.free(capture_scopes);
68566838
......@@ -6916,7 +6898,6 @@ fn forExpr(
69166898 _ = try addEnsureResult(&then_scope, then_result, then_node);
69176899
69186900 try checkUsed(parent_gz, &then_scope.base, then_sub_scope);
6919 try then_scope.addDbgBlockEnd();
69206901
69216902 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
69226903
......@@ -7149,8 +7130,6 @@ fn switchExprErrUnion(
71497130 case_scope.instructions_top = parent_gz.instructions.items.len;
71507131 defer case_scope.unstack();
71517132
7152 try case_scope.addDbgBlockBegin();
7153
71547133 const unwrap_payload_tag: Zir.Inst.Tag = if (payload_is_ref)
71557134 .err_union_payload_unsafe_ptr
71567135 else
......@@ -7173,7 +7152,6 @@ fn switchExprErrUnion(
71737152 catch_or_if_node,
71747153 ),
71757154 };
7176 try case_scope.addDbgBlockEnd();
71777155 _ = try case_scope.addBreakWithSrcNode(
71787156 .@"break",
71797157 switch_block,
......@@ -7184,7 +7162,6 @@ fn switchExprErrUnion(
71847162 .@"if" => {
71857163 var payload_val_scope: Scope.LocalVal = undefined;
71867164
7187 try case_scope.addDbgBlockBegin();
71887165 const then_node = if_full.ast.then_expr;
71897166 const then_sub_scope = s: {
71907167 assert(if_full.error_token != null);
......@@ -7228,7 +7205,6 @@ fn switchExprErrUnion(
72287205 );
72297206 try checkUsed(parent_gz, &case_scope.base, then_sub_scope);
72307207 if (!case_scope.endsWithNoReturn()) {
7231 try case_scope.addDbgBlockEnd();
72327208 _ = try case_scope.addBreakWithSrcNode(
72337209 .@"break",
72347210 switch_block,
......@@ -7407,7 +7383,6 @@ fn switchExprErrUnion(
74077383 if (do_err_trace and nodeMayAppendToErrorTrace(tree, operand_node))
74087384 _ = try case_scope.addSaveErrRetIndex(.always);
74097385
7410 try case_scope.addDbgBlockBegin();
74117386 if (dbg_var_name != .empty) {
74127387 try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
74137388 }
......@@ -7421,7 +7396,6 @@ fn switchExprErrUnion(
74217396 try case_scope.addDbgVar(.dbg_var_val, err_name, err_inst.toRef());
74227397 any_uses_err_capture = true;
74237398 }
7424 try case_scope.addDbgBlockEnd();
74257399
74267400 if (!parent_gz.refIsNoReturn(case_result)) {
74277401 if (do_err_trace)
......@@ -7868,7 +7842,6 @@ fn switchExpr(
78687842 case_scope.instructions_top = parent_gz.instructions.items.len;
78697843 defer case_scope.unstack();
78707844
7871 try case_scope.addDbgBlockBegin();
78727845 if (dbg_var_name != .empty) {
78737846 try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
78747847 }
......@@ -7878,7 +7851,6 @@ fn switchExpr(
78787851 const target_expr_node = case.ast.target_expr;
78797852 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);
78807853 try checkUsed(parent_gz, &case_scope.base, sub_scope);
7881 try case_scope.addDbgBlockEnd();
78827854 if (!parent_gz.refIsNoReturn(case_result)) {
78837855 _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);
78847856 }
......@@ -13165,29 +13137,6 @@ const GenZir = struct {
1316513137 },
1316613138 } });
1316713139 }
13168
13169 fn addDbgBlockBegin(gz: *GenZir) !void {
13170 if (gz.is_comptime) return;
13171
13172 _ = try gz.add(.{ .tag = .dbg_block_begin, .data = undefined });
13173 }
13174
13175 fn addDbgBlockEnd(gz: *GenZir) !void {
13176 if (gz.is_comptime) return;
13177 const gpa = gz.astgen.gpa;
13178
13179 const tags = gz.astgen.instructions.items(.tag);
13180 const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
13181 // remove dbg_block_begin immediately followed by dbg_block_end
13182 if (tags[@intFromEnum(last_inst)] == .dbg_block_begin) {
13183 _ = gz.instructions.pop();
13184 return;
13185 }
13186
13187 const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
13188 try gz.astgen.instructions.append(gpa, .{ .tag = .dbg_block_end, .data = undefined });
13189 try gz.instructions.append(gpa, new_index);
13190 }
1319113140};
1319213141
1319313142/// This can only be for short-lived references; the memory becomes invalidated
src/Liveness.zig-4
......@@ -329,8 +329,6 @@ pub fn categorizeOperand(
329329 .dbg_stmt,
330330 .dbg_inline_begin,
331331 .dbg_inline_end,
332 .dbg_block_begin,
333 .dbg_block_end,
334332 .unreach,
335333 .ret_addr,
336334 .frame_addr,
......@@ -967,8 +965,6 @@ fn analyzeInst(
967965 .dbg_stmt,
968966 .dbg_inline_begin,
969967 .dbg_inline_end,
970 .dbg_block_begin,
971 .dbg_block_end,
972968 .fence,
973969 .ret_addr,
974970 .frame_addr,
src/Liveness/Verify.zig-2
......@@ -48,8 +48,6 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
4848 .dbg_stmt,
4949 .dbg_inline_begin,
5050 .dbg_inline_end,
51 .dbg_block_begin,
52 .dbg_block_end,
5351 .fence,
5452 .ret_addr,
5553 .frame_addr,
src/Sema.zig+148-124
......@@ -364,6 +364,12 @@ pub const Block = struct {
364364
365365 c_import_buf: ?*std.ArrayList(u8) = null,
366366
367 /// If not `null`, this boolean is set when a `dbg_var_ptr` or `dbg_var_val`
368 /// instruction is emitted. It signals that the innermost lexically
369 /// enclosing `block`/`block_inline` should be translated into a real AIR
370 /// `block` in order for codegen to match lexical scoping for debug vars.
371 need_debug_scope: ?*bool = null,
372
367373 const ComptimeReason = union(enum) {
368374 c_import: struct {
369375 block: *Block,
......@@ -482,6 +488,7 @@ pub const Block = struct {
482488 .float_mode = parent.float_mode,
483489 .c_import_buf = parent.c_import_buf,
484490 .error_return_trace_index = parent.error_return_trace_index,
491 .need_debug_scope = parent.need_debug_scope,
485492 };
486493 }
487494
......@@ -986,8 +993,6 @@ fn analyzeBodyInner(
986993 crash_info.push();
987994 defer crash_info.pop();
988995
989 var dbg_block_begins: u32 = 0;
990
991996 // We use a while (true) loop here to avoid a redundant way of breaking out of
992997 // the loop. The only way to break out of the loop is with a `noreturn`
993998 // instruction.
......@@ -1332,18 +1337,6 @@ fn analyzeBodyInner(
13321337 i += 1;
13331338 continue;
13341339 },
1335 .dbg_block_begin => {
1336 dbg_block_begins += 1;
1337 try zirDbgBlockBegin(block);
1338 i += 1;
1339 continue;
1340 },
1341 .dbg_block_end => {
1342 dbg_block_begins -= 1;
1343 try zirDbgBlockEnd(block);
1344 i += 1;
1345 continue;
1346 },
13471340 .ensure_err_union_payload_void => {
13481341 try sema.zirEnsureErrUnionPayloadVoid(block, inst);
13491342 i += 1;
......@@ -1641,10 +1634,12 @@ fn analyzeBodyInner(
16411634 const inline_body = sema.code.bodySlice(extra.end, extra.data.body_len);
16421635 const gpa = sema.gpa;
16431636
1644 const opt_break_data = b: {
1637 const opt_break_data, const need_debug_scope = b: {
16451638 // Create a temporary child block so that this inline block is properly
16461639 // labeled for any .restore_err_ret_index instructions
16471640 var child_block = block.makeSubBlock();
1641 var need_debug_scope = false;
1642 child_block.need_debug_scope = &need_debug_scope;
16481643
16491644 // If this block contains a function prototype, we need to reset the
16501645 // current list of parameters and restore it later.
......@@ -1665,7 +1660,11 @@ fn analyzeBodyInner(
16651660 child_block.instructions = block.instructions;
16661661 defer block.instructions = child_block.instructions;
16671662
1668 break :b try sema.analyzeBodyBreak(&child_block, inline_body);
1663 const result = try sema.analyzeBodyBreak(&child_block, inline_body);
1664 if (need_debug_scope) {
1665 _ = try sema.ensurePostHoc(block, inst);
1666 }
1667 break :b .{ result, need_debug_scope };
16691668 };
16701669
16711670 // A runtime conditional branch that needs a post-hoc block to be
......@@ -1686,28 +1685,22 @@ fn analyzeBodyInner(
16861685 // since it crosses a runtime branch.
16871686 // It may pass through our currently being analyzed block_inline or it
16881687 // may point directly to it. In the latter case, this modifies the
1689 // block that we are about to look up in the post_hoc_blocks map below.
1688 // block that we looked up in the post_hoc_blocks map above.
16901689 try sema.addRuntimeBreak(block, break_data);
1691 } else {
1692 // Here the comptime control flow ends with noreturn; however
1693 // we have runtime control flow continuing after this block.
1694 // This branch is therefore handled by the `i += 1; continue;`
1695 // logic below.
16961690 }
16971691
16981692 try labeled_block.block.instructions.appendSlice(gpa, block.instructions.items[block_index..]);
16991693 block.instructions.items.len = block_index;
17001694
1701 const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges);
1695 const block_result = try sema.analyzeBlockBody(block, inst_data.src(), &labeled_block.block, &labeled_block.label.merges, need_debug_scope);
17021696 {
17031697 // Destroy the ad-hoc block entry so that it does not interfere with
17041698 // the next iteration of comptime control flow, if any.
17051699 labeled_block.destroy(gpa);
17061700 assert(sema.post_hoc_blocks.remove(new_block_inst));
17071701 }
1708 map.putAssumeCapacity(inst, block_result);
1709 i += 1;
1710 continue;
1702
1703 break :blk block_result;
17111704 }
17121705
17131706 const break_data = opt_break_data orelse break always_noreturn;
......@@ -1860,19 +1853,6 @@ fn analyzeBodyInner(
18601853 i += 1;
18611854 };
18621855
1863 // balance out dbg_block_begins in case of early noreturn
1864 if (!block.is_comptime and !block.ownerModule().strip) {
1865 const noreturn_inst = block.instructions.popOrNull();
1866 while (dbg_block_begins > 0) {
1867 dbg_block_begins -= 1;
1868 _ = try block.addInst(.{
1869 .tag = .dbg_block_end,
1870 .data = undefined,
1871 });
1872 }
1873 if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
1874 }
1875
18761856 // We may have overwritten the capture scope due to a `repeat` instruction where
18771857 // the body had a capture; restore it now.
18781858 block.wip_capture_scope = parent_capture_scope;
......@@ -5757,7 +5737,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
57575737 );
57585738 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(loop_block.instructions.items));
57595739 }
5760 return sema.analyzeBlockBody(parent_block, src, &child_block, merges);
5740 return sema.analyzeBlockBody(parent_block, src, &child_block, merges, false);
57615741}
57625742
57635743fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -5945,13 +5925,31 @@ fn resolveBlockBody(
59455925 if (child_block.is_comptime) {
59465926 return sema.resolveBody(child_block, body, body_inst);
59475927 } else {
5928 var need_debug_scope = false;
5929 child_block.need_debug_scope = &need_debug_scope;
59485930 if (sema.analyzeBodyInner(child_block, body)) |_| {
5949 return sema.analyzeBlockBody(parent_block, src, child_block, merges);
5931 return sema.analyzeBlockBody(parent_block, src, child_block, merges, need_debug_scope);
59505932 } else |err| switch (err) {
59515933 error.ComptimeBreak => {
59525934 // Comptime control flow is happening, however child_block may still contain
59535935 // runtime instructions which need to be copied to the parent block.
5954 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
5936 if (need_debug_scope and child_block.instructions.items.len > 0) {
5937 // We need a runtime block for scoping reasons.
5938 _ = try child_block.addBr(merges.block_inst, .void_value);
5939 try parent_block.instructions.append(sema.gpa, merges.block_inst);
5940 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len +
5941 child_block.instructions.items.len);
5942 sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
5943 .ty = .void_type,
5944 .payload = sema.addExtraAssumeCapacity(Air.Block{
5945 .body_len = @intCast(child_block.instructions.items.len),
5946 }),
5947 } };
5948 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
5949 } else {
5950 // We can copy instructions directly to the parent block.
5951 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items);
5952 }
59555953
59565954 const break_inst = sema.comptime_break_inst;
59575955 const break_data = sema.code.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
......@@ -5973,6 +5971,7 @@ fn analyzeBlockBody(
59735971 src: LazySrcLoc,
59745972 child_block: *Block,
59755973 merges: *Block.Merges,
5974 need_debug_scope: bool,
59765975) CompileError!Air.Inst.Ref {
59775976 const tracy = trace(@src());
59785977 defer tracy.end();
......@@ -5987,25 +5986,57 @@ fn analyzeBlockBody(
59875986 if (merges.results.items.len == 0) {
59885987 // No need for a block instruction. We can put the new instructions
59895988 // directly into the parent block.
5989 if (need_debug_scope) {
5990 // The code following this block is unreachable, as the block has no
5991 // merges, so we don't necessarily need to emit this as an AIR block.
5992 // However, we need a block *somewhere* to make the scoping correct,
5993 // so forward this request to the parent block.
5994 if (parent_block.need_debug_scope) |ptr| ptr.* = true;
5995 }
59905996 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items);
59915997 return child_block.instructions.items[child_block.instructions.items.len - 1].toRef();
59925998 }
59935999 if (merges.results.items.len == 1) {
5994 const last_inst_index = child_block.instructions.items.len - 1;
5995 const last_inst = child_block.instructions.items[last_inst_index];
5996 if (sema.getBreakBlock(last_inst)) |br_block| {
5997 if (br_block == merges.block_inst) {
5998 // No need for a block instruction. We can put the new instructions directly
5999 // into the parent block. Here we omit the break instruction.
6000 const without_break = child_block.instructions.items[0..last_inst_index];
6001 try parent_block.instructions.appendSlice(gpa, without_break);
6002 return merges.results.items[0];
6003 }
6000 // If the `break` is trailing, we may be able to elide the AIR block here
6001 // by appending the new instructions directly to the parent block.
6002 if (!need_debug_scope) {
6003 const last_inst_index = child_block.instructions.items.len - 1;
6004 const last_inst = child_block.instructions.items[last_inst_index];
6005 if (sema.getBreakBlock(last_inst)) |br_block| {
6006 if (br_block == merges.block_inst) {
6007 // Great, the last instruction is the break! Put the instructions
6008 // directly into the parent block.
6009 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items[0..last_inst_index]);
6010 return merges.results.items[0];
6011 }
6012 }
6013 }
6014 // Okay, we need a runtime block. If the value is comptime-known, the
6015 // block should just return void, and we return the merge result
6016 // directly. Otherwise, we can defer to the logic below.
6017 if (try sema.resolveValue(merges.results.items[0])) |result_val| {
6018 // Create a block containing all instruction from the body.
6019 try parent_block.instructions.append(gpa, merges.block_inst);
6020 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len +
6021 child_block.instructions.items.len);
6022 sema.air_instructions.items(.data)[@intFromEnum(merges.block_inst)] = .{ .ty_pl = .{
6023 .ty = .void_type,
6024 .payload = sema.addExtraAssumeCapacity(Air.Block{
6025 .body_len = @intCast(child_block.instructions.items.len),
6026 }),
6027 } };
6028 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items));
6029 // Rewrite the break to just give value {}; the value is
6030 // comptime-known and will be returned directly.
6031 sema.air_instructions.items(.data)[@intFromEnum(merges.br_list.items[0])].br.operand = .void_value;
6032 return Air.internedToRef(result_val.toIntern());
60046033 }
60056034 }
60066035 // It is impossible to have the number of results be > 1 in a comptime scope.
60076036 assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
60086037
6038 // Note that we'll always create an AIR block here, so `need_debug_scope` is irrelevant.
6039
60096040 // Need to set the type and emit the Block instruction. This allows machine code generation
60106041 // to emit a jump instruction to after the block when it encounters the break.
60116042 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
63836414 });
63846415}
63856416
6386fn zirDbgBlockBegin(block: *Block) CompileError!void {
6387 if (block.is_comptime or block.ownerModule().strip) return;
6388
6389 _ = try block.addInst(.{
6390 .tag = .dbg_block_begin,
6391 .data = undefined,
6392 });
6393}
6394
6395fn zirDbgBlockEnd(block: *Block) CompileError!void {
6396 if (block.is_comptime or block.ownerModule().strip) return;
6397
6398 _ = try block.addInst(.{
6399 .tag = .dbg_block_end,
6400 .data = undefined,
6401 });
6402}
6403
64046417fn zirDbgVar(
64056418 sema: *Sema,
64066419 block: *Block,
......@@ -6432,6 +6445,15 @@ fn addDbgVar(
64326445 if (try sema.typeRequiresComptime(val_ty)) return;
64336446 if (!(try sema.typeHasRuntimeBits(val_ty))) return;
64346447
6448 // To ensure the lexical scoping is known to backends, this alloc must be
6449 // within a real runtime block. We set a flag which communicates information
6450 // to the closest lexically enclosing block:
6451 // * If it is a `block_inline`, communicates to logic in `analyzeBodyInner`
6452 // to create a post-hoc block.
6453 // * Otherwise, communicates to logic in `resolveBlockBody` to create a
6454 // real `block` instruction.
6455 if (block.need_debug_scope) |ptr| ptr.* = true;
6456
64356457 try sema.queueFullTypeResolution(operand_ty);
64366458
64376459 // Add the name to the AIR.
......@@ -7585,7 +7607,7 @@ fn analyzeCall(
75857607 error.ComptimeReturn => break :result inlining.comptime_result,
75867608 else => |e| return e,
75877609 };
7588 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
7610 break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges, false);
75897611 };
75907612
75917613 if (!is_comptime_call and !block.is_typeof and
......@@ -11528,7 +11550,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
1152811550 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(true_instructions));
1152911551 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
1153011552
11531 return sema.analyzeBlockBody(block, main_src, &child_block, merges);
11553 return sema.analyzeBlockBody(block, main_src, &child_block, merges, false);
1153211554}
1153311555
1153411556fn 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
1215012172 false,
1215112173 );
1215212174
12153 return sema.analyzeBlockBody(block, src, &child_block, merges);
12175 return sema.analyzeBlockBody(block, src, &child_block, merges, false);
1215412176}
1215512177
1215612178const SpecialProng = struct {
......@@ -13163,8 +13185,6 @@ fn validateErrSetSwitch(
1316313185 const tags = sema.code.instructions.items(.tag);
1316413186 const datas = sema.code.instructions.items(.data);
1316513187 for (else_case.body) |else_inst| switch (tags[@intFromEnum(else_inst)]) {
13166 .dbg_block_begin,
13167 .dbg_block_end,
1316813188 .dbg_stmt,
1316913189 .dbg_var_val,
1317013190 .ret_type,
......@@ -13416,8 +13436,6 @@ fn maybeErrorUnwrap(
1341613436 .@"unreachable" => if (!block.wantSafety()) return false,
1341713437 .err_union_code => if (!allow_err_code_inst) return false,
1341813438 .save_err_ret_index,
13419 .dbg_block_begin,
13420 .dbg_block_end,
1342113439 .dbg_stmt,
1342213440 .str,
1342313441 .as_node,
......@@ -13430,10 +13448,7 @@ fn maybeErrorUnwrap(
1343013448
1343113449 for (body) |inst| {
1343213450 const air_inst = switch (tags[@intFromEnum(inst)]) {
13433 .dbg_block_begin,
13434 .dbg_block_end,
13435 .err_union_code,
13436 => continue,
13451 .err_union_code => continue,
1343713452 .dbg_stmt => {
1343813453 try sema.zirDbgStmt(block, inst);
1343913454 continue;
......@@ -13499,8 +13514,6 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I
1349913514 const tags = sema.code.instructions.items(.tag);
1350013515 const inst = for (body) |inst| {
1350113516 switch (tags[@intFromEnum(inst)]) {
13502 .dbg_block_begin,
13503 .dbg_block_end,
1350413517 .dbg_stmt,
1350513518 .save_err_ret_index,
1350613519 => {},
......@@ -19092,55 +19105,64 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1909219105 return try_inst;
1909319106}
1909419107
19108fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*LabeledBlock {
19109 const gop = sema.inst_map.getOrPutAssumeCapacity(dest_block);
19110 if (gop.found_existing) existing: {
19111 // This may be a *result* from an earlier iteration of an inline loop.
19112 // In this case, there will not be a post-hoc block entry, and we can
19113 // continue with the logic below.
19114 const new_block_inst = gop.value_ptr.*.toIndex() orelse break :existing;
19115 return sema.post_hoc_blocks.get(new_block_inst) orelse break :existing;
19116 }
19117
19118 try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
19119
19120 const new_block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
19121 gop.value_ptr.* = new_block_inst.toRef();
19122 try sema.air_instructions.append(sema.gpa, .{
19123 .tag = .block,
19124 .data = undefined,
19125 });
19126 const labeled_block = try sema.gpa.create(LabeledBlock);
19127 labeled_block.* = .{
19128 .label = .{
19129 .zir_block = dest_block,
19130 .merges = .{
19131 .src_locs = .{},
19132 .results = .{},
19133 .br_list = .{},
19134 .block_inst = new_block_inst,
19135 },
19136 },
19137 .block = .{
19138 .parent = block,
19139 .sema = sema,
19140 .src_decl = block.src_decl,
19141 .namespace = block.namespace,
19142 .wip_capture_scope = block.wip_capture_scope,
19143 .instructions = .{},
19144 .label = &labeled_block.label,
19145 .inlining = block.inlining,
19146 .is_comptime = block.is_comptime,
19147 },
19148 };
19149 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
19150 return labeled_block;
19151}
19152
1909519153// A `break` statement is inside a runtime condition, but trying to
1909619154// break from an inline loop. In such case we must convert it to
1909719155// a runtime break.
1909819156fn addRuntimeBreak(sema: *Sema, child_block: *Block, break_data: BreakData) !void {
19099 const gop = sema.inst_map.getOrPutAssumeCapacity(break_data.block_inst);
19100 const labeled_block = if (!gop.found_existing) blk: {
19101 try sema.post_hoc_blocks.ensureUnusedCapacity(sema.gpa, 1);
19102
19103 const new_block_inst: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
19104 gop.value_ptr.* = new_block_inst.toRef();
19105 try sema.air_instructions.append(sema.gpa, .{
19106 .tag = .block,
19107 .data = undefined,
19108 });
19109 const labeled_block = try sema.gpa.create(LabeledBlock);
19110 labeled_block.* = .{
19111 .label = .{
19112 .zir_block = break_data.block_inst,
19113 .merges = .{
19114 .src_locs = .{},
19115 .results = .{},
19116 .br_list = .{},
19117 .block_inst = new_block_inst,
19118 },
19119 },
19120 .block = .{
19121 .parent = child_block,
19122 .sema = sema,
19123 .src_decl = child_block.src_decl,
19124 .namespace = child_block.namespace,
19125 .wip_capture_scope = child_block.wip_capture_scope,
19126 .instructions = .{},
19127 .label = &labeled_block.label,
19128 .inlining = child_block.inlining,
19129 .is_comptime = child_block.is_comptime,
19130 },
19131 };
19132 sema.post_hoc_blocks.putAssumeCapacityNoClobber(new_block_inst, labeled_block);
19133 break :blk labeled_block;
19134 } else blk: {
19135 const new_block_inst = gop.value_ptr.*.toIndex().?;
19136 const labeled_block = sema.post_hoc_blocks.get(new_block_inst).?;
19137 break :blk labeled_block;
19138 };
19157 const labeled_block = try sema.ensurePostHoc(child_block, break_data.block_inst);
1913919158
1914019159 const operand = try sema.resolveInst(break_data.operand);
1914119160 const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand);
19161
1914219162 try labeled_block.label.merges.results.append(sema.gpa, operand);
1914319163 try labeled_block.label.merges.br_list.append(sema.gpa, br_ref.toIndex().?);
19164 try labeled_block.label.merges.src_locs.append(sema.gpa, null);
19165
1914419166 labeled_block.block.runtime_index.increment();
1914519167 if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) {
1914619168 labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop;
......@@ -19481,8 +19503,10 @@ fn analyzeRet(
1948119503 return error.ComptimeReturn;
1948219504 }
1948319505 // We are inlining a function call; rewrite the `ret` as a `break`.
19506 const br_inst = try block.addBr(inlining.merges.block_inst, operand);
1948419507 try inlining.merges.results.append(sema.gpa, operand);
19485 _ = try block.addBr(inlining.merges.block_inst, operand);
19508 try inlining.merges.br_list.append(sema.gpa, br_inst.toIndex().?);
19509 try inlining.merges.src_locs.append(sema.gpa, operand_src);
1948619510 return always_noreturn;
1948719511 } else if (block.is_comptime) {
1948819512 return sema.fail(block, src, "function called at runtime cannot return value at comptime", .{});
src/Zir.zig-10
......@@ -392,10 +392,6 @@ pub const Inst = struct {
392392 /// Same as `dbg_var_ptr` but the local is always a const and the operand
393393 /// is the local's value.
394394 dbg_var_val,
395 /// Marks the beginning of a semantic scope for debug info variables.
396 dbg_block_begin,
397 /// Marks the end of a semantic scope for debug info variables.
398 dbg_block_end,
399395 /// Uses a name to identify a Decl and takes a pointer to it.
400396 /// Uses the `str_tok` union field.
401397 decl_ref,
......@@ -1107,8 +1103,6 @@ pub const Inst = struct {
11071103 .dbg_stmt,
11081104 .dbg_var_ptr,
11091105 .dbg_var_val,
1110 .dbg_block_begin,
1111 .dbg_block_end,
11121106 .decl_ref,
11131107 .decl_val,
11141108 .load,
......@@ -1335,8 +1329,6 @@ pub const Inst = struct {
13351329 .dbg_stmt,
13361330 .dbg_var_ptr,
13371331 .dbg_var_val,
1338 .dbg_block_begin,
1339 .dbg_block_end,
13401332 .ensure_result_used,
13411333 .ensure_result_non_error,
13421334 .ensure_err_union_payload_void,
......@@ -1663,8 +1655,6 @@ pub const Inst = struct {
16631655 .dbg_stmt = .dbg_stmt,
16641656 .dbg_var_ptr = .str_op,
16651657 .dbg_var_val = .str_op,
1666 .dbg_block_begin = .tok,
1667 .dbg_block_end = .tok,
16681658 .decl_ref = .str_tok,
16691659 .decl_val = .str_tok,
16701660 .load = .un_node,
src/arch/aarch64/CodeGen.zig+1-9
......@@ -813,10 +813,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
813813 .dbg_inline_end,
814814 => try self.airDbgInline(inst),
815815
816 .dbg_block_begin,
817 .dbg_block_end,
818 => try self.airDbgBlock(inst),
819
820816 .call => try self.airCall(inst, .auto),
821817 .call_always_tail => try self.airCall(inst, .always_tail),
822818 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -4634,11 +4630,6 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
46344630 return self.finishAir(inst, .dead, .{ .none, .none, .none });
46354631}
46364632
4637fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
4638 // TODO emit debug info lexical block
4639 return self.finishAir(inst, .dead, .{ .none, .none, .none });
4640}
4641
46424633fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
46434634 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
46444635 const operand = pl_op.operand;
......@@ -5066,6 +5057,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
50665057 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
50675058 const extra = self.air.extraData(Air.Block, ty_pl.payload);
50685059 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
5060 // TODO emit debug info lexical block
50695061 try self.genBody(body);
50705062
50715063 // relocations for `br` instructions
src/arch/arm/CodeGen.zig+1-9
......@@ -799,10 +799,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
799799 .dbg_inline_end,
800800 => try self.airDbgInline(inst),
801801
802 .dbg_block_begin,
803 .dbg_block_end,
804 => try self.airDbgBlock(inst),
805
806802 .call => try self.airCall(inst, .auto),
807803 .call_always_tail => try self.airCall(inst, .always_tail),
808804 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -4587,11 +4583,6 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
45874583 return self.finishAir(inst, .dead, .{ .none, .none, .none });
45884584}
45894585
4590fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
4591 // TODO emit debug info lexical block
4592 return self.finishAir(inst, .dead, .{ .none, .none, .none });
4593}
4594
45954586fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
45964587 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
45974588 const operand = pl_op.operand;
......@@ -4997,6 +4988,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
49974988 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
49984989 const extra = self.air.extraData(Air.Block, ty_pl.payload);
49994990 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
4991 // TODO emit debug info lexical block
50004992 try self.genBody(body);
50014993
50024994 // relocations for `br` instructions
src/arch/riscv64/CodeGen.zig+1-9
......@@ -632,10 +632,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
632632 .dbg_inline_end,
633633 => try self.airDbgInline(inst),
634634
635 .dbg_block_begin,
636 .dbg_block_end,
637 => try self.airDbgBlock(inst),
638
639635 .call => try self.airCall(inst, .auto),
640636 .call_always_tail => try self.airCall(inst, .always_tail),
641637 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -1894,11 +1890,6 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
18941890 return self.finishAir(inst, .dead, .{ .none, .none, .none });
18951891}
18961892
1897fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
1898 // TODO emit debug info lexical block
1899 return self.finishAir(inst, .dead, .{ .none, .none, .none });
1900}
1901
19021893fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
19031894 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
19041895 const name = self.air.nullTerminatedString(pl_op.payload);
......@@ -2084,6 +2075,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
20842075 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
20852076 const extra = self.air.extraData(Air.Block, ty_pl.payload);
20862077 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
2078 // TODO emit debug info lexical block
20872079 try self.genBody(body);
20882080
20892081 for (self.blocks.getPtr(inst).?.relocs.items) |reloc| try self.performReloc(reloc);
src/arch/sparc64/CodeGen.zig+1-9
......@@ -645,10 +645,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
645645 .dbg_inline_end,
646646 => try self.airDbgInline(inst),
647647
648 .dbg_block_begin,
649 .dbg_block_end,
650 => try self.airDbgBlock(inst),
651
652648 .call => try self.airCall(inst, .auto),
653649 .call_always_tail => try self.airCall(inst, .always_tail),
654650 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -1146,6 +1142,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
11461142 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
11471143 const extra = self.air.extraData(Air.Block, ty_pl.payload);
11481144 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
1145 // TODO emit debug info lexical block
11491146 try self.genBody(body);
11501147
11511148 // relocations for `bpcc` instructions
......@@ -1655,11 +1652,6 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
16551652 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
16561653}
16571654
1658fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
1659 // TODO emit debug info lexical block
1660 return self.finishAir(inst, .dead, .{ .none, .none, .none });
1661}
1662
16631655fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
16641656 const ty_fn = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_fn;
16651657 const mod = self.bin_file.comp.module.?;
src/arch/wasm/CodeGen.zig-2
......@@ -1913,8 +1913,6 @@ fn genInst(func: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19131913 // TODO
19141914 .dbg_inline_begin,
19151915 .dbg_inline_end,
1916 .dbg_block_begin,
1917 .dbg_block_end,
19181916 => func.finishAir(inst, .none, &.{}),
19191917
19201918 .dbg_var_ptr => func.airDbgVar(inst, true),
src/arch/x86_64/CodeGen.zig+1-10
......@@ -2106,10 +2106,6 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
21062106 .dbg_inline_end,
21072107 => try self.airDbgInline(inst),
21082108
2109 .dbg_block_begin,
2110 .dbg_block_end,
2111 => try self.airDbgBlock(inst),
2112
21132109 .call => try self.airCall(inst, .auto),
21142110 .call_always_tail => try self.airCall(inst, .always_tail),
21152111 .call_never_tail => try self.airCall(inst, .never_tail),
......@@ -12976,12 +12972,6 @@ fn airDbgInline(self: *Self, inst: Air.Inst.Index) !void {
1297612972 self.finishAirBookkeeping();
1297712973}
1297812974
12979fn airDbgBlock(self: *Self, inst: Air.Inst.Index) !void {
12980 _ = inst;
12981 // TODO emit debug info lexical block
12982 self.finishAirBookkeeping();
12983}
12984
1298512975fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
1298612976 const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
1298712977 const operand = pl_op.operand;
......@@ -13428,6 +13418,7 @@ fn airBlock(self: *Self, inst: Air.Inst.Index) !void {
1342813418 const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
1342913419 const extra = self.air.extraData(Air.Block, ty_pl.payload);
1343013420 const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
13421 // TODO emit debug info lexical block
1343113422 try self.genBody(body);
1343213423
1343313424 var block_data = self.blocks.fetchRemove(inst).?;
src/codegen/c.zig-4
......@@ -3268,10 +3268,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
32683268 .dbg_inline_end,
32693269 => try airDbgInline(f, inst),
32703270
3271 .dbg_block_begin,
3272 .dbg_block_end,
3273 => .none,
3274
32753271 .call => try airCall(f, inst, .auto),
32763272 .call_always_tail => .none,
32773273 .call_never_tail => try airCall(f, inst, .never_tail),
src/codegen/llvm.zig+16-28
......@@ -4768,8 +4768,6 @@ pub const FuncGen = struct {
47684768 scope: Builder.Metadata,
47694769 }) = .{},
47704770
4771 scope_stack: std.ArrayListUnmanaged(Builder.Metadata) = .{},
4772
47734771 base_line: u32,
47744772 prev_dbg_line: c_uint,
47754773 prev_dbg_column: c_uint,
......@@ -4813,7 +4811,6 @@ pub const FuncGen = struct {
48134811
48144812 fn deinit(self: *FuncGen) void {
48154813 self.wip.deinit();
4816 self.scope_stack.deinit(self.gpa);
48174814 self.inlined.deinit(self.gpa);
48184815 self.func_inst_table.deinit(self.gpa);
48194816 self.blocks.deinit(self.gpa);
......@@ -5112,8 +5109,6 @@ pub const FuncGen = struct {
51125109 .dbg_stmt => try self.airDbgStmt(inst),
51135110 .dbg_inline_begin => try self.airDbgInlineBegin(inst),
51145111 .dbg_inline_end => try self.airDbgInlineEnd(inst),
5115 .dbg_block_begin => try self.airDbgBlockBegin(),
5116 .dbg_block_end => try self.airDbgBlockEnd(),
51175112 .dbg_var_ptr => try self.airDbgVarPtr(inst),
51185113 .dbg_var_val => try self.airDbgVarVal(inst),
51195114
......@@ -5131,6 +5126,19 @@ pub const FuncGen = struct {
51315126 }
51325127 }
51335128
5129 fn genBodyDebugScope(self: *FuncGen, body: []const Air.Inst.Index) Error!void {
5130 if (self.wip.strip) return self.genBody(body);
5131 const old_scope = self.scope;
5132 self.scope = try self.dg.object.builder.debugLexicalBlock(
5133 old_scope,
5134 self.file,
5135 self.prev_dbg_line,
5136 self.prev_dbg_column,
5137 );
5138 try self.genBody(body);
5139 self.scope = old_scope;
5140 }
5141
51345142 pub const CallAttr = enum {
51355143 Auto,
51365144 NeverTail,
......@@ -5820,7 +5828,7 @@ pub const FuncGen = struct {
58205828 const inst_ty = self.typeOfIndex(inst);
58215829
58225830 if (inst_ty.isNoReturn(mod)) {
5823 try self.genBody(body);
5831 try self.genBodyDebugScope(body);
58245832 return .none;
58255833 }
58265834
......@@ -5836,7 +5844,7 @@ pub const FuncGen = struct {
58365844 });
58375845 defer assert(self.blocks.remove(inst));
58385846
5839 try self.genBody(body);
5847 try self.genBodyDebugScope(body);
58405848
58415849 self.wip.cursor = .{ .block = parent_bb };
58425850
......@@ -6683,26 +6691,6 @@ pub const FuncGen = struct {
66836691 return .none;
66846692 }
66856693
6686 fn airDbgBlockBegin(self: *FuncGen) Allocator.Error!Builder.Value {
6687 const o = self.dg.object;
6688
6689 try self.scope_stack.append(self.gpa, self.scope);
6690
6691 const old = self.scope;
6692 self.scope = try o.builder.debugLexicalBlock(
6693 old,
6694 self.file,
6695 self.prev_dbg_line,
6696 self.prev_dbg_column,
6697 );
6698 return .none;
6699 }
6700
6701 fn airDbgBlockEnd(self: *FuncGen) !Builder.Value {
6702 self.scope = self.scope_stack.pop();
6703 return .none;
6704 }
6705
67066694 fn airDbgVarPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
67076695 const o = self.dg.object;
67086696 const mod = o.module;
......@@ -7488,7 +7476,7 @@ pub const FuncGen = struct {
74887476 for (body_tail[1..]) |body_inst| {
74897477 switch (air_tags[@intFromEnum(body_inst)]) {
74907478 .ret => return true,
7491 .dbg_stmt, .dbg_block_end => continue,
7479 .dbg_stmt => continue,
74927480 else => return false,
74937481 }
74947482 }
src/codegen/spirv.zig-2
......@@ -2322,8 +2322,6 @@ const DeclGen = struct {
23222322 .dbg_inline_begin => return self.airDbgInlineBegin(inst),
23232323 .dbg_inline_end => return self.airDbgInlineEnd(inst),
23242324 .dbg_var_ptr, .dbg_var_val => return self.airDbgVar(inst),
2325 .dbg_block_begin => return,
2326 .dbg_block_end => return,
23272325
23282326 .unwrap_errunion_err => try self.airErrUnionErr(inst),
23292327 .unwrap_errunion_payload => try self.airErrUnionPayload(inst),
src/print_air.zig-2
......@@ -319,8 +319,6 @@ const Writer = struct {
319319 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
320320 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
321321
322 .dbg_block_begin, .dbg_block_end => {},
323
324322 .work_item_id,
325323 .work_group_size,
326324 .work_group_id,
src/print_zir.zig-4
......@@ -510,10 +510,6 @@ const Writer = struct {
510510
511511 .dbg_stmt => try self.writeDbgStmt(stream, inst),
512512
513 .dbg_block_begin,
514 .dbg_block_end,
515 => try stream.writeAll(")"),
516
517513 .closure_get => try self.writeInstNode(stream, inst),
518514
519515 .@"defer" => try self.writeDefer(stream, inst),
test/behavior/eval.zig+18
......@@ -1714,3 +1714,21 @@ test "const with specified type initialized with typed array is comptime-known"
17141714 comptime assert(x[1] == 2);
17151715 comptime assert(x[2] == 3);
17161716}
1717
1718test "block with comptime-known result but possible runtime exit is comptime-known" {
1719 var t: bool = true;
1720 _ = &t;
1721
1722 const a: comptime_int = a: {
1723 if (!t) return error.TestFailed;
1724 break :a 123;
1725 };
1726
1727 const b: comptime_int = b: {
1728 if (t) break :b 456;
1729 return error.TestFailed;
1730 };
1731
1732 comptime assert(a == 123);
1733 comptime assert(b == 456);
1734}