authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-03 00:11:46+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-04 01:21:23+01:00
log3f7b09bd35fe99025700659be0a4441e4cc6968e
treea9a4a819ce6b54aa9de283384b60f6dc65688c44
parentf37598c779b921d5fc4f97cdcfab523e3fb5fc69

stage2: re-implement arithmetic ops with SIB


1 files changed, 189 insertions(+), 141 deletions(-)

src/arch/x86_64/Isel.zig+189-141
...@@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -227,8 +227,10 @@ fn mirPushPop(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
227 16 => .word_ptr,227 16 => .word_ptr,
228 else => .qword_ptr,228 else => .qword_ptr,
229 };229 };
230 return lowerToMEnc(tag, RegisterOrMemory.mem(ops.reg1, imm, ptr_size), isel.code) catch |err|230 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
231 isel.failWithLoweringError(err);231 .disp = imm,
232 .base = ops.reg1,
233 }), isel.code) catch |err| isel.failWithLoweringError(err);
232 },234 },
233 0b10 => {235 0b10 => {
234 // PUSH imm32236 // PUSH imm32
...@@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -284,7 +286,7 @@ fn mirJmpCall(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
284 16 => .word_ptr,286 16 => .word_ptr,
285 else => .qword_ptr,287 else => .qword_ptr,
286 };288 };
287 return lowerToMEnc(tag, RegisterOrMemory.mem(null, imm, ptr_size), isel.code) catch |err|289 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), isel.code) catch |err|
288 isel.failWithLoweringError(err);290 isel.failWithLoweringError(err);
289 }291 }
290 // JMP/CALL reg292 // JMP/CALL reg
...@@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -422,12 +424,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
422 // RM424 // RM
423 const imm = isel.mir.instructions.items(.data)[inst].imm;425 const imm = isel.mir.instructions.items(.data)[inst].imm;
424 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;426 const src_reg: ?Register = if (ops.reg2 == .none) null else ops.reg2;
425 return lowerToRmEnc(427 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
426 tag,428 .disp = imm,
427 ops.reg1,429 .base = src_reg,
428 RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())),430 }), isel.code) catch |err| isel.failWithLoweringError(err);
429 isel.code,
430 ) catch |err| isel.failWithLoweringError(err);
431 },431 },
432 0b10 => {432 0b10 => {
433 if (ops.reg2 == .none) {433 if (ops.reg2 == .none) {
...@@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -436,12 +436,10 @@ fn mirArith(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
436 // mov [reg1 + imm32], reg2436 // mov [reg1 + imm32], reg2
437 // MR437 // MR
438 const imm = isel.mir.instructions.items(.data)[inst].imm;438 const imm = isel.mir.instructions.items(.data)[inst].imm;
439 return lowerToMrEnc(439 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
440 tag,440 .disp = imm,
441 RegisterOrMemory.mem(ops.reg1, imm, Memory.PtrSize.fromBits(ops.reg2.size())),441 .base = ops.reg1,
442 ops.reg2,442 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
443 isel.code,
444 ) catch |err| isel.failWithLoweringError(err);
445 },443 },
446 0b11 => {444 0b11 => {
447 return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});445 return isel.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
...@@ -460,12 +458,10 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -460,12 +458,10 @@ fn mirArithMemImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
460 0b10 => .dword_ptr,458 0b10 => .dword_ptr,
461 0b11 => .qword_ptr,459 0b11 => .qword_ptr,
462 };460 };
463 return lowerToMiEnc(461 return lowerToMiEnc(tag, RegisterOrMemory.mem(ptr_size, .{
464 tag,462 .disp = imm_pair.dest_off,
465 RegisterOrMemory.mem(ops.reg1, imm_pair.dest_off, ptr_size),463 .base = ops.reg1,
466 imm_pair.operand,464 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
467 isel.code,
468 ) catch |err| isel.failWithLoweringError(err);
469}465}
470466
471inline fn setRexWRegister(reg: Register) bool {467inline fn setRexWRegister(reg: Register) bool {
...@@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 {...@@ -492,103 +488,61 @@ inline fn immOpSize(imm: i64) u8 {
492 return 64;488 return 64;
493}489}
494490
495// TODO
496fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {491fn mirArithScaleSrc(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
497 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);492 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
498 const scale = ops.flags;493 const scale = ops.flags;
499 // OP reg1, [reg2 + scale*rcx + imm32]
500 const opc = getOpCode(tag, .rm, ops.reg1.size() == 8).?;
501 const imm = isel.mir.instructions.items(.data)[inst].imm;494 const imm = isel.mir.instructions.items(.data)[inst].imm;
502 const encoder = try Encoder.init(isel.code, 8);495 // OP reg1, [reg2 + scale*rcx + imm32]
503 encoder.rex(.{496 return lowerToRmEnc(tag, ops.reg1, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
504 .w = ops.reg1.size() == 64,497 .disp = imm,
505 .r = ops.reg1.isExtended(),498 .base = ops.reg2,
506 .b = ops.reg2.isExtended(),499 .scale_index = .{
507 });500 .scale = scale,
508 opc.encode(encoder);501 .index = .rcx,
509 if (imm <= math.maxInt(i8)) {502 },
510 encoder.modRm_SIBDisp8(ops.reg1.lowId());503 }), isel.code) catch |err| isel.failWithLoweringError(err);
511 encoder.sib_scaleIndexBaseDisp8(scale, Register.rcx.lowId(), ops.reg2.lowId());
512 encoder.disp8(@intCast(i8, imm));
513 } else {
514 encoder.modRm_SIBDisp32(ops.reg1.lowId());
515 encoder.sib_scaleIndexBaseDisp32(scale, Register.rcx.lowId(), ops.reg2.lowId());
516 encoder.disp32(imm);
517 }
518}504}
519505
520// TODO
521fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {506fn mirArithScaleDst(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
522 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);507 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
523 const scale = ops.flags;508 const scale = ops.flags;
524 const imm = isel.mir.instructions.items(.data)[inst].imm;509 const imm = isel.mir.instructions.items(.data)[inst].imm;
525
526 if (ops.reg2 == .none) {510 if (ops.reg2 == .none) {
527 // OP [reg1 + scale*rax + 0], imm32511 // OP qword ptr [reg1 + scale*rax + 0], imm32
528 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;512 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
529 const modrm_ext = getModRmExt(tag).?;513 .disp = 0,
530 const encoder = try Encoder.init(isel.code, 8);514 .base = ops.reg1,
531 encoder.rex(.{515 .scale_index = .{
532 .w = ops.reg1.size() == 64,516 .scale = scale,
533 .b = ops.reg1.isExtended(),517 .index = .rax,
534 });518 },
535 opc.encode(encoder);519 }), imm, isel.code) catch |err| isel.failWithLoweringError(err);
536 encoder.modRm_SIBDisp0(modrm_ext);
537 encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId());
538 if (imm <= math.maxInt(i8)) {
539 encoder.imm8(@intCast(i8, imm));
540 } else if (imm <= math.maxInt(i16)) {
541 encoder.imm16(@intCast(i16, imm));
542 } else {
543 encoder.imm32(imm);
544 }
545 return;
546 }520 }
547
548 // OP [reg1 + scale*rax + imm32], reg2521 // OP [reg1 + scale*rax + imm32], reg2
549 const opc = getOpCode(tag, .mr, ops.reg1.size() == 8).?;522 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
550 const encoder = try Encoder.init(isel.code, 8);523 .disp = imm,
551 encoder.rex(.{524 .base = ops.reg1,
552 .w = ops.reg1.size() == 64,525 .scale_index = .{
553 .r = ops.reg2.isExtended(),526 .scale = scale,
554 .b = ops.reg1.isExtended(),527 .index = .rax,
555 });528 },
556 opc.encode(encoder);529 }), ops.reg2, isel.code) catch |err| isel.failWithLoweringError(err);
557 if (imm <= math.maxInt(i8)) {
558 encoder.modRm_SIBDisp8(ops.reg2.lowId());
559 encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId());
560 encoder.disp8(@intCast(i8, imm));
561 } else {
562 encoder.modRm_SIBDisp32(ops.reg2.lowId());
563 encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId());
564 encoder.disp32(imm);
565 }
566}530}
567531
568// TODO
569fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {532fn mirArithScaleImm(isel: *Isel, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
570 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);533 const ops = Mir.Ops.decode(isel.mir.instructions.items(.ops)[inst]);
571 const scale = ops.flags;534 const scale = ops.flags;
572 const payload = isel.mir.instructions.items(.data)[inst].payload;535 const payload = isel.mir.instructions.items(.data)[inst].payload;
573 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;536 const imm_pair = isel.mir.extraData(Mir.ImmPair, payload).data;
574 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;537 // OP qword ptr [reg1 + scale*rax + imm32], imm32
575 const modrm_ext = getModRmExt(tag).?;538 return lowerToMiEnc(tag, RegisterOrMemory.mem(.qword_ptr, .{
576 const encoder = try Encoder.init(isel.code, 2);539 .disp = imm_pair.dest_off,
577 encoder.rex(.{540 .base = ops.reg1,
578 .w = ops.reg1.size() == 64,541 .scale_index = .{
579 .b = ops.reg1.isExtended(),542 .scale = scale,
580 });543 .index = .rax,
581 opc.encode(encoder);544 },
582 if (imm_pair.dest_off <= math.maxInt(i8)) {545 }), imm_pair.operand, isel.code) catch |err| isel.failWithLoweringError(err);
583 encoder.modRm_SIBDisp8(modrm_ext);
584 encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId());
585 encoder.disp8(@intCast(i8, imm_pair.dest_off));
586 } else {
587 encoder.modRm_SIBDisp32(modrm_ext);
588 encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId());
589 encoder.disp32(imm_pair.dest_off);
590 }
591 encoder.imm32(imm_pair.operand);
592}546}
593547
594fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {548fn mirMovabs(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
...@@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -646,7 +600,10 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
646 return lowerToRmEnc(600 return lowerToRmEnc(
647 .lea,601 .lea,
648 ops.reg1,602 ops.reg1,
649 RegisterOrMemory.mem(src_reg, imm, Memory.PtrSize.fromBits(ops.reg1.size())),603 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
604 .disp = imm,
605 .base = src_reg,
606 }),
650 isel.code,607 isel.code,
651 ) catch |err| isel.failWithLoweringError(err);608 ) catch |err| isel.failWithLoweringError(err);
652 },609 },
...@@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -657,7 +614,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
657 lowerToRmEnc(614 lowerToRmEnc(
658 .lea,615 .lea,
659 ops.reg1,616 ops.reg1,
660 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),617 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
661 isel.code,618 isel.code,
662 ) catch |err| return isel.failWithLoweringError(err);619 ) catch |err| return isel.failWithLoweringError(err);
663 const end_offset = isel.code.items.len;620 const end_offset = isel.code.items.len;
...@@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {...@@ -673,7 +630,7 @@ fn mirLea(isel: *Isel, inst: Mir.Inst.Index) InnerError!void {
673 lowerToRmEnc(630 lowerToRmEnc(
674 .lea,631 .lea,
675 ops.reg1,632 ops.reg1,
676 RegisterOrMemory.rip(0, Memory.PtrSize.fromBits(ops.reg1.size())),633 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
677 isel.code,634 isel.code,
678 ) catch |err| return isel.failWithLoweringError(err);635 ) catch |err| return isel.failWithLoweringError(err);
679 const end_offset = isel.code.items.len;636 const end_offset = isel.code.items.len;
...@@ -1273,17 +1230,29 @@ const Memory = struct {...@@ -1273,17 +1230,29 @@ const Memory = struct {
1273 if (mem_op.base) |base| {1230 if (mem_op.base) |base| {
1274 const dst = base.lowId();1231 const dst = base.lowId();
1275 const src = operand;1232 const src = operand;
1276 if (dst == 4) {1233 if (dst == 4 or mem_op.scale_index != null) {
1277 if (mem_op.disp == 0) {1234 if (mem_op.disp == 0) {
1278 encoder.modRm_SIBDisp0(src);1235 encoder.modRm_SIBDisp0(src);
1279 encoder.sib_base(dst);1236 if (mem_op.scale_index) |si| {
1237 encoder.sib_scaleIndexBase(si.scale, si.index.lowId(), dst);
1238 } else {
1239 encoder.sib_base(dst);
1240 }
1280 } else if (immOpSize(mem_op.disp) == 8) {1241 } else if (immOpSize(mem_op.disp) == 8) {
1281 encoder.modRm_SIBDisp8(src);1242 encoder.modRm_SIBDisp8(src);
1282 encoder.sib_baseDisp8(dst);1243 if (mem_op.scale_index) |si| {
1244 encoder.sib_scaleIndexBaseDisp8(si.scale, si.index.lowId(), dst);
1245 } else {
1246 encoder.sib_baseDisp8(dst);
1247 }
1283 encoder.disp8(@intCast(i8, mem_op.disp));1248 encoder.disp8(@intCast(i8, mem_op.disp));
1284 } else {1249 } else {
1285 encoder.modRm_SIBDisp32(src);1250 encoder.modRm_SIBDisp32(src);
1286 encoder.sib_baseDisp32(dst);1251 if (mem_op.scale_index) |si| {
1252 encoder.sib_scaleIndexBaseDisp32(si.scale, si.index.lowId(), dst);
1253 } else {
1254 encoder.sib_baseDisp32(dst);
1255 }
1287 encoder.disp32(mem_op.disp);1256 encoder.disp32(mem_op.disp);
1288 }1257 }
1289 } else {1258 } else {
...@@ -1302,7 +1271,11 @@ const Memory = struct {...@@ -1302,7 +1271,11 @@ const Memory = struct {
1302 encoder.modRm_RIPDisp32(operand);1271 encoder.modRm_RIPDisp32(operand);
1303 } else {1272 } else {
1304 encoder.modRm_SIBDisp0(operand);1273 encoder.modRm_SIBDisp0(operand);
1305 encoder.sib_disp32();1274 if (mem_op.scale_index) |si| {
1275 encoder.sib_scaleIndexDisp32(si.scale, si.index.lowId());
1276 } else {
1277 encoder.sib_disp32();
1278 }
1306 }1279 }
1307 encoder.disp32(mem_op.disp);1280 encoder.disp32(mem_op.disp);
1308 }1281 }
...@@ -1326,17 +1299,22 @@ const RegisterOrMemory = union(enum) {...@@ -1326,17 +1299,22 @@ const RegisterOrMemory = union(enum) {
1326 return .{ .register = register };1299 return .{ .register = register };
1327 }1300 }
13281301
1329 fn mem(base: ?Register, disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory {1302 fn mem(ptr_size: Memory.PtrSize, args: struct {
1303 disp: i32,
1304 base: ?Register = null,
1305 scale_index: ?ScaleIndex = null,
1306 }) RegisterOrMemory {
1330 return .{1307 return .{
1331 .memory = .{1308 .memory = .{
1332 .base = base,1309 .base = args.base,
1333 .disp = disp,1310 .disp = args.disp,
1334 .ptr_size = ptr_size,1311 .ptr_size = ptr_size,
1312 .scale_index = args.scale_index,
1335 },1313 },
1336 };1314 };
1337 }1315 }
13381316
1339 fn rip(disp: i32, ptr_size: Memory.PtrSize) RegisterOrMemory {1317 fn rip(ptr_size: Memory.PtrSize, disp: i32) RegisterOrMemory {
1340 return .{1318 return .{
1341 .memory = .{1319 .memory = .{
1342 .base = null,1320 .base = null,
...@@ -1566,6 +1544,10 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr...@@ -1566,6 +1544,10 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
1566 .w = dst_mem.ptr_size == .qword_ptr,1544 .w = dst_mem.ptr_size == .qword_ptr,
1567 .b = base.isExtended(),1545 .b = base.isExtended(),
1568 });1546 });
1547 } else {
1548 encoder.rex(.{
1549 .w = dst_mem.ptr_size == .qword_ptr,
1550 });
1569 }1551 }
1570 opc.encode(encoder);1552 opc.encode(encoder);
1571 dst_mem.encode(encoder, modrm_ext);1553 dst_mem.encode(encoder, modrm_ext);
...@@ -1782,44 +1764,62 @@ test "lower MI encoding" {...@@ -1782,44 +1764,62 @@ test "lower MI encoding" {
1782 defer isel.deinit();1764 defer isel.deinit();
1783 try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());1765 try lowerToMiEnc(.mov, RegisterOrMemory.reg(.rax), 0x10, isel.code());
1784 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");1766 try expectEqualHexStrings("\x48\xc7\xc0\x10\x00\x00\x00", isel.lowered(), "mov rax, 0x10");
1785 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.r11, 0, .dword_ptr), 0x10, isel.code());1767 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0, .base = .r11 }), 0x10, isel.code());
1786 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");1768 try expectEqualHexStrings("\x41\xc7\x03\x10\x00\x00\x00", isel.lowered(), "mov dword ptr [r11 + 0], 0x10");
1787 try lowerToMiEnc(.add, RegisterOrMemory.mem(.rdx, -8, .dword_ptr), 0x10, isel.code());1769 try lowerToMiEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = -8, .base = .rdx }), 0x10, isel.code());
1788 try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");1770 try expectEqualHexStrings("\x81\x42\xF8\x10\x00\x00\x00", isel.lowered(), "add dword ptr [rdx - 8], 0x10");
1789 try lowerToMiEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .dword_ptr), 0x10, isel.code());1771 try lowerToMiEnc(.sub, RegisterOrMemory.mem(.dword_ptr, .{
1772 .disp = 0x10000000,
1773 .base = .r11,
1774 }), 0x10, isel.code());
1790 try expectEqualHexStrings(1775 try expectEqualHexStrings(
1791 "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",1776 "\x41\x81\xab\x00\x00\x00\x10\x10\x00\x00\x00",
1792 isel.lowered(),1777 isel.lowered(),
1793 "sub dword ptr [r11 + 0x10000000], 0x10",1778 "sub dword ptr [r11 + 0x10000000], 0x10",
1794 );1779 );
1795 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), 0x10, isel.code());1780 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), 0x10, isel.code());
1796 try expectEqualHexStrings(1781 try expectEqualHexStrings(
1797 "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",1782 "\x81\x24\x25\x00\x00\x00\x10\x10\x00\x00\x00",
1798 isel.lowered(),1783 isel.lowered(),
1799 "and dword ptr [ds:0x10000000], 0x10",1784 "and dword ptr [ds:0x10000000], 0x10",
1800 );1785 );
1801 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.r12, 0x10000000, .dword_ptr), 0x10, isel.code());1786 try lowerToMiEnc(.@"and", RegisterOrMemory.mem(.dword_ptr, .{
1787 .disp = 0x10000000,
1788 .base = .r12,
1789 }), 0x10, isel.code());
1802 try expectEqualHexStrings(1790 try expectEqualHexStrings(
1803 "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",1791 "\x41\x81\xA4\x24\x00\x00\x00\x10\x10\x00\x00\x00",
1804 isel.lowered(),1792 isel.lowered(),
1805 "and dword ptr [r12 + 0x10000000], 0x10",1793 "and dword ptr [r12 + 0x10000000], 0x10",
1806 );1794 );
1807 try lowerToMiEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), 0x10, isel.code());1795 try lowerToMiEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), 0x10, isel.code());
1808 try expectEqualHexStrings(1796 try expectEqualHexStrings(
1809 "\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",1797 "\x48\xC7\x05\x10\x00\x00\x00\x10\x00\x00\x00",
1810 isel.lowered(),1798 isel.lowered(),
1811 "mov qword ptr [rip + 0x10], 0x10",1799 "mov qword ptr [rip + 0x10], 0x10",
1812 );1800 );
1813 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code());1801 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -8, .base = .rbp }), 0x10, isel.code());
1814 try expectEqualHexStrings(1802 try expectEqualHexStrings(
1815 "\x48\xc7\x45\xf8\x10\x00\x00\x00",1803 "\x48\xc7\x45\xf8\x10\x00\x00\x00",
1816 isel.lowered(),1804 isel.lowered(),
1817 "mov qword ptr [rbp - 8], 0x10",1805 "mov qword ptr [rbp - 8], 0x10",
1818 );1806 );
1819 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code());1807 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.word_ptr, .{ .disp = -2, .base = .rbp }), 0x10, isel.code());
1820 try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");1808 try expectEqualHexStrings("\x66\xC7\x45\xFE\x10\x00", isel.lowered(), "mov word ptr [rbp - 2], 0x10");
1821 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.rbp, -1, .byte_ptr), 0x10, isel.code());1809 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.byte_ptr, .{ .disp = -1, .base = .rbp }), 0x10, isel.code());
1822 try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");1810 try expectEqualHexStrings("\xC6\x45\xFF\x10", isel.lowered(), "mov byte ptr [rbp - 1], 0x10");
1811 try lowerToMiEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
1812 .disp = 0x10000000,
1813 .scale_index = .{
1814 .scale = 1,
1815 .index = .rcx,
1816 },
1817 }), 0x10, isel.code());
1818 try expectEqualHexStrings(
1819 "\x48\xC7\x04\x4D\x00\x00\x00\x10\x10\x00\x00\x00",
1820 isel.lowered(),
1821 "mov qword ptr [rcx*2 + 0x10000000], 0x10",
1822 );
1823}1823}
18241824
1825test "lower RM encoding" {1825test "lower RM encoding" {
...@@ -1827,36 +1827,69 @@ test "lower RM encoding" {...@@ -1827,36 +1827,69 @@ test "lower RM encoding" {
1827 defer isel.deinit();1827 defer isel.deinit();
1828 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());1828 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), isel.code());
1829 try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx");1829 try expectEqualHexStrings("\x48\x8b\xc3", isel.lowered(), "mov rax, rbx");
1830 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.r11, 0, .qword_ptr), isel.code());1830 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), isel.code());
1831 try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]");1831 try expectEqualHexStrings("\x49\x8b\x03", isel.lowered(), "mov rax, qword ptr [r11 + 0]");
1832 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(null, 0x10000000, .qword_ptr), isel.code());1832 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), isel.code());
1833 try expectEqualHexStrings(1833 try expectEqualHexStrings(
1834 "\x4C\x03\x1C\x25\x00\x00\x00\x10",1834 "\x4C\x03\x1C\x25\x00\x00\x00\x10",
1835 isel.lowered(),1835 isel.lowered(),
1836 "add r11, qword ptr [ds:0x10000000]",1836 "add r11, qword ptr [ds:0x10000000]",
1837 );1837 );
1838 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), isel.code());1838 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), isel.code());
1839 try expectEqualHexStrings(1839 try expectEqualHexStrings(
1840 "\x44\x02\x24\x25\x00\x00\x00\x10",1840 "\x44\x02\x24\x25\x00\x00\x00\x10",
1841 isel.lowered(),1841 isel.lowered(),
1842 "add r11b, byte ptr [ds:0x10000000]",1842 "add r11b, byte ptr [ds:0x10000000]",
1843 );1843 );
1844 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r13, 0x10000000, .qword_ptr), isel.code());1844 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
1845 .disp = 0x10000000,
1846 .base = .r13,
1847 }), isel.code());
1845 try expectEqualHexStrings(1848 try expectEqualHexStrings(
1846 "\x4D\x2B\x9D\x00\x00\x00\x10",1849 "\x4D\x2B\x9D\x00\x00\x00\x10",
1847 isel.lowered(),1850 isel.lowered(),
1848 "sub r11, qword ptr [r13 + 0x10000000]",1851 "sub r11, qword ptr [r13 + 0x10000000]",
1849 );1852 );
1850 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.r12, 0x10000000, .qword_ptr), isel.code());1853 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{
1854 .disp = 0x10000000,
1855 .base = .r12,
1856 }), isel.code());
1851 try expectEqualHexStrings(1857 try expectEqualHexStrings(
1852 "\x4D\x2B\x9C\x24\x00\x00\x00\x10",1858 "\x4D\x2B\x9C\x24\x00\x00\x00\x10",
1853 isel.lowered(),1859 isel.lowered(),
1854 "sub r11, qword ptr [r12 + 0x10000000]",1860 "sub r11, qword ptr [r12 + 0x10000000]",
1855 );1861 );
1856 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), isel.code());1862 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), isel.code());
1857 try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");1863 try expectEqualHexStrings("\x48\x8B\x45\xFC", isel.lowered(), "mov rax, qword ptr [rbp - 4]");
1858 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code());1864 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
1859 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");1865 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", isel.lowered(), "lea rax, [rip + 0x10]");
1866 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
1867 .disp = -8,
1868 .base = .rbp,
1869 .scale_index = .{
1870 .scale = 0,
1871 .index = .rcx,
1872 },
1873 }), isel.code());
1874 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
1875 try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{
1876 .disp = -4,
1877 .base = .rbp,
1878 .scale_index = .{
1879 .scale = 2,
1880 .index = .rdx,
1881 },
1882 }), isel.code());
1883 try expectEqualHexStrings("\x8B\x44\x95\xFC", isel.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
1884 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{
1885 .disp = -8,
1886 .base = .rbp,
1887 .scale_index = .{
1888 .scale = 3,
1889 .index = .rcx,
1890 },
1891 }), isel.code());
1892 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", isel.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
1860}1893}
18611894
1862test "lower MR encoding" {1895test "lower MR encoding" {
...@@ -1864,27 +1897,30 @@ test "lower MR encoding" {...@@ -1864,27 +1897,30 @@ test "lower MR encoding" {
1864 defer isel.deinit();1897 defer isel.deinit();
1865 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());1898 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, isel.code());
1866 try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");1899 try expectEqualHexStrings("\x48\x89\xd8", isel.lowered(), "mov rax, rbx");
1867 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.rbp, -4, .qword_ptr), .r11, isel.code());1900 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ .disp = -4, .base = .rbp }), .r11, isel.code());
1868 try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");1901 try expectEqualHexStrings("\x4c\x89\x5d\xfc", isel.lowered(), "mov qword ptr [rbp - 4], r11");
1869 try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .byte_ptr), .r12b, isel.code());1902 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, isel.code());
1870 try expectEqualHexStrings(1903 try expectEqualHexStrings(
1871 "\x44\x00\x24\x25\x00\x00\x00\x10",1904 "\x44\x00\x24\x25\x00\x00\x00\x10",
1872 isel.lowered(),1905 isel.lowered(),
1873 "add byte ptr [ds:0x10000000], r12b",1906 "add byte ptr [ds:0x10000000], r12b",
1874 );1907 );
1875 try lowerToMrEnc(.add, RegisterOrMemory.mem(null, 0x10000000, .dword_ptr), .r12d, isel.code());1908 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, isel.code());
1876 try expectEqualHexStrings(1909 try expectEqualHexStrings(
1877 "\x44\x01\x24\x25\x00\x00\x00\x10",1910 "\x44\x01\x24\x25\x00\x00\x00\x10",
1878 isel.lowered(),1911 isel.lowered(),
1879 "add dword ptr [ds:0x10000000], r12d",1912 "add dword ptr [ds:0x10000000], r12d",
1880 );1913 );
1881 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.r11, 0x10000000, .qword_ptr), .r12, isel.code());1914 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{
1915 .disp = 0x10000000,
1916 .base = .r11,
1917 }), .r12, isel.code());
1882 try expectEqualHexStrings(1918 try expectEqualHexStrings(
1883 "\x4D\x29\xA3\x00\x00\x00\x10",1919 "\x4D\x29\xA3\x00\x00\x00\x10",
1884 isel.lowered(),1920 isel.lowered(),
1885 "sub qword ptr [r11 + 0x10000000], r12",1921 "sub qword ptr [r11 + 0x10000000], r12",
1886 );1922 );
1887 try lowerToMrEnc(.mov, RegisterOrMemory.rip(0x10, .qword_ptr), .r12, isel.code());1923 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, isel.code());
1888 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");1924 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", isel.lowered(), "mov qword ptr [rip + 0x10], r12");
1889}1925}
18901926
...@@ -1935,21 +1971,24 @@ test "lower M encoding" {...@@ -1935,21 +1971,24 @@ test "lower M encoding" {
1935 try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");1971 try expectEqualHexStrings("\x41\xFF\xE4", isel.lowered(), "jmp r12");
1936 try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());1972 try lowerToMEnc(.jmp_near, RegisterOrMemory.reg(.r12w), isel.code());
1937 try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w");1973 try expectEqualHexStrings("\x66\x41\xFF\xE4", isel.lowered(), "jmp r12w");
1938 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .qword_ptr), isel.code());1974 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
1939 try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]");1975 try expectEqualHexStrings("\x41\xFF\x24\x24", isel.lowered(), "jmp qword ptr [r12]");
1940 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0, .word_ptr), isel.code());1976 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.word_ptr, .{ .disp = 0, .base = .r12 }), isel.code());
1941 try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]");1977 try expectEqualHexStrings("\x66\x41\xFF\x24\x24", isel.lowered(), "jmp word ptr [r12]");
1942 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x10, .qword_ptr), isel.code());1978 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10, .base = .r12 }), isel.code());
1943 try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]");1979 try expectEqualHexStrings("\x41\xFF\x64\x24\x10", isel.lowered(), "jmp qword ptr [r12 + 0x10]");
1944 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.r12, 0x1000, .qword_ptr), isel.code());1980 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{
1981 .disp = 0x1000,
1982 .base = .r12,
1983 }), isel.code());
1945 try expectEqualHexStrings(1984 try expectEqualHexStrings(
1946 "\x41\xFF\xA4\x24\x00\x10\x00\x00",1985 "\x41\xFF\xA4\x24\x00\x10\x00\x00",
1947 isel.lowered(),1986 isel.lowered(),
1948 "jmp qword ptr [r12 + 0x1000]",1987 "jmp qword ptr [r12 + 0x1000]",
1949 );1988 );
1950 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(0x10, .qword_ptr), isel.code());1989 try lowerToMEnc(.jmp_near, RegisterOrMemory.rip(.qword_ptr, 0x10), isel.code());
1951 try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]");1990 try expectEqualHexStrings("\xFF\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [rip + 0x10]");
1952 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(null, 0x10, .qword_ptr), isel.code());1991 try lowerToMEnc(.jmp_near, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10 }), isel.code());
1953 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");1992 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", isel.lowered(), "jmp qword ptr [ds:0x10]");
1954 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());1993 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), isel.code());
1955 try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");1994 try expectEqualHexStrings("\x41\x0F\x97\xC3", isel.lowered(), "seta r11b");
...@@ -1967,15 +2006,24 @@ test "lower O encoding" {...@@ -1967,15 +2006,24 @@ test "lower O encoding" {
1967test "lower RMI encoding" {2006test "lower RMI encoding" {
1968 var isel = TestIsel.init();2007 var isel = TestIsel.init();
1969 defer isel.deinit();2008 defer isel.deinit();
1970 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.rbp, -8, .qword_ptr), 0x10, isel.code());2009 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{
2010 .disp = -8,
2011 .base = .rbp,
2012 }), 0x10, isel.code());
1971 try expectEqualHexStrings(2013 try expectEqualHexStrings(
1972 "\x48\x69\x45\xF8\x10\x00\x00\x00",2014 "\x48\x69\x45\xF8\x10\x00\x00\x00",
1973 isel.lowered(),2015 isel.lowered(),
1974 "imul rax, qword ptr [rbp - 8], 0x10",2016 "imul rax, qword ptr [rbp - 8], 0x10",
1975 );2017 );
1976 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.rbp, -4, .dword_ptr), 0x10, isel.code());2018 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{
2019 .disp = -4,
2020 .base = .rbp,
2021 }), 0x10, isel.code());
1977 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");2022 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", isel.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
1978 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.rbp, -2, .word_ptr), 0x10, isel.code());2023 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{
2024 .disp = -2,
2025 .base = .rbp,
2026 }), 0x10, isel.code());
1979 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");2027 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", isel.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
1980 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());2028 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, isel.code());
1981 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");2029 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", isel.lowered(), "imul r12, r12, 0x10");