authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-09 17:54:32+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-06-11 11:02:56+03:00
log0f820d0bdf98b3f8429a9cf2f1b405c2c0a4d958
treed8793ad6cd0258eb704d35fc536636aac3fa45fc
parent002df65b6ec55684d6bc6790ae7b0c0f4abb1375

stage2: improve debugging tools

llvm: dump failed module when -femit-llvm-ir set print_air: * print fully qualified name * use Type.fmt and Value.fmtValue, fmtDebug is useless TypedValue * handle anon structs and tuples * fix bugs

5 files changed, 114 insertions(+), 28 deletions(-)

src/Module.zig+5-2
...@@ -3790,9 +3790,12 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {...@@ -3790,9 +3790,12 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void {
3790 defer liveness.deinit(gpa);3790 defer liveness.deinit(gpa);
37913791
3792 if (builtin.mode == .Debug and mod.comp.verbose_air) {3792 if (builtin.mode == .Debug and mod.comp.verbose_air) {
3793 std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name});3793 const fqn = try decl.getFullyQualifiedName(mod);
3794 defer mod.gpa.free(fqn);
3795
3796 std.debug.print("# Begin Function AIR: {s}:\n", .{fqn});
3794 @import("print_air.zig").dump(mod, air, liveness);3797 @import("print_air.zig").dump(mod, air, liveness);
3795 std.debug.print("# End Function AIR: {s}\n\n", .{decl.name});3798 std.debug.print("# End Function AIR: {s}\n\n", .{fqn});
3796 }3799 }
37973800
3798 mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {3801 mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) {
src/TypedValue.zig+64-11
...@@ -144,7 +144,41 @@ pub fn print(...@@ -144,7 +144,41 @@ pub fn print(
144 return writer.writeAll(".{ ... }");144 return writer.writeAll(".{ ... }");
145 }145 }
146 const vals = val.castTag(.aggregate).?.data;146 const vals = val.castTag(.aggregate).?.data;
147 if (ty.zigTypeTag() == .Struct) {147 if (ty.castTag(.anon_struct)) |anon_struct| {
148 const field_names = anon_struct.data.names;
149 const types = anon_struct.data.types;
150 const max_len = std.math.min(types.len, max_aggregate_items);
151
152 var i: u32 = 0;
153 while (i < max_len) : (i += 1) {
154 if (i != 0) try writer.writeAll(", ");
155 try writer.print(".{s} = ", .{field_names[i]});
156 try print(.{
157 .ty = types[i],
158 .val = vals[i],
159 }, writer, level - 1, mod);
160 }
161 if (types.len > max_aggregate_items) {
162 try writer.writeAll(", ...");
163 }
164 return writer.writeAll(" }");
165 } else if (ty.isTuple()) {
166 const fields = ty.tupleFields();
167 const max_len = std.math.min(fields.types.len, max_aggregate_items);
168
169 var i: u32 = 0;
170 while (i < max_len) : (i += 1) {
171 if (i != 0) try writer.writeAll(", ");
172 try print(.{
173 .ty = fields.types[i],
174 .val = vals[i],
175 }, writer, level - 1, mod);
176 }
177 if (fields.types.len > max_aggregate_items) {
178 try writer.writeAll(", ...");
179 }
180 return writer.writeAll(" }");
181 } else if (ty.zigTypeTag() == .Struct) {
148 try writer.writeAll(".{ ");182 try writer.writeAll(".{ ");
149 const struct_fields = ty.structFields();183 const struct_fields = ty.structFields();
150 const len = struct_fields.count();184 const len = struct_fields.count();
...@@ -194,7 +228,7 @@ pub fn print(...@@ -194,7 +228,7 @@ pub fn print(
194 try writer.writeAll(".{ ");228 try writer.writeAll(".{ ");
195229
196 try print(.{230 try print(.{
197 .ty = ty.unionTagType().?,231 .ty = ty.cast(Type.Payload.Union).?.data.tag_ty,
198 .val = union_val.tag,232 .val = union_val.tag,
199 }, writer, level - 1, mod);233 }, writer, level - 1, mod);
200 try writer.writeAll(" = ");234 try writer.writeAll(" = ");
...@@ -278,19 +312,27 @@ pub fn print(...@@ -278,19 +312,27 @@ pub fn print(
278 .elem_ptr => {312 .elem_ptr => {
279 const elem_ptr = val.castTag(.elem_ptr).?.data;313 const elem_ptr = val.castTag(.elem_ptr).?.data;
280 try writer.writeAll("&");314 try writer.writeAll("&");
281 try print(.{315 if (level == 0) {
282 .ty = elem_ptr.elem_ty,316 try writer.writeAll("(ptr)");
283 .val = elem_ptr.array_ptr,317 } else {
284 }, writer, level - 1, mod);318 try print(.{
319 .ty = elem_ptr.elem_ty,
320 .val = elem_ptr.array_ptr,
321 }, writer, level - 1, mod);
322 }
285 return writer.print("[{}]", .{elem_ptr.index});323 return writer.print("[{}]", .{elem_ptr.index});
286 },324 },
287 .field_ptr => {325 .field_ptr => {
288 const field_ptr = val.castTag(.field_ptr).?.data;326 const field_ptr = val.castTag(.field_ptr).?.data;
289 try writer.writeAll("&");327 try writer.writeAll("&");
290 try print(.{328 if (level == 0) {
291 .ty = field_ptr.container_ty,329 try writer.writeAll("(ptr)");
292 .val = field_ptr.container_ptr,330 } else {
293 }, writer, level - 1, mod);331 try print(.{
332 .ty = field_ptr.container_ty,
333 .val = field_ptr.container_ptr,
334 }, writer, level - 1, mod);
335 }
294336
295 if (field_ptr.container_ty.zigTypeTag() == .Struct) {337 if (field_ptr.container_ty.zigTypeTag() == .Struct) {
296 const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index];338 const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index];
...@@ -344,6 +386,9 @@ pub fn print(...@@ -344,6 +386,9 @@ pub fn print(
344 return writer.writeAll(" }");386 return writer.writeAll(" }");
345 },387 },
346 .slice => {388 .slice => {
389 if (level == 0) {
390 return writer.writeAll(".{ ... }");
391 }
347 const payload = val.castTag(.slice).?.data;392 const payload = val.castTag(.slice).?.data;
348 try writer.writeAll(".{ ");393 try writer.writeAll(".{ ");
349 const elem_ty = ty.elemType2();394 const elem_ty = ty.elemType2();
...@@ -372,17 +417,25 @@ pub fn print(...@@ -372,17 +417,25 @@ pub fn print(
372 .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),417 .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
373 .eu_payload => {418 .eu_payload => {
374 val = val.castTag(.eu_payload).?.data;419 val = val.castTag(.eu_payload).?.data;
420 ty = ty.errorUnionPayload();
375 },421 },
376 .opt_payload => {422 .opt_payload => {
377 val = val.castTag(.opt_payload).?.data;423 val = val.castTag(.opt_payload).?.data;
424 var buf: Type.Payload.ElemType = undefined;
425 ty = ty.optionalChild(&buf);
426 return print(.{ .ty = ty, .val = val }, writer, level, mod);
378 },427 },
379 .eu_payload_ptr => {428 .eu_payload_ptr => {
380 try writer.writeAll("&");429 try writer.writeAll("&");
381 val = val.castTag(.eu_payload_ptr).?.data.container_ptr;430 val = val.castTag(.eu_payload_ptr).?.data.container_ptr;
431 ty = ty.elemType2().errorUnionPayload();
382 },432 },
383 .opt_payload_ptr => {433 .opt_payload_ptr => {
384 try writer.writeAll("&");434 try writer.writeAll("&");
385 val = val.castTag(.opt_payload_ptr).?.data.container_ptr;435 val = val.castTag(.opt_payload).?.data;
436 var buf: Type.Payload.ElemType = undefined;
437 ty = ty.elemType2().optionalChild(&buf);
438 return print(.{ .ty = ty, .val = val }, writer, level, mod);
386 },439 },
387440
388 // TODO these should not appear in this function441 // TODO these should not appear in this function
src/codegen/llvm.zig+12-7
...@@ -599,6 +599,13 @@ pub const Object = struct {...@@ -599,6 +599,13 @@ pub const Object = struct {
599 self.llvm_module.dump();599 self.llvm_module.dump();
600 }600 }
601601
602 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
603 defer arena_allocator.deinit();
604 const arena = arena_allocator.allocator();
605
606 const mod = comp.bin_file.options.module.?;
607 const cache_dir = mod.zig_cache_artifact_directory;
608
602 if (std.debug.runtime_safety) {609 if (std.debug.runtime_safety) {
603 var error_message: [*:0]const u8 = undefined;610 var error_message: [*:0]const u8 = undefined;
604 // verifyModule always allocs the error_message even if there is no error611 // verifyModule always allocs the error_message even if there is no error
...@@ -606,17 +613,15 @@ pub const Object = struct {...@@ -606,17 +613,15 @@ pub const Object = struct {
606613
607 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {614 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
608 std.debug.print("\n{s}\n", .{error_message});615 std.debug.print("\n{s}\n", .{error_message});
616
617 if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path| {
618 _ = self.llvm_module.printModuleToFile(emit_llvm_ir_path, &error_message);
619 }
620
609 @panic("LLVM module verification failed");621 @panic("LLVM module verification failed");
610 }622 }
611 }623 }
612624
613 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
614 defer arena_allocator.deinit();
615 const arena = arena_allocator.allocator();
616
617 const mod = comp.bin_file.options.module.?;
618 const cache_dir = mod.zig_cache_artifact_directory;
619
620 var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|625 var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit|
621 try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?))626 try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?))
622 else627 else
src/codegen/llvm/bindings.zig+3
...@@ -390,6 +390,9 @@ pub const Module = opaque {...@@ -390,6 +390,9 @@ pub const Module = opaque {
390390
391 pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;391 pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2;
392 extern fn LLVMSetModuleInlineAsm2(M: *const Module, Asm: [*]const u8, Len: usize) void;392 extern fn LLVMSetModuleInlineAsm2(M: *const Module, Asm: [*]const u8, Len: usize) void;
393
394 pub const printModuleToFile = LLVMPrintModuleToFile;
395 extern fn LLVMPrintModuleToFile(M: *const Module, Filename: [*:0]const u8, ErrorMessage: *[*:0]const u8) Bool;
393};396};
394397
395pub const lookupIntrinsicID = LLVMLookupIntrinsicID;398pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
src/print_air.zig+30-8
...@@ -4,6 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;...@@ -4,6 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
44
5const Module = @import("Module.zig");5const Module = @import("Module.zig");
6const Value = @import("value.zig").Value;6const Value = @import("value.zig").Value;
7const Type = @import("type.zig").Type;
7const Air = @import("Air.zig");8const Air = @import("Air.zig");
8const Liveness = @import("Liveness.zig");9const Liveness = @import("Liveness.zig");
910
...@@ -304,14 +305,27 @@ const Writer = struct {...@@ -304,14 +305,27 @@ const Writer = struct {
304 // no-op, no argument to write305 // no-op, no argument to write
305 }306 }
306307
308 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
309 const t = ty.tag();
310 switch (t) {
311 .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"),
312 .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"),
313 .generic_poison => try s.writeAll("(generic_poison)"),
314 .var_args_param => try s.writeAll("(var_args_param)"),
315 .bound_fn => try s.writeAll("(bound_fn)"),
316 else => try ty.print(s, w.module),
317 }
318 }
319
307 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {320 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
308 const ty = w.air.instructions.items(.data)[inst].ty;321 const ty = w.air.instructions.items(.data)[inst].ty;
309 try s.print("{}", .{ty.fmtDebug()});322 try w.writeType(s, ty);
310 }323 }
311324
312 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {325 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
313 const ty_op = w.air.instructions.items(.data)[inst].ty_op;326 const ty_op = w.air.instructions.items(.data)[inst].ty_op;
314 try s.print("{}, ", .{w.air.getRefType(ty_op.ty).fmtDebug()});327 try w.writeType(s, w.air.getRefType(ty_op.ty));
328 try s.writeAll(", ");
315 try w.writeOperand(s, inst, 0, ty_op.operand);329 try w.writeOperand(s, inst, 0, ty_op.operand);
316 }330 }
317331
...@@ -320,7 +334,8 @@ const Writer = struct {...@@ -320,7 +334,8 @@ const Writer = struct {
320 const extra = w.air.extraData(Air.Block, ty_pl.payload);334 const extra = w.air.extraData(Air.Block, ty_pl.payload);
321 const body = w.air.extra[extra.end..][0..extra.data.body_len];335 const body = w.air.extra[extra.end..][0..extra.data.body_len];
322336
323 try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()});337 try w.writeType(s, w.air.getRefType(ty_pl.ty));
338 try s.writeAll(", {\n");
324 const old_indent = w.indent;339 const old_indent = w.indent;
325 w.indent += 2;340 w.indent += 2;
326 try w.writeBody(s, body);341 try w.writeBody(s, body);
...@@ -335,7 +350,8 @@ const Writer = struct {...@@ -335,7 +350,8 @@ const Writer = struct {
335 const len = @intCast(usize, vector_ty.arrayLen());350 const len = @intCast(usize, vector_ty.arrayLen());
336 const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]);351 const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]);
337352
338 try s.print("{}, [", .{vector_ty.fmtDebug()});353 try w.writeType(s, vector_ty);
354 try s.writeAll(", [");
339 for (elements) |elem, i| {355 for (elements) |elem, i| {
340 if (i != 0) try s.writeAll(", ");356 if (i != 0) try s.writeAll(", ");
341 try w.writeOperand(s, inst, i, elem);357 try w.writeOperand(s, inst, i, elem);
...@@ -408,7 +424,8 @@ const Writer = struct {...@@ -408,7 +424,8 @@ const Writer = struct {
408 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;424 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
409425
410 const elem_ty = w.air.typeOfIndex(inst).childType();426 const elem_ty = w.air.typeOfIndex(inst).childType();
411 try s.print("{}, ", .{elem_ty.fmtDebug()});427 try w.writeType(s, elem_ty);
428 try s.writeAll(", ");
412 try w.writeOperand(s, inst, 0, pl_op.operand);429 try w.writeOperand(s, inst, 0, pl_op.operand);
413 try s.writeAll(", ");430 try s.writeAll(", ");
414 try w.writeOperand(s, inst, 1, extra.lhs);431 try w.writeOperand(s, inst, 1, extra.lhs);
...@@ -511,7 +528,9 @@ const Writer = struct {...@@ -511,7 +528,9 @@ const Writer = struct {
511 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {528 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
512 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;529 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
513 const val = w.air.values[ty_pl.payload];530 const val = w.air.values[ty_pl.payload];
514 try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty).fmtDebug(), val.fmtDebug() });531 const ty = w.air.getRefType(ty_pl.ty);
532 try w.writeType(s, ty);
533 try s.print(", {}", .{val.fmtValue(ty, w.module)});
515 }534 }
516535
517 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {536 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
...@@ -523,7 +542,7 @@ const Writer = struct {...@@ -523,7 +542,7 @@ const Writer = struct {
523 var op_index: usize = 0;542 var op_index: usize = 0;
524543
525 const ret_ty = w.air.typeOfIndex(inst);544 const ret_ty = w.air.typeOfIndex(inst);
526 try s.print("{}", .{ret_ty.fmtDebug()});545 try w.writeType(s, ret_ty);
527546
528 if (is_volatile) {547 if (is_volatile) {
529 try s.writeAll(", volatile");548 try s.writeAll(", volatile");
...@@ -647,7 +666,10 @@ const Writer = struct {...@@ -647,7 +666,10 @@ const Writer = struct {
647 const body = w.air.extra[extra.end..][0..extra.data.body_len];666 const body = w.air.extra[extra.end..][0..extra.data.body_len];
648667
649 try w.writeOperand(s, inst, 0, extra.data.ptr);668 try w.writeOperand(s, inst, 0, extra.data.ptr);
650 try s.print(", {}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()});669
670 try s.writeAll(", ");
671 try w.writeType(s, w.air.getRefType(ty_pl.ty));
672 try s.writeAll(", {\n");
651 const old_indent = w.indent;673 const old_indent = w.indent;
652 w.indent += 2;674 w.indent += 2;
653 try w.writeBody(s, body);675 try w.writeBody(s, body);