Commit 4ecc5956f6

Jakub Konka <kubkon@jakubkonka.com>
2021-12-29 22:04:03
stage2: update PrintMir with latest instructions and Isel changes
1 parent b7e2235
Changed files (2)
src
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 {};
     }
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 {