| ... | @@ -581,6 +581,7 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 { | ... | @@ -581,6 +581,7 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 { |
| 581 | .sbb => 0x1b, | 581 | .sbb => 0x1b, |
| 582 | .cmp => 0x3b, | 582 | .cmp => 0x3b, |
| 583 | .mov => 0x8b, | 583 | .mov => 0x8b, |
| | 584 | .lea => 0x8d, |
| 584 | else => unreachable, | 585 | else => unreachable, |
| 585 | }, | 586 | }, |
| 586 | .oi => return switch (tag) { | 587 | .oi => return switch (tag) { |
| ... | @@ -621,6 +622,7 @@ const ScaleIndexBase = struct { | ... | @@ -621,6 +622,7 @@ const ScaleIndexBase = struct { |
| 621 | | 622 | |
| 622 | const Memory = struct { | 623 | const Memory = struct { |
| 623 | reg: ?Register, | 624 | reg: ?Register, |
| | 625 | rip: bool = false, |
| 624 | disp: i32, | 626 | disp: i32, |
| 625 | sib: ?ScaleIndexBase = null, | 627 | sib: ?ScaleIndexBase = null, |
| 626 | }; | 628 | }; |
| ... | @@ -641,6 +643,16 @@ const RegisterOrMemory = union(enum) { | ... | @@ -641,6 +643,16 @@ const RegisterOrMemory = union(enum) { |
| 641 | }, | 643 | }, |
| 642 | }; | 644 | }; |
| 643 | } | 645 | } |
| | 646 | |
| | 647 | fn rip(disp: i32) RegisterOrMemory { |
| | 648 | return .{ |
| | 649 | .memory = .{ |
| | 650 | .reg = null, |
| | 651 | .rip = true, |
| | 652 | .disp = disp, |
| | 653 | }, |
| | 654 | }; |
| | 655 | } |
| 644 | }; | 656 | }; |
| 645 | | 657 | |
| 646 | fn lowerToTdEnc( | 658 | fn lowerToTdEnc( |
| ... | @@ -813,8 +825,12 @@ fn lowerToMiEnc( | ... | @@ -813,8 +825,12 @@ fn lowerToMiEnc( |
| 813 | } | 825 | } |
| 814 | } else { | 826 | } else { |
| 815 | encoder.opcode_1byte(opc); | 827 | encoder.opcode_1byte(opc); |
| 816 | encoder.modRm_SIBDisp0(modrm_ext); | 828 | if (dst_mem.rip) { |
| 817 | encoder.sib_disp32(); | 829 | encoder.modRm_RIPDisp32(modrm_ext); |
| | 830 | } else { |
| | 831 | encoder.modRm_SIBDisp0(modrm_ext); |
| | 832 | encoder.sib_disp32(); |
| | 833 | } |
| 818 | encoder.disp32(dst_mem.disp); | 834 | encoder.disp32(dst_mem.disp); |
| 819 | } | 835 | } |
| 820 | encoder.imm32(imm); | 836 | encoder.imm32(imm); |
| ... | @@ -880,8 +896,12 @@ fn lowerToRmEnc( | ... | @@ -880,8 +896,12 @@ fn lowerToRmEnc( |
| 880 | .r = reg.isExtended(), | 896 | .r = reg.isExtended(), |
| 881 | }); | 897 | }); |
| 882 | encoder.opcode_1byte(opc); | 898 | encoder.opcode_1byte(opc); |
| 883 | encoder.modRm_SIBDisp0(reg.lowId()); | 899 | if (src_mem.rip) { |
| 884 | encoder.sib_disp32(); | 900 | encoder.modRm_RIPDisp32(reg.lowId()); |
| | 901 | } else { |
| | 902 | encoder.modRm_SIBDisp0(reg.lowId()); |
| | 903 | encoder.sib_disp32(); |
| | 904 | } |
| 885 | encoder.disp32(src_mem.disp); | 905 | encoder.disp32(src_mem.disp); |
| 886 | } | 906 | } |
| 887 | }, | 907 | }, |
| ... | @@ -950,8 +970,12 @@ fn lowerToMrEnc( | ... | @@ -950,8 +970,12 @@ fn lowerToMrEnc( |
| 950 | .r = reg.isExtended(), | 970 | .r = reg.isExtended(), |
| 951 | }); | 971 | }); |
| 952 | encoder.opcode_1byte(opc); | 972 | encoder.opcode_1byte(opc); |
| 953 | encoder.modRm_SIBDisp0(reg.lowId()); | 973 | if (dst_mem.rip) { |
| 954 | encoder.sib_disp32(); | 974 | encoder.modRm_RIPDisp32(reg.lowId()); |
| | 975 | } else { |
| | 976 | encoder.modRm_SIBDisp0(reg.lowId()); |
| | 977 | encoder.sib_disp32(); |
| | 978 | } |
| 955 | encoder.disp32(dst_mem.disp); | 979 | encoder.disp32(dst_mem.disp); |
| 956 | } | 980 | } |
| 957 | }, | 981 | }, |
| ... | @@ -1206,37 +1230,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -1206,37 +1230,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 1206 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1230 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1207 | assert(ops.flags == 0b01); | 1231 | assert(ops.flags == 0b01); |
| 1208 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 1232 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 1209 | | 1233 | return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(ops.reg2, imm), emit.code); |
| 1210 | if (imm == 0) { | | |
| 1211 | const encoder = try Encoder.init(emit.code, 3); | | |
| 1212 | encoder.rex(.{ | | |
| 1213 | .w = ops.reg1.size() == 64, | | |
| 1214 | .r = ops.reg1.isExtended(), | | |
| 1215 | .b = ops.reg2.isExtended(), | | |
| 1216 | }); | | |
| 1217 | encoder.opcode_1byte(0x8d); | | |
| 1218 | encoder.modRm_indirectDisp0(ops.reg1.lowId(), ops.reg2.lowId()); | | |
| 1219 | } else if (imm <= math.maxInt(i8)) { | | |
| 1220 | const encoder = try Encoder.init(emit.code, 4); | | |
| 1221 | encoder.rex(.{ | | |
| 1222 | .w = ops.reg1.size() == 64, | | |
| 1223 | .r = ops.reg1.isExtended(), | | |
| 1224 | .b = ops.reg2.isExtended(), | | |
| 1225 | }); | | |
| 1226 | encoder.opcode_1byte(0x8d); | | |
| 1227 | encoder.modRm_indirectDisp8(ops.reg1.lowId(), ops.reg2.lowId()); | | |
| 1228 | encoder.disp8(@intCast(i8, imm)); | | |
| 1229 | } else { | | |
| 1230 | const encoder = try Encoder.init(emit.code, 7); | | |
| 1231 | encoder.rex(.{ | | |
| 1232 | .w = ops.reg1.size() == 64, | | |
| 1233 | .r = ops.reg1.isExtended(), | | |
| 1234 | .b = ops.reg2.isExtended(), | | |
| 1235 | }); | | |
| 1236 | encoder.opcode_1byte(0x8d); | | |
| 1237 | encoder.modRm_indirectDisp32(ops.reg1.lowId(), ops.reg2.lowId()); | | |
| 1238 | encoder.disp32(imm); | | |
| 1239 | } | | |
| 1240 | } | 1234 | } |
| 1241 | | 1235 | |
| 1242 | fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | 1236 | fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| ... | @@ -1244,26 +1238,22 @@ fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -1244,26 +1238,22 @@ fn mirLeaRip(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 1244 | assert(tag == .lea_rip); | 1238 | assert(tag == .lea_rip); |
| 1245 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1239 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1246 | const start_offset = emit.code.items.len; | 1240 | const start_offset = emit.code.items.len; |
| 1247 | const encoder = try Encoder.init(emit.code, 7); | 1241 | try lowerToRmEnc(.lea, ops.reg1, RegisterOrMemory.rip(0), emit.code); |
| 1248 | encoder.rex(.{ | | |
| 1249 | .w = ops.reg1.size() == 64, | | |
| 1250 | .r = ops.reg1.isExtended(), | | |
| 1251 | }); | | |
| 1252 | encoder.opcode_1byte(0x8d); | | |
| 1253 | encoder.modRm_RIPDisp32(ops.reg1.lowId()); | | |
| 1254 | const end_offset = emit.code.items.len; | 1242 | const end_offset = emit.code.items.len; |
| 1255 | if (@truncate(u1, ops.flags) == 0b0) { | 1243 | if (@truncate(u1, ops.flags) == 0b0) { |
| | 1244 | // Backpatch the displacement |
| | 1245 | // TODO figure out if this can be simplified |
| 1256 | const payload = emit.mir.instructions.items(.data)[inst].payload; | 1246 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 1257 | const imm = emit.mir.extraData(Mir.Imm64, payload).data.decode(); | 1247 | const imm = emit.mir.extraData(Mir.Imm64, payload).data.decode(); |
| 1258 | encoder.disp32(@intCast(i32, @intCast(i64, imm) - @intCast(i64, end_offset - start_offset + 4))); | 1248 | const disp = @intCast(i32, @intCast(i64, imm) - @intCast(i64, end_offset - start_offset)); |
| | 1249 | mem.writeIntLittle(i32, emit.code.items[end_offset - 4 ..][0..4], disp); |
| 1259 | } else { | 1250 | } else { |
| 1260 | const got_entry = emit.mir.instructions.items(.data)[inst].got_entry; | 1251 | const got_entry = emit.mir.instructions.items(.data)[inst].got_entry; |
| 1261 | encoder.disp32(0); | | |
| 1262 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { | 1252 | if (emit.bin_file.cast(link.File.MachO)) |macho_file| { |
| 1263 | // TODO I think the reloc might be in the wrong place. | 1253 | // TODO I think the reloc might be in the wrong place. |
| 1264 | const decl = macho_file.active_decl.?; | 1254 | const decl = macho_file.active_decl.?; |
| 1265 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ | 1255 | try decl.link.macho.relocs.append(emit.bin_file.allocator, .{ |
| 1266 | .offset = @intCast(u32, end_offset), | 1256 | .offset = @intCast(u32, end_offset - 4), |
| 1267 | .target = .{ .local = got_entry }, | 1257 | .target = .{ .local = got_entry }, |
| 1268 | .addend = 0, | 1258 | .addend = 0, |
| 1269 | .subtractor = null, | 1259 | .subtractor = null, |
| ... | @@ -1530,6 +1520,12 @@ test "lower MI encoding" { | ... | @@ -1530,6 +1520,12 @@ test "lower MI encoding" { |
| 1530 | code.emitted(), | 1520 | code.emitted(), |
| 1531 | "and dword ptr [r12 + 0x10000000], 0x10", | 1521 | "and dword ptr [r12 + 0x10000000], 0x10", |
| 1532 | ); | 1522 | ); |
| | 1523 | try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10), 0x10, code.buffer()); |
| | 1524 | try expectEqualHexStrings( |
| | 1525 | "\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00", |
| | 1526 | code.emitted(), |
| | 1527 | "mov [rip + 0x10], 0x10", |
| | 1528 | ); |
| 1533 | } | 1529 | } |
| 1534 | | 1530 | |
| 1535 | test "lower RM encoding" { | 1531 | test "lower RM encoding" { |
| ... | @@ -1565,6 +1561,8 @@ test "lower RM encoding" { | ... | @@ -1565,6 +1561,8 @@ test "lower RM encoding" { |
| 1565 | ); | 1561 | ); |
| 1566 | try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4), code.buffer()); | 1562 | try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4), code.buffer()); |
| 1567 | try expectEqualHexStrings("\x48\x8B\x45\xFC", code.emitted(), "mov rax, qword ptr [rbp - 4]"); | 1563 | try expectEqualHexStrings("\x48\x8B\x45\xFC", code.emitted(), "mov rax, qword ptr [rbp - 4]"); |
| | 1564 | try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(0x10), code.buffer()); |
| | 1565 | try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", code.emitted(), "lea rax, [rip + 0x10]"); |
| 1568 | } | 1566 | } |
| 1569 | | 1567 | |
| 1570 | test "lower MR encoding" { | 1568 | test "lower MR encoding" { |
| ... | @@ -1592,6 +1590,8 @@ test "lower MR encoding" { | ... | @@ -1592,6 +1590,8 @@ test "lower MR encoding" { |
| 1592 | code.emitted(), | 1590 | code.emitted(), |
| 1593 | "sub qword ptr [r11 + 0x10000000], r12", | 1591 | "sub qword ptr [r11 + 0x10000000], r12", |
| 1594 | ); | 1592 | ); |
| | 1593 | try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10), .r12, code.buffer()); |
| | 1594 | try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", code.emitted(), "mov qword ptr [rip + 0x10], r12"); |
| 1595 | } | 1595 | } |
| 1596 | | 1596 | |
| 1597 | test "lower OI encoding" { | 1597 | test "lower OI encoding" { |