diff options
| author | Matthew Lugg <mlugg@mlugg.co.uk> | 2024-02-27 03:25:04 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-02-27 03:25:04 +0000 |
| commit | 8775d8bbcef347640c6ae7e73da02ca6eff1d669 (patch) | |
| tree | 3f04f80b042d7baf10074b6f88fabb5693b2b71e /src | |
| parent | f803761e13a65ccbc6a5508f2dc2d7723b010dab (diff) | |
| parent | 59447e53056d8fb6682b79accccffa176d0b44d1 (diff) | |
| download | zig-8775d8bbcef347640c6ae7e73da02ca6eff1d669.tar.gz zig-8775d8bbcef347640c6ae7e73da02ca6eff1d669.zip | |
Merge pull request #19062 from mlugg/dbg-var-blocks
compiler: decide dbg_var scoping based on AIR blocks
Diffstat (limited to 'src')
| -rw-r--r-- | src/Air.zig | 8 | ||||
| -rw-r--r-- | src/AstGen.zig | 51 | ||||
| -rw-r--r-- | src/Liveness.zig | 4 | ||||
| -rw-r--r-- | src/Liveness/Verify.zig | 2 | ||||
| -rw-r--r-- | src/Sema.zig | 272 | ||||
| -rw-r--r-- | src/Zir.zig | 10 | ||||
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 10 | ||||
| -rw-r--r-- | src/arch/arm/CodeGen.zig | 10 | ||||
| -rw-r--r-- | src/arch/riscv64/CodeGen.zig | 10 | ||||
| -rw-r--r-- | src/arch/sparc64/CodeGen.zig | 10 | ||||
| -rw-r--r-- | src/arch/wasm/CodeGen.zig | 2 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 11 | ||||
| -rw-r--r-- | src/codegen/c.zig | 4 | ||||
| -rw-r--r-- | src/codegen/llvm.zig | 44 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 2 | ||||
| -rw-r--r-- | src/print_air.zig | 2 | ||||
| -rw-r--r-- | src/print_zir.zig | 4 |
17 files changed, 169 insertions, 287 deletions
diff --git a/src/Air.zig b/src/Air.zig index fbd958dece..f316ed04e6 100644 --- a/src/Air.zig +++ b/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, diff --git a/src/AstGen.zig b/src/AstGen.zig index 9555aec681..375dafe880 100644 --- a/src/AstGen.zig +++ b/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 diff --git a/src/Liveness.zig b/src/Liveness.zig index d1283c502b..3b29c20ceb 100644 --- a/src/Liveness.zig +++ b/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, diff --git a/src/Liveness/Verify.zig b/src/Liveness/Verify.zig index bb3d1c67f9..de7981d18f 100644 --- a/src/Liveness/Verify.zig +++ b/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, diff --git a/src/Sema.zig b/src/Sema.zig index f54e489fbd..daacf6d089 100644 --- a/src/Sema.zig +++ b/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; @@ -5762,7 +5742,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 { @@ -5950,13 +5930,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"; @@ -5978,6 +5976,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(); @@ -5992,25 +5991,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); @@ -6388,24 +6419,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, @@ -6437,6 +6450,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. @@ -7590,7 +7612,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 @@ -11534,7 +11556,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 { @@ -12156,7 +12178,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 { @@ -13169,8 +13191,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, @@ -13422,8 +13442,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, @@ -13436,10 +13454,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; @@ -13505,8 +13520,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, => {}, @@ -19098,55 +19111,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; @@ -19487,8 +19509,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", .{}); diff --git a/src/Zir.zig b/src/Zir.zig index 61d1301167..3e6ffcc325 100644 --- a/src/Zir.zig +++ b/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, diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 750edb45a8..d85475f1fe 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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 diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index ed3434106f..c8011c90a7 100644 --- a/src/arch/arm/CodeGen.zig +++ b/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 diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index fe46d0ddb6..1c83b2efad 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/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); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index 9d5f8158ef..85e8fbecb7 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/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.?; diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 781190e13b..c3a9bb8895 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/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), diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 4ca2ae44bb..9c9c4a0064 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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).?; diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 0977acf7fe..d4747256bb 100644 --- a/src/codegen/c.zig +++ b/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), diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index bd0c337169..331af769ca 100644 --- a/src/codegen/llvm.zig +++ b/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, } } diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index dc3b646ab7..ca724c3879 100644 --- a/src/codegen/spirv.zig +++ b/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), diff --git a/src/print_air.zig b/src/print_air.zig index 6f9ac1f771..e4f4121299 100644 --- a/src/print_air.zig +++ b/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, diff --git a/src/print_zir.zig b/src/print_zir.zig index 226b09a5c4..711dcaa2a3 100644 --- a/src/print_zir.zig +++ b/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), |
