From 4ecc5956f62166708f3f47522e326452b0166dda Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Wed, 29 Dec 2021 22:04:03 +0100 Subject: [PATCH] stage2: update PrintMir with latest instructions and Isel changes --- src/arch/x86_64/CodeGen.zig | 6 +- src/arch/x86_64/PrintMir.zig | 379 ++++++++++------------------------- 2 files changed, 113 insertions(+), 272 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index dc14a8293b..a209739904 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -329,7 +329,11 @@ pub fn generate( if (builtin.mode == .Debug and bin_file.options.module.?.comp.verbose_mir) { const w = std.io.getStdErr().writer(); w.print("# Begin Function MIR: {s}:\n", .{module_fn.owner_decl.name}) catch {}; - const print = @import("./PrintMir.zig"){ .mir = mir }; + const PrintMir = @import("PrintMir.zig"); + const print = PrintMir{ + .mir = mir, + .bin_file = bin_file, + }; print.printMir(w, function.mir_to_air_map, air) catch {}; // we don't care if the debug printing fails w.print("# End Function MIR: {s}\n\n", .{module_fn.owner_decl.name}) catch {}; } diff --git a/src/arch/x86_64/PrintMir.zig b/src/arch/x86_64/PrintMir.zig index 91740241d9..d7ebcba34c 100644 --- a/src/arch/x86_64/PrintMir.zig +++ b/src/arch/x86_64/PrintMir.zig @@ -25,6 +25,7 @@ const Type = @import("../../type.zig").Type; const fmtIntSizeBin = std.fmt.fmtIntSizeBin; mir: Mir, +bin_file: *link.File, pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap(Mir.Inst.Index, Air.Inst.Index), air: Air) !void { const instruction_bytes = print.mir.instructions.len * @@ -116,15 +117,15 @@ pub fn printMir(print: *const Print, w: anytype, mir_to_air_map: std.AutoHashMap .jmp => try print.mirJmpCall(.jmp, inst, w), .call => try print.mirJmpCall(.call, inst, w), - // .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w), - // .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w), - // .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w), + .cond_jmp_greater_less => try print.mirCondJmp(.cond_jmp_greater_less, inst, w), + .cond_jmp_above_below => try print.mirCondJmp(.cond_jmp_above_below, inst, w), + .cond_jmp_eq_ne => try print.mirCondJmp(.cond_jmp_eq_ne, inst, w), - // .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w), - // .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w), - // .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w), + .cond_set_byte_greater_less => try print.mirCondSetByte(.cond_set_byte_greater_less, inst, w), + .cond_set_byte_above_below => try print.mirCondSetByte(.cond_set_byte_above_below, inst, w), + .cond_set_byte_eq_ne => try print.mirCondSetByte(.cond_set_byte_eq_ne, inst, w), - // .@"test" => try print.mirTest(inst, w), + .@"test" => try print.mirTest(inst, w), .brk => try w.writeAll("brk\n"), .ret => try w.writeAll("ret\n"), @@ -209,254 +210,24 @@ fn mirJmpCall(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: a try w.print("{s}\n", .{@tagName(ops.reg1)}); } -const CondType = enum { - /// greater than or equal - gte, - - /// greater than - gt, - - /// less than - lt, - - /// less than or equal - lte, - - /// above or equal - ae, - - /// above - a, - - /// below - b, - - /// below or equal - be, - - /// not equal - ne, - - /// equal - eq, - - fn fromTagAndFlags(tag: Mir.Inst.Tag, flags: u2) CondType { - return switch (tag) { - .cond_jmp_greater_less, - .cond_set_byte_greater_less, - => switch (flags) { - 0b00 => CondType.gte, - 0b01 => CondType.gt, - 0b10 => CondType.lt, - 0b11 => CondType.lte, - }, - .cond_jmp_above_below, - .cond_set_byte_above_below, - => switch (flags) { - 0b00 => CondType.ae, - 0b01 => CondType.a, - 0b10 => CondType.b, - 0b11 => CondType.be, - }, - .cond_jmp_eq_ne, - .cond_set_byte_eq_ne, - => switch (@truncate(u1, flags)) { - 0b0 => CondType.ne, - 0b1 => CondType.eq, - }, - else => unreachable, - }; - } -}; - -inline fn getCondOpCode(tag: Mir.Inst.Tag, cond: CondType) u8 { - switch (cond) { - .gte => return switch (tag) { - .cond_jmp_greater_less => 0x8d, - .cond_set_byte_greater_less => 0x9d, - else => unreachable, - }, - .gt => return switch (tag) { - .cond_jmp_greater_less => 0x8f, - .cond_set_byte_greater_less => 0x9f, - else => unreachable, - }, - .lt => return switch (tag) { - .cond_jmp_greater_less => 0x8c, - .cond_set_byte_greater_less => 0x9c, - else => unreachable, - }, - .lte => return switch (tag) { - .cond_jmp_greater_less => 0x8e, - .cond_set_byte_greater_less => 0x9e, - else => unreachable, - }, - .ae => return switch (tag) { - .cond_jmp_above_below => 0x83, - .cond_set_byte_above_below => 0x93, - else => unreachable, - }, - .a => return switch (tag) { - .cond_jmp_above_below => 0x87, - .cond_set_byte_greater_less => 0x97, - else => unreachable, - }, - .b => return switch (tag) { - .cond_jmp_above_below => 0x82, - .cond_set_byte_greater_less => 0x92, - else => unreachable, - }, - .be => return switch (tag) { - .cond_jmp_above_below => 0x86, - .cond_set_byte_greater_less => 0x96, - else => unreachable, - }, - .eq => return switch (tag) { - .cond_jmp_eq_ne => 0x84, - .cond_set_byte_eq_ne => 0x94, - else => unreachable, - }, - .ne => return switch (tag) { - .cond_jmp_eq_ne => 0x85, - .cond_set_byte_eq_ne => 0x95, - else => unreachable, - }, - } -} - fn mirCondJmp(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { - _ = w; // TODO - const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); - const target = print.mir.instructions.items(.data)[inst].inst; - const cond = CondType.fromTagAndFlags(tag, ops.flags); - const opc = getCondOpCode(tag, cond); - const source = print.code.items.len; - const encoder = try Encoder.init(print.code, 6); - encoder.opcode_2byte(0x0f, opc); - try print.relocs.append(print.bin_file.allocator, .{ - .source = source, - .target = target, - .offset = print.code.items.len, - .length = 6, - }); - encoder.imm32(0); + _ = print; + _ = tag; + _ = inst; + try w.writeAll("TODO print mirCondJmp\n"); } fn mirCondSetByte(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { - _ = w; // TODO - const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); - const cond = CondType.fromTagAndFlags(tag, ops.flags); - const opc = getCondOpCode(tag, cond); - const encoder = try Encoder.init(print.code, 4); - encoder.rex(.{ - .w = true, - .b = ops.reg1.isExtended(), - }); - encoder.opcode_2byte(0x0f, opc); - encoder.modRm_direct(0x0, ops.reg1.lowId()); + _ = tag; + _ = inst; + _ = print; + try w.writeAll("TODO print mirCondSetByte\n"); } fn mirTest(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { - _ = w; // TODO - const tag = print.mir.instructions.items(.tag)[inst]; - assert(tag == .@"test"); - const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); - switch (ops.flags) { - 0b00 => blk: { - if (ops.reg2 == .none) { - // TEST r/m64, imm32 - const imm = print.mir.instructions.items(.data)[inst].imm; - if (ops.reg1.to64() == .rax) { - // TODO reduce the size of the instruction if the immediate - // is smaller than 32 bits - const encoder = try Encoder.init(print.code, 6); - encoder.rex(.{ - .w = true, - }); - encoder.opcode_1byte(0xa9); - encoder.imm32(imm); - break :blk; - } - const opc: u8 = if (ops.reg1.size() == 8) 0xf6 else 0xf7; - const encoder = try Encoder.init(print.code, 7); - encoder.rex(.{ - .w = true, - .b = ops.reg1.isExtended(), - }); - encoder.opcode_1byte(opc); - encoder.modRm_direct(0, ops.reg1.lowId()); - encoder.imm8(@intCast(i8, imm)); - break :blk; - } - // TEST r/m64, r64 - return print.fail("TODO TEST r/m64, r64", .{}); - }, - else => return print.fail("TODO more TEST alternatives", .{}), - } -} - -const EncType = enum { - /// OP r/m64, imm32 - mi, - - /// OP r/m64, r64 - mr, - - /// OP r64, r/m64 - rm, -}; - -const OpCode = struct { - opc: u8, - /// Only used if `EncType == .mi`. - modrm_ext: u3, -}; - -inline fn getArithOpCode(tag: Mir.Inst.Tag, enc: EncType) OpCode { - switch (enc) { - .mi => return switch (tag) { - .adc => .{ .opc = 0x81, .modrm_ext = 0x2 }, - .add => .{ .opc = 0x81, .modrm_ext = 0x0 }, - .sub => .{ .opc = 0x81, .modrm_ext = 0x5 }, - .xor => .{ .opc = 0x81, .modrm_ext = 0x6 }, - .@"and" => .{ .opc = 0x81, .modrm_ext = 0x4 }, - .@"or" => .{ .opc = 0x81, .modrm_ext = 0x1 }, - .sbb => .{ .opc = 0x81, .modrm_ext = 0x3 }, - .cmp => .{ .opc = 0x81, .modrm_ext = 0x7 }, - .mov => .{ .opc = 0xc7, .modrm_ext = 0x0 }, - else => unreachable, - }, - .mr => { - const opc: u8 = switch (tag) { - .adc => 0x11, - .add => 0x01, - .sub => 0x29, - .xor => 0x31, - .@"and" => 0x21, - .@"or" => 0x09, - .sbb => 0x19, - .cmp => 0x39, - .mov => 0x89, - else => unreachable, - }; - return .{ .opc = opc, .modrm_ext = undefined }; - }, - .rm => { - const opc: u8 = switch (tag) { - .adc => 0x13, - .add => 0x03, - .sub => 0x2b, - .xor => 0x33, - .@"and" => 0x23, - .@"or" => 0x0b, - .sbb => 0x1b, - .cmp => 0x3b, - .mov => 0x8b, - else => unreachable, - }; - return .{ .opc = opc, .modrm_ext = undefined }; - }, - } + _ = print; + _ = inst; + try w.writeAll("TODO print mirTest\n"); } fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { @@ -473,36 +244,61 @@ fn mirArith(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: any 0b01 => { const imm = print.mir.instructions.items(.data)[inst].imm; if (ops.reg2 == .none) { - try w.print("{s}, [ds:{d}]", .{ @tagName(ops.reg1), imm }); + try w.print("{s}, ", .{@tagName(ops.reg1)}); + switch (ops.reg1.size()) { + 8 => try w.print("byte ptr ", .{}), + 16 => try w.print("word ptr ", .{}), + 32 => try w.print("dword ptr ", .{}), + 64 => try w.print("qword ptr ", .{}), + else => unreachable, + } + try w.print("[ds:{d}]", .{imm}); } else { - try w.print("{s}, [{s} + {d}]", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm }); + try w.print("{s}, ", .{@tagName(ops.reg1)}); + switch (ops.reg1.size()) { + 8 => try w.print("byte ptr ", .{}), + 16 => try w.print("word ptr ", .{}), + 32 => try w.print("dword ptr ", .{}), + 64 => try w.print("qword ptr ", .{}), + else => unreachable, + } + try w.print("[{s} + {d}]", .{ @tagName(ops.reg2), imm }); } }, 0b10 => { const imm = print.mir.instructions.items(.data)[inst].imm; if (ops.reg2 == .none) { - try w.print("[{s} + 0], {d}", .{ @tagName(ops.reg1), imm }); + try w.writeAll("unused variant"); } else { + switch (ops.reg2.size()) { + 8 => try w.print("byte ptr ", .{}), + 16 => try w.print("word ptr ", .{}), + 32 => try w.print("dword ptr ", .{}), + 64 => try w.print("qword ptr ", .{}), + else => unreachable, + } try w.print("[{s} + {d}], {s}", .{ @tagName(ops.reg1), imm, @tagName(ops.reg2) }); } }, 0b11 => { - if (ops.reg2 == .none) { - const payload = print.mir.instructions.items(.data)[inst].payload; - const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data; - try w.print("[{s} + {d}], {d}", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand }); - } - try w.writeAll("TODO"); + try w.writeAll("unused variant"); }, } try w.writeByte('\n'); } fn mirArithMemImm(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { - _ = print; - _ = tag; - _ = inst; - return w.writeAll("TODO mirArithMemImm\n"); + const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); + const payload = print.mir.instructions.items(.data)[inst].payload; + const imm_pair = print.mir.extraData(Mir.ImmPair, payload).data; + try w.print("{s} ", .{@tagName(tag)}); + switch (ops.flags) { + 0b00 => try w.print("byte ptr ", .{}), + 0b01 => try w.print("word ptr ", .{}), + 0b10 => try w.print("dword ptr ", .{}), + 0b11 => try w.print("qword ptr ", .{}), + } + try w.print("[{s} + {d}], {d}\n", .{ @tagName(ops.reg1), imm_pair.dest_off, imm_pair.operand }); } fn mirArithScaleSrc(print: *const Print, tag: Mir.Inst.Tag, inst: Mir.Inst.Index, w: anytype) !void { @@ -575,16 +371,57 @@ fn mirIMulComplex(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { } fn mirLea(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void { - _ = print; - _ = inst; - return w.writeAll("TODO lea\n"); - // const tag = print.mir.instructions.items(.tag)[inst]; - // assert(tag == .lea); - // const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); - // assert(ops.flags == 0b01); - // const imm = print.mir.instructions.items(.data)[inst].imm; - - // try w.print("lea {s} [{s} + {d}]\n", .{ @tagName(ops.reg1), @tagName(ops.reg2), imm }); + const ops = Mir.Ops.decode(print.mir.instructions.items(.ops)[inst]); + try w.writeAll("lea "); + switch (ops.flags) { + 0b00 => { + const imm = print.mir.instructions.items(.data)[inst].imm; + try w.print("{s} [", .{@tagName(ops.reg1)}); + if (ops.reg2 != .none) { + try w.print("{s} + ", .{@tagName(ops.reg2)}); + } else { + try w.print("ds:", .{}); + } + try w.print("{d}]\n", .{imm}); + }, + 0b01 => { + try w.print("{s}, ", .{@tagName(ops.reg1)}); + switch (ops.reg1.size()) { + 8 => try w.print("byte ptr ", .{}), + 16 => try w.print("word ptr ", .{}), + 32 => try w.print("dword ptr ", .{}), + 64 => try w.print("qword ptr ", .{}), + else => unreachable, + } + try w.print("[rip + 0x0] ", .{}); + const payload = print.mir.instructions.items(.data)[inst].payload; + const imm = print.mir.extraData(Mir.Imm64, payload).data.decode(); + try w.print("target@{x}", .{imm}); + }, + 0b10 => { + try w.print("{s}, ", .{@tagName(ops.reg1)}); + switch (ops.reg1.size()) { + 8 => try w.print("byte ptr ", .{}), + 16 => try w.print("word ptr ", .{}), + 32 => try w.print("dword ptr ", .{}), + 64 => try w.print("qword ptr ", .{}), + else => unreachable, + } + try w.print("[rip + 0x0] ", .{}); + const got_entry = print.mir.instructions.items(.data)[inst].got_entry; + if (print.bin_file.cast(link.File.MachO)) |macho_file| { + const target = macho_file.locals.items[got_entry]; + const target_name = macho_file.getString(target.n_strx); + try w.print("target@{s}", .{target_name}); + } else { + try w.writeAll("TODO lea reg, [rip + reloc] for linking backends different than MachO"); + } + }, + 0b11 => { + try w.writeAll("unused variant\n"); + }, + } + try w.writeAll("\n"); } fn mirCallExtern(print: *const Print, inst: Mir.Inst.Index, w: anytype) !void {