Skip to content

Commit 0bc9635

Browse files
committed
stage2: add debug info for locals in the LLVM backend
Adds 2 new AIR instructions: * dbg_var_ptr * dbg_var_val Sema no longer emits dbg_stmt AIR instructions when strip=true. LLVM backend: fixed lowerPtrToVoid when calling ptrAlignment on the element type is problematic. LLVM backend: fixed alloca instructions improperly getting debug location annotated, causing chaotic debug info behavior. zig_llvm.cpp: fixed incorrect bindings for a function that should use unsigned integers for line and column. A bunch of C test cases regressed because the new dbg_var AIR instructions caused their operands to be alive, exposing latent bugs. Mostly it's just a problem that the C backend lowers mutable and const slices to the same C type, so we need to represent that in the C backend instead of printing two duplicate typedefs.
1 parent 7ec2261 commit 0bc9635

29 files changed

+338
-26
lines changed

src/Air.zig

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ pub const Inst = struct {
327327
/// Result type is always void.
328328
/// Uses the `dbg_stmt` field.
329329
dbg_stmt,
330+
/// Marks the beginning of a local variable. The operand is a pointer pointing
331+
/// to the storage for the variable. The local may be a const or a var.
332+
/// Result type is always void.
333+
/// Uses `pl_op`. The payload index is the variable name. It points to the extra
334+
/// array, reinterpreting the bytes there as a null-terminated string.
335+
dbg_var_ptr,
336+
/// Same as `dbg_var_ptr` except the local is a const, not a var, and the
337+
/// operand is the local's value.
338+
dbg_var_val,
330339
/// ?T => bool
331340
/// Result type is always bool.
332341
/// Uses the `un_op` field.
@@ -962,6 +971,8 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
962971

963972
.breakpoint,
964973
.dbg_stmt,
974+
.dbg_var_ptr,
975+
.dbg_var_val,
965976
.store,
966977
.fence,
967978
.atomic_store_unordered,
@@ -972,13 +983,13 @@ pub fn typeOfIndex(air: Air, inst: Air.Inst.Index) Type {
972983
.memcpy,
973984
.set_union_tag,
974985
.prefetch,
975-
=> return Type.initTag(.void),
986+
=> return Type.void,
976987

977988
.ptrtoint,
978989
.slice_len,
979990
.ret_addr,
980991
.frame_addr,
981-
=> return Type.initTag(.usize),
992+
=> return Type.usize,
982993

983994
.wasm_memory_grow => return Type.i32,
984995
.wasm_memory_size => return Type.u32,
@@ -1089,3 +1100,12 @@ pub fn value(air: Air, inst: Air.Inst.Ref) ?Value {
10891100
else => return air.typeOfIndex(inst_index).onePossibleValue(),
10901101
}
10911102
}
1103+
1104+
pub fn nullTerminatedString(air: Air, index: usize) [:0]const u8 {
1105+
const bytes = std.mem.sliceAsBytes(air.extra[index..]);
1106+
var end: usize = 0;
1107+
while (bytes[end] != 0) {
1108+
end += 1;
1109+
}
1110+
return bytes[0..end :0];
1111+
}

src/AstGen.zig

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2389,6 +2389,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
23892389
.breakpoint,
23902390
.fence,
23912391
.dbg_stmt,
2392+
.dbg_var_ptr,
2393+
.dbg_var_val,
23922394
.ensure_result_used,
23932395
.ensure_result_non_error,
23942396
.@"export",
@@ -2666,6 +2668,15 @@ fn varDecl(
26662668
} else .none;
26672669
const init_inst = try reachableExpr(gz, scope, result_loc, var_decl.ast.init_node, node);
26682670

2671+
if (!gz.force_comptime) {
2672+
_ = try gz.add(.{ .tag = .dbg_var_val, .data = .{
2673+
.str_op = .{
2674+
.str = ident_name,
2675+
.operand = init_inst,
2676+
},
2677+
} });
2678+
}
2679+
26692680
const sub_scope = try block_arena.create(Scope.LocalVal);
26702681
sub_scope.* = .{
26712682
.parent = scope,
@@ -2751,6 +2762,15 @@ fn varDecl(
27512762
}
27522763
gz.instructions.items.len = dst;
27532764

2765+
if (!gz.force_comptime) {
2766+
_ = try gz.add(.{ .tag = .dbg_var_val, .data = .{
2767+
.str_op = .{
2768+
.str = ident_name,
2769+
.operand = init_inst,
2770+
},
2771+
} });
2772+
}
2773+
27542774
const sub_scope = try block_arena.create(Scope.LocalVal);
27552775
sub_scope.* = .{
27562776
.parent = scope,
@@ -2785,6 +2805,16 @@ fn varDecl(
27852805
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
27862806
}
27872807
const const_ptr = try gz.addUnNode(.make_ptr_const, init_scope.rl_ptr, node);
2808+
2809+
if (!gz.force_comptime) {
2810+
_ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{
2811+
.str_op = .{
2812+
.str = ident_name,
2813+
.operand = const_ptr,
2814+
},
2815+
} });
2816+
}
2817+
27882818
const sub_scope = try block_arena.create(Scope.LocalPtr);
27892819
sub_scope.* = .{
27902820
.parent = scope,
@@ -2848,6 +2878,16 @@ fn varDecl(
28482878
if (resolve_inferred_alloc != .none) {
28492879
_ = try gz.addUnNode(.resolve_inferred_alloc, resolve_inferred_alloc, node);
28502880
}
2881+
2882+
if (!gz.force_comptime) {
2883+
_ = try gz.add(.{ .tag = .dbg_var_ptr, .data = .{
2884+
.str_op = .{
2885+
.str = ident_name,
2886+
.operand = var_data.alloc,
2887+
},
2888+
} });
2889+
}
2890+
28512891
const sub_scope = try block_arena.create(Scope.LocalPtr);
28522892
sub_scope.* = .{
28532893
.parent = scope,

src/Liveness.zig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,13 @@ fn analyzeInst(
394394
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
395395
},
396396

397+
.dbg_var_ptr,
398+
.dbg_var_val,
399+
=> {
400+
const operand = inst_datas[inst].pl_op.operand;
401+
return trackOperands(a, new_set, inst, main_tomb, .{ operand, .none, .none });
402+
},
403+
397404
.prefetch => {
398405
const prefetch = inst_datas[inst].prefetch;
399406
return trackOperands(a, new_set, inst, main_tomb, .{ prefetch.ptr, .none, .none });

src/Sema.zig

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,16 @@ fn analyzeBodyInner(
872872
i += 1;
873873
continue;
874874
},
875+
.dbg_var_ptr => {
876+
try sema.zirDbgVar(block, inst, .dbg_var_ptr);
877+
i += 1;
878+
continue;
879+
},
880+
.dbg_var_val => {
881+
try sema.zirDbgVar(block, inst, .dbg_var_val);
882+
i += 1;
883+
continue;
884+
},
875885
.ensure_err_payload_void => {
876886
try sema.zirEnsureErrPayloadVoid(block, inst);
877887
i += 1;
@@ -4158,14 +4168,11 @@ fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError
41584168
}
41594169

41604170
fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
4161-
const tracy = trace(@src());
4162-
defer tracy.end();
4163-
41644171
// We do not set sema.src here because dbg_stmt instructions are only emitted for
41654172
// ZIR code that possibly will need to generate runtime code. So error messages
41664173
// and other source locations must not rely on sema.src being set from dbg_stmt
41674174
// instructions.
4168-
if (block.is_comptime) return;
4175+
if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
41694176

41704177
const inst_data = sema.code.instructions.items(.data)[inst].dbg_stmt;
41714178
_ = try block.addInst(.{
@@ -4177,6 +4184,38 @@ fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!voi
41774184
});
41784185
}
41794186

4187+
fn zirDbgVar(
4188+
sema: *Sema,
4189+
block: *Block,
4190+
inst: Zir.Inst.Index,
4191+
air_tag: Air.Inst.Tag,
4192+
) CompileError!void {
4193+
if (block.is_comptime or sema.mod.comp.bin_file.options.strip) return;
4194+
4195+
const str_op = sema.code.instructions.items(.data)[inst].str_op;
4196+
const operand = sema.resolveInst(str_op.operand);
4197+
const operand_ty = sema.typeOf(operand);
4198+
if (!(try sema.typeHasRuntimeBits(block, sema.src, operand_ty))) return;
4199+
const name = str_op.getStr(sema.code);
4200+
4201+
// Add the name to the AIR.
4202+
const name_extra_index = @intCast(u32, sema.air_extra.items.len);
4203+
const elements_used = name.len / 4 + 1;
4204+
try sema.air_extra.ensureUnusedCapacity(sema.gpa, elements_used);
4205+
const buffer = mem.sliceAsBytes(sema.air_extra.unusedCapacitySlice());
4206+
mem.copy(u8, buffer, name);
4207+
buffer[name.len] = 0;
4208+
sema.air_extra.items.len += elements_used;
4209+
4210+
_ = try block.addInst(.{
4211+
.tag = air_tag,
4212+
.data = .{ .pl_op = .{
4213+
.payload = name_extra_index,
4214+
.operand = operand,
4215+
} },
4216+
});
4217+
}
4218+
41804219
fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
41814220
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
41824221
const src = inst_data.src();

src/Zir.zig

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,14 @@ pub const Inst = struct {
322322
/// Uses the `dbg_stmt` union field. The line and column are offset
323323
/// from the parent declaration.
324324
dbg_stmt,
325+
/// Marks a variable declaration. Used for debug info.
326+
/// Uses the `str_op` union field. The string is the local variable name,
327+
/// and the operand is the pointer to the variable's location. The local
328+
/// may be a const or a var.
329+
dbg_var_ptr,
330+
/// Same as `dbg_var_ptr` but the local is always a const and the operand
331+
/// is the local's value.
332+
dbg_var_val,
325333
/// Uses a name to identify a Decl and takes a pointer to it.
326334
/// Uses the `str_tok` union field.
327335
decl_ref,
@@ -1032,6 +1040,8 @@ pub const Inst = struct {
10321040
.error_set_decl_anon,
10331041
.error_set_decl_func,
10341042
.dbg_stmt,
1043+
.dbg_var_ptr,
1044+
.dbg_var_val,
10351045
.decl_ref,
10361046
.decl_val,
10371047
.load,
@@ -1297,6 +1307,8 @@ pub const Inst = struct {
12971307
.error_set_decl_anon = .pl_node,
12981308
.error_set_decl_func = .pl_node,
12991309
.dbg_stmt = .dbg_stmt,
1310+
.dbg_var_ptr = .str_op,
1311+
.dbg_var_val = .str_op,
13001312
.decl_ref = .str_tok,
13011313
.decl_val = .str_tok,
13021314
.load = .un_node,
@@ -2232,6 +2244,15 @@ pub const Inst = struct {
22322244
return .{ .node_offset = self.src_node };
22332245
}
22342246
},
2247+
str_op: struct {
2248+
/// Offset into `string_bytes`. Null-terminated.
2249+
str: u32,
2250+
operand: Ref,
2251+
2252+
pub fn getStr(self: @This(), zir: Zir) [:0]const u8 {
2253+
return zir.nullTerminatedString(self.str);
2254+
}
2255+
},
22352256

22362257
// Make sure we don't accidentally add a field to make this union
22372258
// bigger than expected. Note that in Debug builds, Zig is allowed
@@ -2268,6 +2289,7 @@ pub const Inst = struct {
22682289
switch_capture,
22692290
dbg_stmt,
22702291
inst_node,
2292+
str_op,
22712293
};
22722294
};
22732295

src/arch/aarch64/CodeGen.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
643643
.prefetch => try self.airPrefetch(inst),
644644
.mul_add => try self.airMulAdd(inst),
645645

646+
.dbg_var_ptr,
647+
.dbg_var_val,
648+
=> try self.airDbgVar(inst),
649+
646650
.call => try self.airCall(inst, .auto),
647651
.call_always_tail => try self.airCall(inst, .always_tail),
648652
.call_never_tail => try self.airCall(inst, .never_tail),
@@ -2650,6 +2654,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
26502654
return self.finishAirBookkeeping();
26512655
}
26522656

2657+
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
2658+
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2659+
const name = self.air.nullTerminatedString(pl_op.payload);
2660+
const operand = pl_op.operand;
2661+
// TODO emit debug info for this variable
2662+
_ = name;
2663+
return self.finishAir(inst, .dead, .{ operand, .none, .none });
2664+
}
2665+
26532666
fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
26542667
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
26552668
const cond = try self.resolveInst(pl_op.operand);

src/arch/arm/CodeGen.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
642642
.prefetch => try self.airPrefetch(inst),
643643
.mul_add => try self.airMulAdd(inst),
644644

645+
.dbg_var_ptr,
646+
.dbg_var_val,
647+
=> try self.airDbgVar(inst),
648+
645649
.call => try self.airCall(inst, .auto),
646650
.call_always_tail => try self.airCall(inst, .always_tail),
647651
.call_never_tail => try self.airCall(inst, .never_tail),
@@ -2831,6 +2835,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
28312835
return self.finishAirBookkeeping();
28322836
}
28332837

2838+
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
2839+
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
2840+
const name = self.air.nullTerminatedString(pl_op.payload);
2841+
const operand = pl_op.operand;
2842+
// TODO emit debug info for this variable
2843+
_ = name;
2844+
return self.finishAir(inst, .dead, .{ operand, .none, .none });
2845+
}
2846+
28342847
fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
28352848
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
28362849
const cond = try self.resolveInst(pl_op.operand);

src/arch/riscv64/CodeGen.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
609609
.prefetch => try self.airPrefetch(inst),
610610
.mul_add => try self.airMulAdd(inst),
611611

612+
.dbg_var_ptr,
613+
.dbg_var_val,
614+
=> try self.airDbgVar(inst),
615+
612616
.call => try self.airCall(inst, .auto),
613617
.call_always_tail => try self.airCall(inst, .always_tail),
614618
.call_never_tail => try self.airCall(inst, .never_tail),
@@ -1636,6 +1640,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
16361640
return self.finishAirBookkeeping();
16371641
}
16381642

1643+
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
1644+
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
1645+
const name = self.air.nullTerminatedString(pl_op.payload);
1646+
const operand = pl_op.operand;
1647+
// TODO emit debug info for this variable
1648+
_ = name;
1649+
return self.finishAir(inst, .dead, .{ operand, .none, .none });
1650+
}
1651+
16391652
fn airCondBr(self: *Self, inst: Air.Inst.Index) !void {
16401653
_ = inst;
16411654

src/arch/wasm/CodeGen.zig

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1219,13 +1219,18 @@ fn genInst(self: *Self, inst: Air.Inst.Index) !WValue {
12191219
.br => self.airBr(inst),
12201220
.bool_to_int => self.airBoolToInt(inst),
12211221
.cond_br => self.airCondBr(inst),
1222-
.dbg_stmt => WValue.none,
12231222
.intcast => self.airIntcast(inst),
12241223
.fptrunc => self.airFptrunc(inst),
12251224
.fpext => self.airFpext(inst),
12261225
.float_to_int => self.airFloatToInt(inst),
12271226
.get_union_tag => self.airGetUnionTag(inst),
12281227

1228+
// TODO
1229+
.dbg_stmt,
1230+
.dbg_var_ptr,
1231+
.dbg_var_val,
1232+
=> WValue.none,
1233+
12291234
.call => self.airCall(inst, .auto),
12301235
.call_always_tail => self.airCall(inst, .always_tail),
12311236
.call_never_tail => self.airCall(inst, .never_tail),

src/arch/x86_64/CodeGen.zig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
726726
.prefetch => try self.airPrefetch(inst),
727727
.mul_add => try self.airMulAdd(inst),
728728

729+
.dbg_var_ptr,
730+
.dbg_var_val,
731+
=> try self.airDbgVar(inst),
732+
729733
.call => try self.airCall(inst, .auto),
730734
.call_always_tail => try self.airCall(inst, .always_tail),
731735
.call_never_tail => try self.airCall(inst, .never_tail),
@@ -3666,6 +3670,15 @@ fn airDbgStmt(self: *Self, inst: Air.Inst.Index) !void {
36663670
return self.finishAirBookkeeping();
36673671
}
36683672

3673+
fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
3674+
const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3675+
const name = self.air.nullTerminatedString(pl_op.payload);
3676+
const operand = pl_op.operand;
3677+
// TODO emit debug info for this variable
3678+
_ = name;
3679+
return self.finishAir(inst, .dead, .{ operand, .none, .none });
3680+
}
3681+
36693682
fn genCondBrMir(self: *Self, ty: Type, mcv: MCValue) !u32 {
36703683
const abi_size = ty.abiSize(self.target.*);
36713684
switch (mcv) {

0 commit comments

Comments
 (0)