From 0f820d0bdf98b3f8429a9cf2f1b405c2c0a4d958 Mon Sep 17 00:00:00 2001 From: Veikka Tuominen Date: Thu, 9 Jun 2022 17:54:32 +0300 Subject: [PATCH] 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 --- src/Module.zig | 7 +++- src/TypedValue.zig | 75 ++++++++++++++++++++++++++++++----- src/codegen/llvm.zig | 19 +++++---- src/codegen/llvm/bindings.zig | 3 ++ src/print_air.zig | 38 ++++++++++++++---- 5 files changed, 114 insertions(+), 28 deletions(-) diff --git a/src/Module.zig b/src/Module.zig index f03ba77a39..bcf6491ce6 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3790,9 +3790,12 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func: *Fn) SemaError!void { defer liveness.deinit(gpa); if (builtin.mode == .Debug and mod.comp.verbose_air) { - std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name}); + const fqn = try decl.getFullyQualifiedName(mod); + defer mod.gpa.free(fqn); + + std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); @import("print_air.zig").dump(mod, air, liveness); - std.debug.print("# End Function AIR: {s}\n\n", .{decl.name}); + std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); } mod.comp.bin_file.updateFunc(mod, func, air, liveness) catch |err| switch (err) { diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 4b3bc23231..3c1b28e544 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -144,7 +144,41 @@ pub fn print( return writer.writeAll(".{ ... }"); } const vals = val.castTag(.aggregate).?.data; - if (ty.zigTypeTag() == .Struct) { + if (ty.castTag(.anon_struct)) |anon_struct| { + const field_names = anon_struct.data.names; + const types = anon_struct.data.types; + const max_len = std.math.min(types.len, max_aggregate_items); + + var i: u32 = 0; + while (i < max_len) : (i += 1) { + if (i != 0) try writer.writeAll(", "); + try writer.print(".{s} = ", .{field_names[i]}); + try print(.{ + .ty = types[i], + .val = vals[i], + }, writer, level - 1, mod); + } + if (types.len > max_aggregate_items) { + try writer.writeAll(", ..."); + } + return writer.writeAll(" }"); + } else if (ty.isTuple()) { + const fields = ty.tupleFields(); + const max_len = std.math.min(fields.types.len, max_aggregate_items); + + var i: u32 = 0; + while (i < max_len) : (i += 1) { + if (i != 0) try writer.writeAll(", "); + try print(.{ + .ty = fields.types[i], + .val = vals[i], + }, writer, level - 1, mod); + } + if (fields.types.len > max_aggregate_items) { + try writer.writeAll(", ..."); + } + return writer.writeAll(" }"); + } else if (ty.zigTypeTag() == .Struct) { try writer.writeAll(".{ "); const struct_fields = ty.structFields(); const len = struct_fields.count(); @@ -194,7 +228,7 @@ pub fn print( try writer.writeAll(".{ "); try print(.{ - .ty = ty.unionTagType().?, + .ty = ty.cast(Type.Payload.Union).?.data.tag_ty, .val = union_val.tag, }, writer, level - 1, mod); try writer.writeAll(" = "); @@ -278,19 +312,27 @@ pub fn print( .elem_ptr => { const elem_ptr = val.castTag(.elem_ptr).?.data; try writer.writeAll("&"); - try print(.{ - .ty = elem_ptr.elem_ty, - .val = elem_ptr.array_ptr, - }, writer, level - 1, mod); + if (level == 0) { + try writer.writeAll("(ptr)"); + } else { + try print(.{ + .ty = elem_ptr.elem_ty, + .val = elem_ptr.array_ptr, + }, writer, level - 1, mod); + } return writer.print("[{}]", .{elem_ptr.index}); }, .field_ptr => { const field_ptr = val.castTag(.field_ptr).?.data; try writer.writeAll("&"); - try print(.{ - .ty = field_ptr.container_ty, - .val = field_ptr.container_ptr, - }, writer, level - 1, mod); + if (level == 0) { + try writer.writeAll("(ptr)"); + } else { + try print(.{ + .ty = field_ptr.container_ty, + .val = field_ptr.container_ptr, + }, writer, level - 1, mod); + } if (field_ptr.container_ty.zigTypeTag() == .Struct) { const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index]; @@ -344,6 +386,9 @@ pub fn print( return writer.writeAll(" }"); }, .slice => { + if (level == 0) { + return writer.writeAll(".{ ... }"); + } const payload = val.castTag(.slice).?.data; try writer.writeAll(".{ "); const elem_ty = ty.elemType2(); @@ -372,17 +417,25 @@ pub fn print( .@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}), .eu_payload => { val = val.castTag(.eu_payload).?.data; + ty = ty.errorUnionPayload(); }, .opt_payload => { val = val.castTag(.opt_payload).?.data; + var buf: Type.Payload.ElemType = undefined; + ty = ty.optionalChild(&buf); + return print(.{ .ty = ty, .val = val }, writer, level, mod); }, .eu_payload_ptr => { try writer.writeAll("&"); val = val.castTag(.eu_payload_ptr).?.data.container_ptr; + ty = ty.elemType2().errorUnionPayload(); }, .opt_payload_ptr => { try writer.writeAll("&"); - val = val.castTag(.opt_payload_ptr).?.data.container_ptr; + val = val.castTag(.opt_payload).?.data; + var buf: Type.Payload.ElemType = undefined; + ty = ty.elemType2().optionalChild(&buf); + return print(.{ .ty = ty, .val = val }, writer, level, mod); }, // TODO these should not appear in this function diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 19a6917be4..8031c4635e 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -599,6 +599,13 @@ pub const Object = struct { self.llvm_module.dump(); } + var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + const mod = comp.bin_file.options.module.?; + const cache_dir = mod.zig_cache_artifact_directory; + if (std.debug.runtime_safety) { var error_message: [*:0]const u8 = undefined; // verifyModule always allocs the error_message even if there is no error @@ -606,17 +613,15 @@ pub const Object = struct { if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) { std.debug.print("\n{s}\n", .{error_message}); + + if (try locPath(arena, comp.emit_llvm_ir, cache_dir)) |emit_llvm_ir_path| { + _ = self.llvm_module.printModuleToFile(emit_llvm_ir_path, &error_message); + } + @panic("LLVM module verification failed"); } } - var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - - const mod = comp.bin_file.options.module.?; - const cache_dir = mod.zig_cache_artifact_directory; - var emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit) |emit| try emit.basenamePath(arena, try arena.dupeZ(u8, comp.bin_file.intermediary_basename.?)) else diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index ca748d3ce3..671014ba3b 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -390,6 +390,9 @@ pub const Module = opaque { pub const setModuleInlineAsm2 = LLVMSetModuleInlineAsm2; extern fn LLVMSetModuleInlineAsm2(M: *const Module, Asm: [*]const u8, Len: usize) void; + + pub const printModuleToFile = LLVMPrintModuleToFile; + extern fn LLVMPrintModuleToFile(M: *const Module, Filename: [*:0]const u8, ErrorMessage: *[*:0]const u8) Bool; }; pub const lookupIntrinsicID = LLVMLookupIntrinsicID; diff --git a/src/print_air.zig b/src/print_air.zig index af1bcb8cfb..d6db7ca75f 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -4,6 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin; const Module = @import("Module.zig"); const Value = @import("value.zig").Value; +const Type = @import("type.zig").Type; const Air = @import("Air.zig"); const Liveness = @import("Liveness.zig"); @@ -304,14 +305,27 @@ const Writer = struct { // no-op, no argument to write } + fn writeType(w: *Writer, s: anytype, ty: Type) !void { + const t = ty.tag(); + switch (t) { + .inferred_alloc_const => try s.writeAll("(inferred_alloc_const)"), + .inferred_alloc_mut => try s.writeAll("(inferred_alloc_mut)"), + .generic_poison => try s.writeAll("(generic_poison)"), + .var_args_param => try s.writeAll("(var_args_param)"), + .bound_fn => try s.writeAll("(bound_fn)"), + else => try ty.print(s, w.module), + } + } + fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty = w.air.instructions.items(.data)[inst].ty; - try s.print("{}", .{ty.fmtDebug()}); + try w.writeType(s, ty); } fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_op = w.air.instructions.items(.data)[inst].ty_op; - try s.print("{}, ", .{w.air.getRefType(ty_op.ty).fmtDebug()}); + try w.writeType(s, w.air.getRefType(ty_op.ty)); + try s.writeAll(", "); try w.writeOperand(s, inst, 0, ty_op.operand); } @@ -320,7 +334,8 @@ const Writer = struct { const extra = w.air.extraData(Air.Block, ty_pl.payload); const body = w.air.extra[extra.end..][0..extra.data.body_len]; - try s.print("{}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()}); + try w.writeType(s, w.air.getRefType(ty_pl.ty)); + try s.writeAll(", {\n"); const old_indent = w.indent; w.indent += 2; try w.writeBody(s, body); @@ -335,7 +350,8 @@ const Writer = struct { const len = @intCast(usize, vector_ty.arrayLen()); const elements = @ptrCast([]const Air.Inst.Ref, w.air.extra[ty_pl.payload..][0..len]); - try s.print("{}, [", .{vector_ty.fmtDebug()}); + try w.writeType(s, vector_ty); + try s.writeAll(", ["); for (elements) |elem, i| { if (i != 0) try s.writeAll(", "); try w.writeOperand(s, inst, i, elem); @@ -408,7 +424,8 @@ const Writer = struct { const extra = w.air.extraData(Air.Bin, pl_op.payload).data; const elem_ty = w.air.typeOfIndex(inst).childType(); - try s.print("{}, ", .{elem_ty.fmtDebug()}); + try w.writeType(s, elem_ty); + try s.writeAll(", "); try w.writeOperand(s, inst, 0, pl_op.operand); try s.writeAll(", "); try w.writeOperand(s, inst, 1, extra.lhs); @@ -511,7 +528,9 @@ const Writer = struct { fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_pl = w.air.instructions.items(.data)[inst].ty_pl; const val = w.air.values[ty_pl.payload]; - try s.print("{}, {}", .{ w.air.getRefType(ty_pl.ty).fmtDebug(), val.fmtDebug() }); + const ty = w.air.getRefType(ty_pl.ty); + try w.writeType(s, ty); + try s.print(", {}", .{val.fmtValue(ty, w.module)}); } fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { @@ -523,7 +542,7 @@ const Writer = struct { var op_index: usize = 0; const ret_ty = w.air.typeOfIndex(inst); - try s.print("{}", .{ret_ty.fmtDebug()}); + try w.writeType(s, ret_ty); if (is_volatile) { try s.writeAll(", volatile"); @@ -647,7 +666,10 @@ const Writer = struct { const body = w.air.extra[extra.end..][0..extra.data.body_len]; try w.writeOperand(s, inst, 0, extra.data.ptr); - try s.print(", {}, {{\n", .{w.air.getRefType(ty_pl.ty).fmtDebug()}); + + try s.writeAll(", "); + try w.writeType(s, w.air.getRefType(ty_pl.ty)); + try s.writeAll(", {\n"); const old_indent = w.indent; w.indent += 2; try w.writeBody(s, body);