aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2021-12-29 22:04:03 +0100
committerJakub Konka <kubkon@jakubkonka.com>2021-12-29 22:06:38 +0100
commit4ecc5956f62166708f3f47522e326452b0166dda (patch)
tree908340c747ac198e9c9530fb66774b5dd8d77f38 /src
parentb7e223597395358dc63cf88c92ace5eaa455cf89 (diff)
downloadzig-4ecc5956f62166708f3f47522e326452b0166dda.tar.gz
zig-4ecc5956f62166708f3f47522e326452b0166dda.zip
stage2: update PrintMir with latest instructions and Isel changes
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig6
-rw-r--r--src/arch/x86_64/PrintMir.zig379
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 {