diff --git a/BRANCH_TODO b/BRANCH_TODO deleted file mode 100644 index 9055cda307..0000000000 --- a/BRANCH_TODO +++ /dev/null @@ -1,566 +0,0 @@ - * be sure to test debug info of parameters - - - pub fn specialOperandDeaths(self: Inst) bool { - return (self.deaths & (1 << deaths_bits)) != 0; - } - - /// Returns `null` if runtime-known. - /// Should be called by codegen, not by Sema. Sema functions should call - /// `resolvePossiblyUndefinedValue` or `resolveDefinedValue` instead. - /// TODO audit Sema code for violations to the above guidance. - pub fn value(base: *Inst) ?Value { - if (base.ty.onePossibleValue()) |opv| return opv; - - const inst = base.castTag(.constant) orelse return null; - return inst.val; - } - - - -/// For debugging purposes, prints a function representation to stderr. -pub fn dumpFn(old_module: Module, module_fn: *Module.Fn) void { - const allocator = old_module.gpa; - var ctx: DumpAir = .{ - .allocator = allocator, - .arena = std.heap.ArenaAllocator.init(allocator), - .old_module = &old_module, - .module_fn = module_fn, - .indent = 2, - .inst_table = DumpAir.InstTable.init(allocator), - .partial_inst_table = DumpAir.InstTable.init(allocator), - .const_table = DumpAir.InstTable.init(allocator), - }; - defer ctx.inst_table.deinit(); - defer ctx.partial_inst_table.deinit(); - defer ctx.const_table.deinit(); - defer ctx.arena.deinit(); - - switch (module_fn.state) { - .queued => std.debug.print("(queued)", .{}), - .inline_only => std.debug.print("(inline_only)", .{}), - .in_progress => std.debug.print("(in_progress)", .{}), - .sema_failure => std.debug.print("(sema_failure)", .{}), - .dependency_failure => std.debug.print("(dependency_failure)", .{}), - .success => { - const writer = std.io.getStdErr().writer(); - ctx.dump(module_fn.body, writer) catch @panic("failed to dump AIR"); - }, - } -} - -const DumpAir = struct { - allocator: *std.mem.Allocator, - arena: std.heap.ArenaAllocator, - old_module: *const Module, - module_fn: *Module.Fn, - indent: usize, - inst_table: InstTable, - partial_inst_table: InstTable, - const_table: InstTable, - next_index: usize = 0, - next_partial_index: usize = 0, - next_const_index: usize = 0, - - const InstTable = std.AutoArrayHashMap(*Inst, usize); - - /// TODO: Improve this code to include a stack of Body and store the instructions - /// in there. Now we are putting all the instructions in a function local table, - /// however instructions that are in a Body can be thown away when the Body ends. - fn dump(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) !void { - // First pass to pre-populate the table so that we can show even invalid references. - // Must iterate the same order we iterate the second time. - // We also look for constants and put them in the const_table. - try dtz.fetchInstsAndResolveConsts(body); - - std.debug.print("Module.Function(name={s}):\n", .{dtz.module_fn.owner_decl.name}); - - var it = dtz.const_table.iterator(); - while (it.next()) |entry| { - const constant = entry.key_ptr.*.castTag(.constant).?; - try writer.print(" @{d}: {} = {};\n", .{ - entry.value_ptr.*, constant.base.ty, constant.val, - }); - } - - return dtz.dumpBody(body, writer); - } - - fn fetchInstsAndResolveConsts(dtz: *DumpAir, body: Body) error{OutOfMemory}!void { - for (body.instructions) |inst| { - try dtz.inst_table.put(inst, dtz.next_index); - dtz.next_index += 1; - switch (inst.tag) { - .alloc, - .retvoid, - .unreach, - .breakpoint, - .dbg_stmt, - .arg, - => {}, - - .ref, - .ret, - .bitcast, - .not, - .is_non_null, - .is_non_null_ptr, - .is_null, - .is_null_ptr, - .is_err, - .is_non_err, - .is_err_ptr, - .is_non_err_ptr, - .ptrtoint, - .floatcast, - .intcast, - .load, - .optional_payload, - .optional_payload_ptr, - .wrap_optional, - .wrap_errunion_payload, - .wrap_errunion_err, - .unwrap_errunion_payload, - .unwrap_errunion_err, - .unwrap_errunion_payload_ptr, - .unwrap_errunion_err_ptr, - => { - const un_op = inst.cast(Inst.UnOp).?; - try dtz.findConst(un_op.operand); - }, - - .add, - .addwrap, - .sub, - .subwrap, - .mul, - .mulwrap, - .div, - .cmp_lt, - .cmp_lte, - .cmp_eq, - .cmp_gte, - .cmp_gt, - .cmp_neq, - .store, - .bool_and, - .bool_or, - .bit_and, - .bit_or, - .xor, - => { - const bin_op = inst.cast(Inst.BinOp).?; - try dtz.findConst(bin_op.lhs); - try dtz.findConst(bin_op.rhs); - }, - - .br => { - const br = inst.castTag(.br).?; - try dtz.findConst(&br.block.base); - try dtz.findConst(br.operand); - }, - - .br_block_flat => { - const br_block_flat = inst.castTag(.br_block_flat).?; - try dtz.findConst(&br_block_flat.block.base); - try dtz.fetchInstsAndResolveConsts(br_block_flat.body); - }, - - .br_void => { - const br_void = inst.castTag(.br_void).?; - try dtz.findConst(&br_void.block.base); - }, - - .block => { - const block = inst.castTag(.block).?; - try dtz.fetchInstsAndResolveConsts(block.body); - }, - - .condbr => { - const condbr = inst.castTag(.condbr).?; - try dtz.findConst(condbr.condition); - try dtz.fetchInstsAndResolveConsts(condbr.then_body); - try dtz.fetchInstsAndResolveConsts(condbr.else_body); - }, - .switchbr => { - const switchbr = inst.castTag(.switchbr).?; - try dtz.findConst(switchbr.target); - try dtz.fetchInstsAndResolveConsts(switchbr.else_body); - for (switchbr.cases) |case| { - try dtz.fetchInstsAndResolveConsts(case.body); - } - }, - - .loop => { - const loop = inst.castTag(.loop).?; - try dtz.fetchInstsAndResolveConsts(loop.body); - }, - .call => { - const call = inst.castTag(.call).?; - try dtz.findConst(call.func); - for (call.args) |arg| { - try dtz.findConst(arg); - } - }, - .struct_field_ptr => { - const struct_field_ptr = inst.castTag(.struct_field_ptr).?; - try dtz.findConst(struct_field_ptr.struct_ptr); - }, - - // TODO fill out this debug printing - .assembly, - .constant, - .varptr, - => {}, - } - } - } - - fn dumpBody(dtz: *DumpAir, body: Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void { - for (body.instructions) |inst| { - const my_index = dtz.next_partial_index; - try dtz.partial_inst_table.put(inst, my_index); - dtz.next_partial_index += 1; - - try writer.writeByteNTimes(' ', dtz.indent); - try writer.print("%{d}: {} = {s}(", .{ - my_index, inst.ty, @tagName(inst.tag), - }); - switch (inst.tag) { - .alloc, - .retvoid, - .unreach, - .breakpoint, - .dbg_stmt, - => try writer.writeAll(")\n"), - - .ref, - .ret, - .bitcast, - .not, - .is_non_null, - .is_non_null_ptr, - .is_null, - .is_null_ptr, - .is_err, - .is_err_ptr, - .is_non_err, - .is_non_err_ptr, - .ptrtoint, - .floatcast, - .intcast, - .load, - .optional_payload, - .optional_payload_ptr, - .wrap_optional, - .wrap_errunion_err, - .wrap_errunion_payload, - .unwrap_errunion_err, - .unwrap_errunion_payload, - .unwrap_errunion_payload_ptr, - .unwrap_errunion_err_ptr, - => { - const un_op = inst.cast(Inst.UnOp).?; - const kinky = try dtz.writeInst(writer, un_op.operand); - if (kinky != null) { - try writer.writeAll(") // Instruction does not dominate all uses!\n"); - } else { - try writer.writeAll(")\n"); - } - }, - - .add, - .addwrap, - .sub, - .subwrap, - .mul, - .mulwrap, - .div, - .cmp_lt, - .cmp_lte, - .cmp_eq, - .cmp_gte, - .cmp_gt, - .cmp_neq, - .store, - .bool_and, - .bool_or, - .bit_and, - .bit_or, - .xor, - => { - const bin_op = inst.cast(Inst.BinOp).?; - - const lhs_kinky = try dtz.writeInst(writer, bin_op.lhs); - try writer.writeAll(", "); - const rhs_kinky = try dtz.writeInst(writer, bin_op.rhs); - - if (lhs_kinky != null or rhs_kinky != null) { - try writer.writeAll(") // Instruction does not dominate all uses!"); - if (lhs_kinky) |lhs| { - try writer.print(" %{d}", .{lhs}); - } - if (rhs_kinky) |rhs| { - try writer.print(" %{d}", .{rhs}); - } - try writer.writeAll("\n"); - } else { - try writer.writeAll(")\n"); - } - }, - - .arg => { - const arg = inst.castTag(.arg).?; - try writer.print("{s})\n", .{arg.name}); - }, - - .br => { - const br = inst.castTag(.br).?; - - const lhs_kinky = try dtz.writeInst(writer, &br.block.base); - try writer.writeAll(", "); - const rhs_kinky = try dtz.writeInst(writer, br.operand); - - if (lhs_kinky != null or rhs_kinky != null) { - try writer.writeAll(") // Instruction does not dominate all uses!"); - if (lhs_kinky) |lhs| { - try writer.print(" %{d}", .{lhs}); - } - if (rhs_kinky) |rhs| { - try writer.print(" %{d}", .{rhs}); - } - try writer.writeAll("\n"); - } else { - try writer.writeAll(")\n"); - } - }, - - .br_block_flat => { - const br_block_flat = inst.castTag(.br_block_flat).?; - const block_kinky = try dtz.writeInst(writer, &br_block_flat.block.base); - if (block_kinky != null) { - try writer.writeAll(", { // Instruction does not dominate all uses!\n"); - } else { - try writer.writeAll(", {\n"); - } - - const old_indent = dtz.indent; - dtz.indent += 2; - try dtz.dumpBody(br_block_flat.body, writer); - dtz.indent = old_indent; - - try writer.writeByteNTimes(' ', dtz.indent); - try writer.writeAll("})\n"); - }, - - .br_void => { - const br_void = inst.castTag(.br_void).?; - const kinky = try dtz.writeInst(writer, &br_void.block.base); - if (kinky) |_| { - try writer.writeAll(") // Instruction does not dominate all uses!\n"); - } else { - try writer.writeAll(")\n"); - } - }, - - .block => { - const block = inst.castTag(.block).?; - - try writer.writeAll("{\n"); - - const old_indent = dtz.indent; - dtz.indent += 2; - try dtz.dumpBody(block.body, writer); - dtz.indent = old_indent; - - try writer.writeByteNTimes(' ', dtz.indent); - try writer.writeAll("})\n"); - }, - - .condbr => { - const condbr = inst.castTag(.condbr).?; - - const condition_kinky = try dtz.writeInst(writer, condbr.condition); - if (condition_kinky != null) { - try writer.writeAll(", { // Instruction does not dominate all uses!\n"); - } else { - try writer.writeAll(", {\n"); - } - - const old_indent = dtz.indent; - dtz.indent += 2; - try dtz.dumpBody(condbr.then_body, writer); - - try writer.writeByteNTimes(' ', old_indent); - try writer.writeAll("}, {\n"); - - try dtz.dumpBody(condbr.else_body, writer); - dtz.indent = old_indent; - - try writer.writeByteNTimes(' ', old_indent); - try writer.writeAll("})\n"); - }, - - .switchbr => { - const switchbr = inst.castTag(.switchbr).?; - - const condition_kinky = try dtz.writeInst(writer, switchbr.target); - if (condition_kinky != null) { - try writer.writeAll(", { // Instruction does not dominate all uses!\n"); - } else { - try writer.writeAll(", {\n"); - } - const old_indent = dtz.indent; - - if (switchbr.else_body.instructions.len != 0) { - dtz.indent += 2; - try dtz.dumpBody(switchbr.else_body, writer); - - try writer.writeByteNTimes(' ', old_indent); - try writer.writeAll("}, {\n"); - dtz.indent = old_indent; - } - for (switchbr.cases) |case| { - dtz.indent += 2; - try dtz.dumpBody(case.body, writer); - - try writer.writeByteNTimes(' ', old_indent); - try writer.writeAll("}, {\n"); - dtz.indent = old_indent; - } - - try writer.writeByteNTimes(' ', old_indent); - try writer.writeAll("})\n"); - }, - - .loop => { - const loop = inst.castTag(.loop).?; - - try writer.writeAll("{\n"); - - const old_indent = dtz.indent; - dtz.indent += 2; - try dtz.dumpBody(loop.body, writer); - dtz.indent = old_indent; - - try writer.writeByteNTimes(' ', dtz.indent); - try writer.writeAll("})\n"); - }, - - .call => { - const call = inst.castTag(.call).?; - - const args_kinky = try dtz.allocator.alloc(?usize, call.args.len); - defer dtz.allocator.free(args_kinky); - std.mem.set(?usize, args_kinky, null); - var any_kinky_args = false; - - const func_kinky = try dtz.writeInst(writer, call.func); - - for (call.args) |arg, i| { - try writer.writeAll(", "); - - args_kinky[i] = try dtz.writeInst(writer, arg); - any_kinky_args = any_kinky_args or args_kinky[i] != null; - } - - if (func_kinky != null or any_kinky_args) { - try writer.writeAll(") // Instruction does not dominate all uses!"); - if (func_kinky) |func_index| { - try writer.print(" %{d}", .{func_index}); - } - for (args_kinky) |arg_kinky| { - if (arg_kinky) |arg_index| { - try writer.print(" %{d}", .{arg_index}); - } - } - try writer.writeAll("\n"); - } else { - try writer.writeAll(")\n"); - } - }, - - .struct_field_ptr => { - const struct_field_ptr = inst.castTag(.struct_field_ptr).?; - const kinky = try dtz.writeInst(writer, struct_field_ptr.struct_ptr); - if (kinky != null) { - try writer.print("{d}) // Instruction does not dominate all uses!\n", .{ - struct_field_ptr.field_index, - }); - } else { - try writer.print("{d})\n", .{struct_field_ptr.field_index}); - } - }, - - // TODO fill out this debug printing - .assembly, - .constant, - .varptr, - => { - try writer.writeAll("!TODO!)\n"); - }, - } - } - } - - fn writeInst(dtz: *DumpAir, writer: std.fs.File.Writer, inst: *Inst) !?usize { - if (dtz.partial_inst_table.get(inst)) |operand_index| { - try writer.print("%{d}", .{operand_index}); - return null; - } else if (dtz.const_table.get(inst)) |operand_index| { - try writer.print("@{d}", .{operand_index}); - return null; - } else if (dtz.inst_table.get(inst)) |operand_index| { - try writer.print("%{d}", .{operand_index}); - return operand_index; - } else { - try writer.writeAll("!BADREF!"); - return null; - } - } - - fn findConst(dtz: *DumpAir, operand: *Inst) !void { - if (operand.tag == .constant) { - try dtz.const_table.put(operand, dtz.next_const_index); - dtz.next_const_index += 1; - } - } -}; - -pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void { - const zir_module = scope.namespace(); - const source = zir_module.getSource(mod) catch @panic("dumpInst failed to get source"); - const loc = std.zig.findLineColumn(source, inst.src); - if (inst.tag == .constant) { - std.debug.print("constant ty={} val={} src={s}:{d}:{d}\n", .{ - inst.ty, - inst.castTag(.constant).?.val, - zir_module.subFilePath(), - loc.line + 1, - loc.column + 1, - }); - } else if (inst.deaths == 0) { - std.debug.print("{s} ty={} src={s}:{d}:{d}\n", .{ - @tagName(inst.tag), - inst.ty, - zir_module.subFilePath(), - loc.line + 1, - loc.column + 1, - }); - } else { - std.debug.print("{s} ty={} deaths={b} src={s}:{d}:{d}\n", .{ - @tagName(inst.tag), - inst.ty, - inst.deaths, - zir_module.subFilePath(), - loc.line + 1, - loc.column + 1, - }); - } -} - - /// For debugging purposes. - pub fn dump(func: *Fn, mod: Module) void { - ir.dumpFn(mod, func); - } - diff --git a/src/Air.zig b/src/Air.zig index 60e6e9933d..a8b38b7659 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -374,8 +374,8 @@ pub const Asm = struct { pub fn getMainBody(air: Air) []const Air.Inst.Index { const body_index = air.extra[@enumToInt(ExtraIndex.main_block)]; - const body_len = air.extra[body_index]; - return air.extra[body_index..][0..body_len]; + const extra = air.extraData(Block, body_index); + return air.extra[extra.end..][0..extra.data.body_len]; } pub fn getType(air: Air, inst: Air.Inst.Index) Type { diff --git a/src/Compilation.zig b/src/Compilation.zig index f241ae6b10..50d1f5760e 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1,6 +1,7 @@ const Compilation = @This(); const std = @import("std"); +const builtin = @import("builtin"); const mem = std.mem; const Allocator = std.mem.Allocator; const assert = std.debug.assert; @@ -907,7 +908,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { // comptime conditions ((build_options.have_llvm and comptime std.Target.current.isDarwin()) and // runtime conditions - (use_lld and std.builtin.os.tag == .macos and options.target.isDarwin())); + (use_lld and builtin.os.tag == .macos and options.target.isDarwin())); const sysroot = blk: { if (options.sysroot) |sysroot| { @@ -2026,8 +2027,10 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor var liveness = try Liveness.analyze(gpa, air, decl.namespace.file_scope.zir); defer liveness.deinit(gpa); - if (std.builtin.mode == .Debug and self.verbose_air) { - @panic("TODO implement dumping AIR and liveness"); + if (builtin.mode == .Debug and self.verbose_air) { + std.debug.print("# Begin Function AIR: {s}:\n", .{decl.name}); + @import("print_air.zig").dump(gpa, air, liveness); + std.debug.print("# End Function AIR: {s}:\n", .{decl.name}); } assert(decl.ty.hasCodeGenBits()); diff --git a/src/Module.zig b/src/Module.zig index fb514ccbd2..f452824d33 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -3551,7 +3551,8 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air { try sema.analyzeFnBody(&inner_block, func.zir_body_inst); // Copy the block into place and mark that as the main block. - try sema.air_extra.ensureUnusedCapacity(gpa, inner_block.instructions.items.len + 1); + try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + + inner_block.instructions.items.len); const main_block_index = sema.addExtraAssumeCapacity(Air.Block{ .body_len = @intCast(u32, inner_block.instructions.items.len), }); diff --git a/src/Sema.zig b/src/Sema.zig index ac6755d24e..a144ce1d50 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -2028,6 +2028,7 @@ fn analyzeBlockBody( refToIndex(coerced_operand).?); // Convert the br operand to a block. + const br_operand_ty_ref = try sema.addType(br_operand_ty); try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len + coerce_block.instructions.items.len); try sema.air_instructions.ensureUnusedCapacity(gpa, 2); @@ -2037,7 +2038,7 @@ fn analyzeBlockBody( sema.air_instructions.appendAssumeCapacity(.{ .tag = .block, .data = .{ .ty_pl = .{ - .ty = try sema.addType(br_operand_ty), + .ty = br_operand_ty_ref, .payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = @intCast(u32, coerce_block.instructions.items.len), }), diff --git a/src/print_air.zig b/src/print_air.zig new file mode 100644 index 0000000000..44c170a078 --- /dev/null +++ b/src/print_air.zig @@ -0,0 +1,294 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const fmtIntSizeBin = std.fmt.fmtIntSizeBin; + +const Module = @import("Module.zig"); +const Value = @import("value.zig").Value; +const Air = @import("Air.zig"); +const Liveness = @import("Liveness.zig"); + +pub fn dump(gpa: *Allocator, air: Air, liveness: Liveness) void { + const instruction_bytes = air.instructions.len * + // Here we don't use @sizeOf(Air.Inst.Data) because it would include + // the debug safety tag but we want to measure release size. + (@sizeOf(Air.Inst.Tag) + 8); + const extra_bytes = air.extra.len * @sizeOf(u32); + const values_bytes = air.values.len * @sizeOf(Value); + const variables_bytes = air.variables.len * @sizeOf(*Module.Var); + const tomb_bytes = liveness.tomb_bits.len * @sizeOf(usize); + const liveness_extra_bytes = liveness.extra.len * @sizeOf(u32); + const liveness_special_bytes = liveness.special.count() * 8; + const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes + + values_bytes * variables_bytes + @sizeOf(Liveness) + liveness_extra_bytes + + liveness_special_bytes + tomb_bytes; + + // zig fmt: off + std.debug.print( + \\# Total AIR+Liveness bytes: {} + \\# AIR Instructions: {d} ({}) + \\# AIR Extra Data: {d} ({}) + \\# AIR Values Bytes: {d} ({}) + \\# AIR Variables Bytes: {d} ({}) + \\# Liveness tomb_bits: {} + \\# Liveness Extra Data: {d} ({}) + \\# Liveness special table: {d} ({}) + \\ + , .{ + fmtIntSizeBin(total_bytes), + air.instructions.len, fmtIntSizeBin(instruction_bytes), + air.extra.len, fmtIntSizeBin(extra_bytes), + air.values.len, fmtIntSizeBin(values_bytes), + air.variables.len, fmtIntSizeBin(variables_bytes), + fmtIntSizeBin(tomb_bytes), + liveness.extra.len, fmtIntSizeBin(liveness_extra_bytes), + liveness.special.count(), fmtIntSizeBin(liveness_special_bytes), + }); + // zig fmt: on + var arena = std.heap.ArenaAllocator.init(gpa); + defer arena.deinit(); + + var writer: Writer = .{ + .gpa = gpa, + .arena = &arena.allocator, + .air = air, + .liveness = liveness, + .indent = 0, + }; + const stream = std.io.getStdErr().writer(); + writer.writeAllConstants(stream) catch return; + writer.writeBody(stream, air.getMainBody()) catch return; +} + +const Writer = struct { + gpa: *Allocator, + arena: *Allocator, + air: Air, + liveness: Liveness, + indent: usize, + + fn writeAllConstants(w: *Writer, s: anytype) @TypeOf(s).Error!void { + for (w.air.instructions.items(.tag)) |tag, i| { + const inst = @intCast(u32, i); + switch (tag) { + .constant, .const_ty => { + try s.writeByteNTimes(' ', w.indent); + try s.print("%{d} ", .{inst}); + try w.writeInst(s, inst); + try s.writeAll(")\n"); + }, + else => continue, + } + } + } + + fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void { + for (body) |inst| { + try s.writeByteNTimes(' ', w.indent); + try s.print("%{d} ", .{inst}); + try w.writeInst(s, inst); + if (w.liveness.isUnused(inst)) { + try s.writeAll(") unused\n"); + } else { + try s.writeAll("\n"); + } + } + } + + fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const tags = w.air.instructions.items(.tag); + const tag = tags[inst]; + try s.print("= {s}(", .{@tagName(tags[inst])}); + switch (tag) { + .arg => try w.writeTyStr(s, inst), + + .add, + .addwrap, + .sub, + .subwrap, + .mul, + .mulwrap, + .div, + .bit_and, + .bit_or, + .xor, + .cmp_lt, + .cmp_lte, + .cmp_eq, + .cmp_gte, + .cmp_gt, + .cmp_neq, + .bool_and, + .bool_or, + .store, + => try w.writeBinOp(s, inst), + + .is_null, + .is_non_null, + .is_null_ptr, + .is_non_null_ptr, + .is_err, + .is_non_err, + .is_err_ptr, + .is_non_err_ptr, + .ptrtoint, + .ret, + => try w.writeUnOp(s, inst), + + .breakpoint, + .unreach, + => try w.writeNoOp(s, inst), + + .const_ty, + .alloc, + => try w.writeTy(s, inst), + + .not, + .bitcast, + .load, + .ref, + .floatcast, + .intcast, + .optional_payload, + .optional_payload_ptr, + .wrap_optional, + .unwrap_errunion_payload, + .unwrap_errunion_err, + .unwrap_errunion_payload_ptr, + .unwrap_errunion_err_ptr, + .wrap_errunion_payload, + .wrap_errunion_err, + => try w.writeTyOp(s, inst), + + .block, + .loop, + => try w.writeBlock(s, inst), + + .struct_field_ptr => try w.writeStructFieldPtr(s, inst), + .varptr => try w.writeVarPtr(s, inst), + .constant => try w.writeConstant(s, inst), + .assembly => try w.writeAssembly(s, inst), + .dbg_stmt => try w.writeDbgStmt(s, inst), + .call => try w.writeCall(s, inst), + .br => try w.writeBr(s, inst), + .cond_br => try w.writeCondBr(s, inst), + .switch_br => try w.writeSwitchBr(s, inst), + } + } + + fn writeTyStr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + 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}); + } + + fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeBlock(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeStructFieldPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeVarPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + 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("{}, {}", .{ ty_pl.ty, val }); + } + + fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const dbg_stmt = w.air.instructions.items(.data)[inst].dbg_stmt; + try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 }); + } + + fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + const pl_op = w.air.instructions.items(.data)[inst].pl_op; + const extra = w.air.extraData(Air.Call, pl_op.payload); + const args = w.air.extra[extra.end..][0..extra.data.args_len]; + try w.writeInstRef(s, pl_op.operand); + try s.writeAll(", ["); + for (args) |arg, i| { + if (i != 0) try s.writeAll(", "); + try w.writeInstRef(s, @intToEnum(Air.Inst.Ref, arg)); + } + try s.writeAll("]"); + } + + fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + _ = inst; + try s.writeAll("TODO"); + } + + fn writeInstRef(w: *Writer, s: anytype, inst: Air.Inst.Ref) @TypeOf(s).Error!void { + var i: usize = @enumToInt(inst); + + if (i < Air.Inst.Ref.typed_value_map.len) { + return s.print("@{}", .{inst}); + } + i -= Air.Inst.Ref.typed_value_map.len; + + return w.writeInstIndex(s, @intCast(Air.Inst.Index, i)); + } + + fn writeInstIndex(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { + _ = w; + return s.print("%{d}", .{inst}); + } +}; diff --git a/src/value.zig b/src/value.zig index df3a97b09a..abb2ea7b1e 100644 --- a/src/value.zig +++ b/src/value.zig @@ -573,7 +573,7 @@ pub const Value = extern union { .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream), .int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}), .int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}), - .function => return out_stream.writeAll("(function)"), + .function => return out_stream.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}), .extern_fn => return out_stream.writeAll("(extern function)"), .variable => return out_stream.writeAll("(variable)"), .ref_val => {