authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-12 20:52:52+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-19 19:36:35+02:00
log019cc94ec7291c652b3e18980194e028f8df9ec1
tree33ef6ce1fe00ea5217ffdd09cdbc7cc2e168957b
parent875a16030c2e58f9f8b9a2b66b43b565e3932cf5

x64: clean up populating VEX prefix


2 files changed, 222 insertions(+), 201 deletions(-)

src/arch/x86_64/Emit.zig+105-112
...@@ -249,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -249,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
249 switch (ops.flags) {249 switch (ops.flags) {
250 0b00 => {250 0b00 => {
251 // PUSH/POP reg251 // PUSH/POP reg
252 return lowerToOEnc(tag, .{ .register = ops.reg1 }, emit.code);252 return lowerToOEnc(tag, Register.reg(ops.reg1), emit.code);
253 },253 },
254 0b01 => {254 0b01 => {
255 // PUSH/POP r/m64255 // PUSH/POP r/m64
...@@ -285,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I...@@ -285,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I
285 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{285 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
286 .disp = @bitCast(u32, -@intCast(i32, disp)),286 .disp = @bitCast(u32, -@intCast(i32, disp)),
287 .base = ops.reg1,287 .base = ops.reg1,
288 }), .{ .register = reg.to64() }, emit.code);288 }), Register.reg(reg.to64()), emit.code);
289 } else {289 } else {
290 try lowerToRmEnc(.mov, .{ .register = reg.to64() }, RegisterOrMemory.mem(.qword_ptr, .{290 try lowerToRmEnc(.mov, Register.reg(reg.to64()), RegisterOrMemory.mem(.qword_ptr, .{
291 .disp = @bitCast(u32, -@intCast(i32, disp)),291 .disp = @bitCast(u32, -@intCast(i32, disp)),
292 .base = ops.reg1,292 .base = ops.reg1,
293 }), emit.code);293 }), emit.code);
...@@ -321,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -321,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
321 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code);321 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code);
322 }322 }
323 // JMP/CALL reg323 // JMP/CALL reg
324 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);324 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
325 },325 },
326 0b10 => {326 0b10 => {
327 // JMP/CALL r/m64327 // JMP/CALL r/m64
...@@ -394,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne...@@ -394,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne
394 },394 },
395 else => unreachable,395 else => unreachable,
396 };396 };
397 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1.to8() }), emit.code);397 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1.to8()), emit.code);
398}398}
399399
400fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {400fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
401 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);401 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
402 if (ops.flags == 0b00) {402 if (ops.flags == 0b00) {
403 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.reg(.{ .register = ops.reg2 }), emit.code);403 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);
404 }404 }
405 const imm = emit.mir.instructions.items(.data)[inst].imm;405 const imm = emit.mir.instructions.items(.data)[inst].imm;
406 const ptr_size: Memory.PtrSize = switch (ops.flags) {406 const ptr_size: Memory.PtrSize = switch (ops.flags) {
...@@ -409,7 +409,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -409,7 +409,7 @@ fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
409 0b10 => .dword_ptr,409 0b10 => .dword_ptr,
410 0b11 => .qword_ptr,410 0b11 => .qword_ptr,
411 };411 };
412 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(ptr_size, .{412 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(ptr_size, .{
413 .disp = imm,413 .disp = imm,
414 .base = ops.reg2,414 .base = ops.reg2,
415 }), emit.code);415 }), emit.code);
...@@ -430,13 +430,13 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -430,13 +430,13 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
430 // I430 // I
431 return lowerToIEnc(.@"test", imm, emit.code);431 return lowerToIEnc(.@"test", imm, emit.code);
432 }432 }
433 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);433 return lowerToMiEnc(.@"test", RegisterOrMemory.reg(ops.reg1), imm, emit.code);
434 }434 }
435 // TEST r/m64, r64435 // TEST r/m64, r64
436 return lowerToMrEnc(436 return lowerToMrEnc(
437 .@"test",437 .@"test",
438 RegisterOrMemory.reg(.{ .register = ops.reg1 }),438 RegisterOrMemory.reg(ops.reg1),
439 .{ .register = ops.reg2 },439 Register.reg(ops.reg2),
440 emit.code,440 emit.code,
441 );441 );
442 },442 },
...@@ -478,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -478,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
478 // mov reg1, imm32478 // mov reg1, imm32
479 // MI479 // MI
480 const imm = emit.mir.instructions.items(.data)[inst].imm;480 const imm = emit.mir.instructions.items(.data)[inst].imm;
481 return lowerToMiEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);481 return lowerToMiEnc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);
482 }482 }
483 // mov reg1, reg2483 // mov reg1, reg2
484 // RM484 // RM
485 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.reg(.{ .register = ops.reg2 }), emit.code);485 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);
486 },486 },
487 0b01 => {487 0b01 => {
488 // mov reg1, [reg2 + imm32]488 // mov reg1, [reg2 + imm32]
489 // RM489 // RM
490 const imm = emit.mir.instructions.items(.data)[inst].imm;490 const imm = emit.mir.instructions.items(.data)[inst].imm;
491 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;491 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
492 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{492 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
493 .disp = imm,493 .disp = imm,
494 .base = src_reg,494 .base = src_reg,
495 }), emit.code);495 }), emit.code);
...@@ -504,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -504,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
504 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{504 return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{
505 .disp = imm,505 .disp = imm,
506 .base = ops.reg1,506 .base = ops.reg1,
507 }), .{ .register = ops.reg2 }, emit.code);507 }), Register.reg(ops.reg2), emit.code);
508 },508 },
509 0b11 => {509 0b11 => {
510 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});510 return emit.fail("TODO unused variant: mov reg1, reg2, 0b11", .{});
...@@ -562,7 +562,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -562,7 +562,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
562 .scale = scale,562 .scale = scale,
563 .index = .rcx,563 .index = .rcx,
564 };564 };
565 return lowerToRmEnc(tag, .{ .register = ops.reg1 }, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{565 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
566 .disp = imm,566 .disp = imm,
567 .base = ops.reg2,567 .base = ops.reg2,
568 .scale_index = scale_index,568 .scale_index = scale_index,
...@@ -590,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void...@@ -590,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
590 .disp = imm,590 .disp = imm,
591 .base = ops.reg1,591 .base = ops.reg1,
592 .scale_index = scale_index,592 .scale_index = scale_index,
593 }), .{ .register = ops.reg2 }, emit.code);593 }), Register.reg(ops.reg2), emit.code);
594}594}
595595
596fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {596fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
...@@ -641,27 +641,22 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -641,27 +641,22 @@ fn mirMovSignExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
641 switch (ops.flags) {641 switch (ops.flags) {
642 0b00 => {642 0b00 => {
643 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;643 const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx;
644 return lowerToRmEnc(644 return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);
645 tag,
646 .{ .register = ops.reg1 },
647 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
648 emit.code,
649 );
650 },645 },
651 0b01 => {646 0b01 => {
652 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{647 return lowerToRmEnc(.movsx, Register.reg(ops.reg1), RegisterOrMemory.mem(.byte_ptr, .{
653 .disp = imm,648 .disp = imm,
654 .base = ops.reg2,649 .base = ops.reg2,
655 }), emit.code);650 }), emit.code);
656 },651 },
657 0b10 => {652 0b10 => {
658 return lowerToRmEnc(.movsx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{653 return lowerToRmEnc(.movsx, Register.reg(ops.reg1), RegisterOrMemory.mem(.word_ptr, .{
659 .disp = imm,654 .disp = imm,
660 .base = ops.reg2,655 .base = ops.reg2,
661 }), emit.code);656 }), emit.code);
662 },657 },
663 0b11 => {658 0b11 => {
664 return lowerToRmEnc(.movsxd, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.dword_ptr, .{659 return lowerToRmEnc(.movsxd, Register.reg(ops.reg1), RegisterOrMemory.mem(.dword_ptr, .{
665 .disp = imm,660 .disp = imm,
666 .base = ops.reg2,661 .base = ops.reg2,
667 }), emit.code);662 }), emit.code);
...@@ -676,21 +671,16 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -676,21 +671,16 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
676 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;671 const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined;
677 switch (ops.flags) {672 switch (ops.flags) {
678 0b00 => {673 0b00 => {
679 return lowerToRmEnc(674 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);
680 .movzx,
681 .{ .register = ops.reg1 },
682 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
683 emit.code,
684 );
685 },675 },
686 0b01 => {676 0b01 => {
687 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.byte_ptr, .{677 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.mem(.byte_ptr, .{
688 .disp = imm,678 .disp = imm,
689 .base = ops.reg2,679 .base = ops.reg2,
690 }), emit.code);680 }), emit.code);
691 },681 },
692 0b10 => {682 0b10 => {
693 return lowerToRmEnc(.movzx, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.word_ptr, .{683 return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.mem(.word_ptr, .{
694 .disp = imm,684 .disp = imm,
695 .base = ops.reg2,685 .base = ops.reg2,
696 }), emit.code);686 }), emit.code);
...@@ -713,16 +703,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -713,16 +703,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
713 if (ops.flags == 0b00) {703 if (ops.flags == 0b00) {
714 // movabs reg, imm64704 // movabs reg, imm64
715 // OI705 // OI
716 return lowerToOiEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);706 return lowerToOiEnc(.mov, Register.reg(ops.reg1), imm, emit.code);
717 }707 }
718 if (ops.reg1 == .none) {708 if (ops.reg1 == .none) {
719 // movabs moffs64, rax709 // movabs moffs64, rax
720 // TD710 // TD
721 return lowerToTdEnc(.mov, imm, .{ .register = ops.reg2 }, emit.code);711 return lowerToTdEnc(.mov, imm, Register.reg(ops.reg2), emit.code);
722 }712 }
723 // movabs rax, moffs64713 // movabs rax, moffs64
724 // FD714 // FD
725 return lowerToFdEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code);715 return lowerToFdEnc(.mov, Register.reg(ops.reg1), imm, emit.code);
726}716}
727717
728fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {718fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
...@@ -773,18 +763,18 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -773,18 +763,18 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
773 0b00 => {763 0b00 => {
774 // sal reg1, 1764 // sal reg1, 1
775 // M1765 // M1
776 return lowerToM1Enc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);766 return lowerToM1Enc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
777 },767 },
778 0b01 => {768 0b01 => {
779 // sal reg1, .cl769 // sal reg1, .cl
780 // MC770 // MC
781 return lowerToMcEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);771 return lowerToMcEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
782 },772 },
783 0b10 => {773 0b10 => {
784 // sal reg1, imm8774 // sal reg1, imm8
785 // MI775 // MI
786 const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);776 const imm = @truncate(u8, emit.mir.instructions.items(.data)[inst].imm);
787 return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), imm, emit.code);777 return lowerToMiImm8Enc(tag, RegisterOrMemory.reg(ops.reg1), imm, emit.code);
788 },778 },
789 0b11 => {779 0b11 => {
790 return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});780 return emit.fail("TODO unused variant: SHIFT reg1, 0b11", .{});
...@@ -796,7 +786,7 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {...@@ -796,7 +786,7 @@ fn mirMulDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
796 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);786 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
797 if (ops.reg1 != .none) {787 if (ops.reg1 != .none) {
798 assert(ops.reg2 == .none);788 assert(ops.reg2 == .none);
799 return lowerToMEnc(tag, RegisterOrMemory.reg(.{ .register = ops.reg1 }), emit.code);789 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
800 }790 }
801 assert(ops.reg1 == .none);791 assert(ops.reg1 == .none);
802 assert(ops.reg2 != .none);792 assert(ops.reg2 != .none);
...@@ -819,35 +809,24 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -819,35 +809,24 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
819 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);809 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
820 switch (ops.flags) {810 switch (ops.flags) {
821 0b00 => {811 0b00 => {
822 return lowerToRmEnc(812 return lowerToRmEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code);
823 .imul,
824 .{ .register = ops.reg1 },
825 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
826 emit.code,
827 );
828 },813 },
829 0b01 => {814 0b01 => {
830 const imm = emit.mir.instructions.items(.data)[inst].imm;815 const imm = emit.mir.instructions.items(.data)[inst].imm;
831 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;816 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
832 return lowerToRmEnc(.imul, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.qword_ptr, .{817 return lowerToRmEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.mem(.qword_ptr, .{
833 .disp = imm,818 .disp = imm,
834 .base = src_reg,819 .base = src_reg,
835 }), emit.code);820 }), emit.code);
836 },821 },
837 0b10 => {822 0b10 => {
838 const imm = emit.mir.instructions.items(.data)[inst].imm;823 const imm = emit.mir.instructions.items(.data)[inst].imm;
839 return lowerToRmiEnc(824 return lowerToRmiEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), imm, emit.code);
840 .imul,
841 .{ .register = ops.reg1 },
842 RegisterOrMemory.reg(.{ .register = ops.reg2 }),
843 imm,
844 emit.code,
845 );
846 },825 },
847 0b11 => {826 0b11 => {
848 const payload = emit.mir.instructions.items(.data)[inst].payload;827 const payload = emit.mir.instructions.items(.data)[inst].payload;
849 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;828 const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data;
850 return lowerToRmiEnc(.imul, .{ .register = ops.reg1 }, RegisterOrMemory.mem(.qword_ptr, .{829 return lowerToRmiEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.mem(.qword_ptr, .{
851 .disp = imm_pair.dest_off,830 .disp = imm_pair.dest_off,
852 .base = ops.reg2,831 .base = ops.reg2,
853 }), imm_pair.operand, emit.code);832 }), imm_pair.operand, emit.code);
...@@ -878,7 +857,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -878,7 +857,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
878 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;857 const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2;
879 return lowerToRmEnc(858 return lowerToRmEnc(
880 .lea,859 .lea,
881 .{ .register = ops.reg1 },860 Register.reg(ops.reg1),
882 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{861 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
883 .disp = imm,862 .disp = imm,
884 .base = src_reg,863 .base = src_reg,
...@@ -892,7 +871,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -892,7 +871,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
892 const start_offset = emit.code.items.len;871 const start_offset = emit.code.items.len;
893 try lowerToRmEnc(872 try lowerToRmEnc(
894 .lea,873 .lea,
895 .{ .register = ops.reg1 },874 Register.reg(ops.reg1),
896 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),875 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
897 emit.code,876 emit.code,
898 );877 );
...@@ -913,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -913,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
913 };892 };
914 return lowerToRmEnc(893 return lowerToRmEnc(
915 .lea,894 .lea,
916 .{ .register = ops.reg1 },895 Register.reg(ops.reg1),
917 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{896 RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{
918 .disp = imm,897 .disp = imm,
919 .base = src_reg,898 .base = src_reg,
...@@ -936,7 +915,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -936,7 +915,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
936 // RM915 // RM
937 try lowerToRmEnc(916 try lowerToRmEnc(
938 .lea,917 .lea,
939 .{ .register = ops.reg1 },918 Register.reg(ops.reg1),
940 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),919 RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0),
941 emit.code,920 emit.code,
942 );921 );
...@@ -1666,8 +1645,12 @@ const RegisterOrMemory = union(enum) {...@@ -1666,8 +1645,12 @@ const RegisterOrMemory = union(enum) {
1666 register: Register,1645 register: Register,
1667 memory: Memory,1646 memory: Memory,
16681647
1669 fn reg(register: Register) RegisterOrMemory {1648 fn reg(register: GpRegister) RegisterOrMemory {
1670 return .{ .register = register };1649 return .{ .register = Register.reg(register) };
1650 }
1651
1652 fn avxReg(register: AvxRegister) RegisterOrMemory {
1653 return .{ .register = Register.avxReg(register) };
1671 }1654 }
16721655
1673 fn mem(ptr_size: Memory.PtrSize, args: struct {1656 fn mem(ptr_size: Memory.PtrSize, args: struct {
...@@ -1976,22 +1959,32 @@ fn lowerToMrEnc(...@@ -1976,22 +1959,32 @@ fn lowerToMrEnc(
1976 encoder.modRm_direct(reg.lowId(), dst_reg.lowId());1959 encoder.modRm_direct(reg.lowId(), dst_reg.lowId());
1977 },1960 },
1978 .memory => |dst_mem| {1961 .memory => |dst_mem| {
1979 const encoder = try Encoder.init(code, 9);1962 const encoder = blk: {
1980 if (reg.size() == 16) {1963 switch (reg) {
1981 encoder.prefix16BitMode();1964 .register => {
1982 }1965 const encoder = try Encoder.init(code, 9);
1983 if (dst_mem.base) |base| {1966 if (reg.size() == 16) {
1984 encoder.rex(.{1967 encoder.prefix16BitMode();
1985 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),1968 }
1986 .r = reg.isExtended(),1969 if (dst_mem.base) |base| {
1987 .b = base.isExtended(),1970 encoder.rex(.{
1988 });1971 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
1989 } else {1972 .r = reg.isExtended(),
1990 encoder.rex(.{1973 .b = base.isExtended(),
1991 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),1974 });
1992 .r = reg.isExtended(),1975 } else {
1993 });1976 encoder.rex(.{
1994 }1977 .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg),
1978 .r = reg.isExtended(),
1979 });
1980 }
1981 break :blk encoder;
1982 },
1983 .avx_register => {
1984 unreachable;
1985 },
1986 }
1987 };
1995 opc.encode(encoder);1988 opc.encode(encoder);
1996 dst_mem.encode(encoder, reg.lowId());1989 dst_mem.encode(encoder, reg.lowId());
1997 },1990 },
...@@ -2168,23 +2161,23 @@ test "lower MI encoding" {...@@ -2168,23 +2161,23 @@ test "lower MI encoding" {
2168test "lower RM encoding" {2161test "lower RM encoding" {
2169 var emit = TestEmit.init();2162 var emit = TestEmit.init();
2170 defer emit.deinit();2163 defer emit.deinit();
2171 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.reg(.rbx), emit.code());2164 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.reg(.rbx), emit.code());
2172 try expectEqualHexStrings("\x48\x8b\xc3", emit.lowered(), "mov rax, rbx");2165 try expectEqualHexStrings("\x48\x8b\xc3", emit.lowered(), "mov rax, rbx");
2173 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), emit.code());2166 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0, .base = .r11 }), emit.code());
2174 try expectEqualHexStrings("\x49\x8b\x03", emit.lowered(), "mov rax, qword ptr [r11 + 0]");2167 try expectEqualHexStrings("\x49\x8b\x03", emit.lowered(), "mov rax, qword ptr [r11 + 0]");
2175 try lowerToRmEnc(.add, .r11, RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), emit.code());2168 try lowerToRmEnc(.add, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{ .disp = 0x10000000 }), emit.code());
2176 try expectEqualHexStrings(2169 try expectEqualHexStrings(
2177 "\x4C\x03\x1C\x25\x00\x00\x00\x10",2170 "\x4C\x03\x1C\x25\x00\x00\x00\x10",
2178 emit.lowered(),2171 emit.lowered(),
2179 "add r11, qword ptr [ds:0x10000000]",2172 "add r11, qword ptr [ds:0x10000000]",
2180 );2173 );
2181 try lowerToRmEnc(.add, .r12b, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), emit.code());2174 try lowerToRmEnc(.add, Register.reg(.r12b), RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), emit.code());
2182 try expectEqualHexStrings(2175 try expectEqualHexStrings(
2183 "\x44\x02\x24\x25\x00\x00\x00\x10",2176 "\x44\x02\x24\x25\x00\x00\x00\x10",
2184 emit.lowered(),2177 emit.lowered(),
2185 "add r11b, byte ptr [ds:0x10000000]",2178 "add r11b, byte ptr [ds:0x10000000]",
2186 );2179 );
2187 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{2180 try lowerToRmEnc(.sub, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{
2188 .disp = 0x10000000,2181 .disp = 0x10000000,
2189 .base = .r13,2182 .base = .r13,
2190 }), emit.code());2183 }), emit.code());
...@@ -2193,7 +2186,7 @@ test "lower RM encoding" {...@@ -2193,7 +2186,7 @@ test "lower RM encoding" {
2193 emit.lowered(),2186 emit.lowered(),
2194 "sub r11, qword ptr [r13 + 0x10000000]",2187 "sub r11, qword ptr [r13 + 0x10000000]",
2195 );2188 );
2196 try lowerToRmEnc(.sub, .r11, RegisterOrMemory.mem(.qword_ptr, .{2189 try lowerToRmEnc(.sub, Register.reg(.r11), RegisterOrMemory.mem(.qword_ptr, .{
2197 .disp = 0x10000000,2190 .disp = 0x10000000,
2198 .base = .r12,2191 .base = .r12,
2199 }), emit.code());2192 }), emit.code());
...@@ -2202,14 +2195,14 @@ test "lower RM encoding" {...@@ -2202,14 +2195,14 @@ test "lower RM encoding" {
2202 emit.lowered(),2195 emit.lowered(),
2203 "sub r11, qword ptr [r12 + 0x10000000]",2196 "sub r11, qword ptr [r12 + 0x10000000]",
2204 );2197 );
2205 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{2198 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{
2206 .disp = @bitCast(u32, @as(i32, -4)),2199 .disp = @bitCast(u32, @as(i32, -4)),
2207 .base = .rbp,2200 .base = .rbp,
2208 }), emit.code());2201 }), emit.code());
2209 try expectEqualHexStrings("\x48\x8B\x45\xFC", emit.lowered(), "mov rax, qword ptr [rbp - 4]");2202 try expectEqualHexStrings("\x48\x8B\x45\xFC", emit.lowered(), "mov rax, qword ptr [rbp - 4]");
2210 try lowerToRmEnc(.lea, .rax, RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());2203 try lowerToRmEnc(.lea, Register.reg(.rax), RegisterOrMemory.rip(.qword_ptr, 0x10), emit.code());
2211 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", emit.lowered(), "lea rax, [rip + 0x10]");2204 try expectEqualHexStrings("\x48\x8D\x05\x10\x00\x00\x00", emit.lowered(), "lea rax, [rip + 0x10]");
2212 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{2205 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{
2213 .disp = @bitCast(u32, @as(i32, -8)),2206 .disp = @bitCast(u32, @as(i32, -8)),
2214 .base = .rbp,2207 .base = .rbp,
2215 .scale_index = .{2208 .scale_index = .{
...@@ -2218,7 +2211,7 @@ test "lower RM encoding" {...@@ -2218,7 +2211,7 @@ test "lower RM encoding" {
2218 },2211 },
2219 }), emit.code());2212 }), emit.code());
2220 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");2213 try expectEqualHexStrings("\x48\x8B\x44\x0D\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*1 - 8]");
2221 try lowerToRmEnc(.mov, .eax, RegisterOrMemory.mem(.dword_ptr, .{2214 try lowerToRmEnc(.mov, Register.reg(.eax), RegisterOrMemory.mem(.dword_ptr, .{
2222 .disp = @bitCast(u32, @as(i32, -4)),2215 .disp = @bitCast(u32, @as(i32, -4)),
2223 .base = .rbp,2216 .base = .rbp,
2224 .scale_index = .{2217 .scale_index = .{
...@@ -2227,7 +2220,7 @@ test "lower RM encoding" {...@@ -2227,7 +2220,7 @@ test "lower RM encoding" {
2227 },2220 },
2228 }), emit.code());2221 }), emit.code());
2229 try expectEqualHexStrings("\x8B\x44\x95\xFC", emit.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");2222 try expectEqualHexStrings("\x8B\x44\x95\xFC", emit.lowered(), "mov eax, dword ptr [rbp + rdx*4 - 4]");
2230 try lowerToRmEnc(.mov, .rax, RegisterOrMemory.mem(.qword_ptr, .{2223 try lowerToRmEnc(.mov, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{
2231 .disp = @bitCast(u32, @as(i32, -8)),2224 .disp = @bitCast(u32, @as(i32, -8)),
2232 .base = .rbp,2225 .base = .rbp,
2233 .scale_index = .{2226 .scale_index = .{
...@@ -2236,7 +2229,7 @@ test "lower RM encoding" {...@@ -2236,7 +2229,7 @@ test "lower RM encoding" {
2236 },2229 },
2237 }), emit.code());2230 }), emit.code());
2238 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");2231 try expectEqualHexStrings("\x48\x8B\x44\xCD\xF8", emit.lowered(), "mov rax, qword ptr [rbp + rcx*8 - 8]");
2239 try lowerToRmEnc(.mov, .r8b, RegisterOrMemory.mem(.byte_ptr, .{2232 try lowerToRmEnc(.mov, Register.reg(.r8b), RegisterOrMemory.mem(.byte_ptr, .{
2240 .disp = @bitCast(u32, @as(i32, -24)),2233 .disp = @bitCast(u32, @as(i32, -24)),
2241 .base = .rsi,2234 .base = .rsi,
2242 .scale_index = .{2235 .scale_index = .{
...@@ -2245,7 +2238,7 @@ test "lower RM encoding" {...@@ -2245,7 +2238,7 @@ test "lower RM encoding" {
2245 },2238 },
2246 }), emit.code());2239 }), emit.code());
2247 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", emit.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");2240 try expectEqualHexStrings("\x44\x8A\x44\x0E\xE8", emit.lowered(), "mov r8b, byte ptr [rsi + rcx*1 - 24]");
2248 try lowerToRmEnc(.lea, .rsi, RegisterOrMemory.mem(.qword_ptr, .{2241 try lowerToRmEnc(.lea, Register.reg(.rsi), RegisterOrMemory.mem(.qword_ptr, .{
2249 .disp = 0,2242 .disp = 0,
2250 .base = .rbp,2243 .base = .rbp,
2251 .scale_index = .{2244 .scale_index = .{
...@@ -2259,20 +2252,20 @@ test "lower RM encoding" {...@@ -2259,20 +2252,20 @@ test "lower RM encoding" {
2259test "lower MR encoding" {2252test "lower MR encoding" {
2260 var emit = TestEmit.init();2253 var emit = TestEmit.init();
2261 defer emit.deinit();2254 defer emit.deinit();
2262 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), .rbx, emit.code());2255 try lowerToMrEnc(.mov, RegisterOrMemory.reg(.rax), Register.reg(.rbx), emit.code());
2263 try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx");2256 try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx");
2264 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{2257 try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{
2265 .disp = @bitCast(u32, @as(i32, -4)),2258 .disp = @bitCast(u32, @as(i32, -4)),
2266 .base = .rbp,2259 .base = .rbp,
2267 }), .r11, emit.code());2260 }), Register.reg(.r11), emit.code());
2268 try expectEqualHexStrings("\x4c\x89\x5d\xfc", emit.lowered(), "mov qword ptr [rbp - 4], r11");2261 try expectEqualHexStrings("\x4c\x89\x5d\xfc", emit.lowered(), "mov qword ptr [rbp - 4], r11");
2269 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), .r12b, emit.code());2262 try lowerToMrEnc(.add, RegisterOrMemory.mem(.byte_ptr, .{ .disp = 0x10000000 }), Register.reg(.r12b), emit.code());
2270 try expectEqualHexStrings(2263 try expectEqualHexStrings(
2271 "\x44\x00\x24\x25\x00\x00\x00\x10",2264 "\x44\x00\x24\x25\x00\x00\x00\x10",
2272 emit.lowered(),2265 emit.lowered(),
2273 "add byte ptr [ds:0x10000000], r12b",2266 "add byte ptr [ds:0x10000000], r12b",
2274 );2267 );
2275 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), .r12d, emit.code());2268 try lowerToMrEnc(.add, RegisterOrMemory.mem(.dword_ptr, .{ .disp = 0x10000000 }), Register.reg(.r12d), emit.code());
2276 try expectEqualHexStrings(2269 try expectEqualHexStrings(
2277 "\x44\x01\x24\x25\x00\x00\x00\x10",2270 "\x44\x01\x24\x25\x00\x00\x00\x10",
2278 emit.lowered(),2271 emit.lowered(),
...@@ -2281,53 +2274,53 @@ test "lower MR encoding" {...@@ -2281,53 +2274,53 @@ test "lower MR encoding" {
2281 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{2274 try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{
2282 .disp = 0x10000000,2275 .disp = 0x10000000,
2283 .base = .r11,2276 .base = .r11,
2284 }), .r12, emit.code());2277 }), Register.reg(.r12), emit.code());
2285 try expectEqualHexStrings(2278 try expectEqualHexStrings(
2286 "\x4D\x29\xA3\x00\x00\x00\x10",2279 "\x4D\x29\xA3\x00\x00\x00\x10",
2287 emit.lowered(),2280 emit.lowered(),
2288 "sub qword ptr [r11 + 0x10000000], r12",2281 "sub qword ptr [r11 + 0x10000000], r12",
2289 );2282 );
2290 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), .r12, emit.code());2283 try lowerToMrEnc(.mov, RegisterOrMemory.rip(.qword_ptr, 0x10), Register.reg(.r12), emit.code());
2291 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12");2284 try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12");
2292}2285}
22932286
2294test "lower OI encoding" {2287test "lower OI encoding" {
2295 var emit = TestEmit.init();2288 var emit = TestEmit.init();
2296 defer emit.deinit();2289 defer emit.deinit();
2297 try lowerToOiEnc(.mov, .rax, 0x1000000000000000, emit.code());2290 try lowerToOiEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code());
2298 try expectEqualHexStrings(2291 try expectEqualHexStrings(
2299 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",2292 "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10",
2300 emit.lowered(),2293 emit.lowered(),
2301 "movabs rax, 0x1000000000000000",2294 "movabs rax, 0x1000000000000000",
2302 );2295 );
2303 try lowerToOiEnc(.mov, .r11, 0x1000000000000000, emit.code());2296 try lowerToOiEnc(.mov, Register.reg(.r11), 0x1000000000000000, emit.code());
2304 try expectEqualHexStrings(2297 try expectEqualHexStrings(
2305 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",2298 "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10",
2306 emit.lowered(),2299 emit.lowered(),
2307 "movabs r11, 0x1000000000000000",2300 "movabs r11, 0x1000000000000000",
2308 );2301 );
2309 try lowerToOiEnc(.mov, .r11d, 0x10000000, emit.code());2302 try lowerToOiEnc(.mov, Register.reg(.r11d), 0x10000000, emit.code());
2310 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", emit.lowered(), "mov r11d, 0x10000000");2303 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", emit.lowered(), "mov r11d, 0x10000000");
2311 try lowerToOiEnc(.mov, .r11w, 0x1000, emit.code());2304 try lowerToOiEnc(.mov, Register.reg(.r11w), 0x1000, emit.code());
2312 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", emit.lowered(), "mov r11w, 0x1000");2305 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", emit.lowered(), "mov r11w, 0x1000");
2313 try lowerToOiEnc(.mov, .r11b, 0x10, emit.code());2306 try lowerToOiEnc(.mov, Register.reg(.r11b), 0x10, emit.code());
2314 try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10");2307 try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10");
2315}2308}
23162309
2317test "lower FD/TD encoding" {2310test "lower FD/TD encoding" {
2318 var emit = TestEmit.init();2311 var emit = TestEmit.init();
2319 defer emit.deinit();2312 defer emit.deinit();
2320 try lowerToFdEnc(.mov, .rax, 0x1000000000000000, emit.code());2313 try lowerToFdEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code());
2321 try expectEqualHexStrings(2314 try expectEqualHexStrings(
2322 "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",2315 "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",
2323 emit.lowered(),2316 emit.lowered(),
2324 "mov rax, ds:0x1000000000000000",2317 "mov rax, ds:0x1000000000000000",
2325 );2318 );
2326 try lowerToFdEnc(.mov, .eax, 0x10000000, emit.code());2319 try lowerToFdEnc(.mov, Register.reg(.eax), 0x10000000, emit.code());
2327 try expectEqualHexStrings("\xa1\x00\x00\x00\x10", emit.lowered(), "mov eax, ds:0x10000000");2320 try expectEqualHexStrings("\xa1\x00\x00\x00\x10", emit.lowered(), "mov eax, ds:0x10000000");
2328 try lowerToFdEnc(.mov, .ax, 0x1000, emit.code());2321 try lowerToFdEnc(.mov, Register.reg(.ax), 0x1000, emit.code());
2329 try expectEqualHexStrings("\x66\xa1\x00\x10", emit.lowered(), "mov ax, ds:0x1000");2322 try expectEqualHexStrings("\x66\xa1\x00\x10", emit.lowered(), "mov ax, ds:0x1000");
2330 try lowerToFdEnc(.mov, .al, 0x10, emit.code());2323 try lowerToFdEnc(.mov, Register.reg(.al), 0x10, emit.code());
2331 try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10");2324 try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10");
2332}2325}
23332326
...@@ -2403,16 +2396,16 @@ test "lower M1 and MC encodings" {...@@ -2403,16 +2396,16 @@ test "lower M1 and MC encodings" {
2403test "lower O encoding" {2396test "lower O encoding" {
2404 var emit = TestEmit.init();2397 var emit = TestEmit.init();
2405 defer emit.deinit();2398 defer emit.deinit();
2406 try lowerToOEnc(.pop, .r12, emit.code());2399 try lowerToOEnc(.pop, Register.reg(.r12), emit.code());
2407 try expectEqualHexStrings("\x41\x5c", emit.lowered(), "pop r12");2400 try expectEqualHexStrings("\x41\x5c", emit.lowered(), "pop r12");
2408 try lowerToOEnc(.push, .r12w, emit.code());2401 try lowerToOEnc(.push, Register.reg(.r12w), emit.code());
2409 try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w");2402 try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w");
2410}2403}
24112404
2412test "lower RMI encoding" {2405test "lower RMI encoding" {
2413 var emit = TestEmit.init();2406 var emit = TestEmit.init();
2414 defer emit.deinit();2407 defer emit.deinit();
2415 try lowerToRmiEnc(.imul, .rax, RegisterOrMemory.mem(.qword_ptr, .{2408 try lowerToRmiEnc(.imul, Register.reg(.rax), RegisterOrMemory.mem(.qword_ptr, .{
2416 .disp = @bitCast(u32, @as(i32, -8)),2409 .disp = @bitCast(u32, @as(i32, -8)),
2417 .base = .rbp,2410 .base = .rbp,
2418 }), 0x10, emit.code());2411 }), 0x10, emit.code());
...@@ -2421,18 +2414,18 @@ test "lower RMI encoding" {...@@ -2421,18 +2414,18 @@ test "lower RMI encoding" {
2421 emit.lowered(),2414 emit.lowered(),
2422 "imul rax, qword ptr [rbp - 8], 0x10",2415 "imul rax, qword ptr [rbp - 8], 0x10",
2423 );2416 );
2424 try lowerToRmiEnc(.imul, .eax, RegisterOrMemory.mem(.dword_ptr, .{2417 try lowerToRmiEnc(.imul, Register.reg(.eax), RegisterOrMemory.mem(.dword_ptr, .{
2425 .disp = @bitCast(u32, @as(i32, -4)),2418 .disp = @bitCast(u32, @as(i32, -4)),
2426 .base = .rbp,2419 .base = .rbp,
2427 }), 0x10, emit.code());2420 }), 0x10, emit.code());
2428 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", emit.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");2421 try expectEqualHexStrings("\x69\x45\xFC\x10\x00\x00\x00", emit.lowered(), "imul eax, dword ptr [rbp - 4], 0x10");
2429 try lowerToRmiEnc(.imul, .ax, RegisterOrMemory.mem(.word_ptr, .{2422 try lowerToRmiEnc(.imul, Register.reg(.ax), RegisterOrMemory.mem(.word_ptr, .{
2430 .disp = @bitCast(u32, @as(i32, -2)),2423 .disp = @bitCast(u32, @as(i32, -2)),
2431 .base = .rbp,2424 .base = .rbp,
2432 }), 0x10, emit.code());2425 }), 0x10, emit.code());
2433 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", emit.lowered(), "imul ax, word ptr [rbp - 2], 0x10");2426 try expectEqualHexStrings("\x66\x69\x45\xFE\x10\x00", emit.lowered(), "imul ax, word ptr [rbp - 2], 0x10");
2434 try lowerToRmiEnc(.imul, .r12, RegisterOrMemory.reg(.r12), 0x10, emit.code());2427 try lowerToRmiEnc(.imul, Register.reg(.r12), RegisterOrMemory.reg(.r12), 0x10, emit.code());
2435 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", emit.lowered(), "imul r12, r12, 0x10");2428 try expectEqualHexStrings("\x4D\x69\xE4\x10\x00\x00\x00", emit.lowered(), "imul r12, r12, 0x10");
2436 try lowerToRmiEnc(.imul, .r12w, RegisterOrMemory.reg(.r12w), 0x10, emit.code());2429 try lowerToRmiEnc(.imul, Register.reg(.r12w), RegisterOrMemory.reg(.r12w), 0x10, emit.code());
2437 try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10");2430 try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10");
2438}2431}
src/arch/x86_64/bits.zig+117-89
...@@ -302,96 +302,113 @@ pub const Encoder = struct {...@@ -302,96 +302,113 @@ pub const Encoder = struct {
302 self.code.appendAssumeCapacity(0x66);302 self.code.appendAssumeCapacity(0x66);
303 }303 }
304304
305 pub fn Vex(comptime count: comptime_int) type {305 pub const Vex = struct {
306 if (count < 2 or count > 3) {306 rex_prefix: Rex = .{},
307 @compileError("VEX prefix can either be 2- or 3-byte long");307 lead_opc: u5 = 0b0_0001,
308 register: u4 = 0b1111,
309 length: u1 = 0b0,
310 simd_prefix: u2 = 0b00,
311 wig: bool = false,
312 lig: bool = false,
313 lz: bool = false,
314
315 pub fn rex(self: *Vex, r: Rex) void {
316 self.rex_prefix = r;
308 }317 }
309318
310 return struct {319 pub fn lead_opc_0f(self: *Vex) void {
311 bytes: [count]u8 = switch (count) {320 self.lead_opc = 0b0_0001;
312 2 => .{ 0xc5, 0xf8 },321 }
313 3 => .{ 0xc4, 0xe1, 0xf8 },
314 else => unreachable,
315 },
316
317 pub fn rex(self: *@This(), prefix: Rex) void {
318 const byte = &self.bytes[1];
319 if (prefix.w) switch (count) {
320 3 => self.bytes[2] &= 0b0111_1111,
321 else => unreachable,
322 };
323 if (prefix.r) byte.* &= 0b0111_1111;
324 if (prefix.x) switch (count) {
325 3 => byte.* &= 0b1011_1111,
326 else => unreachable,
327 };
328 if (prefix.b) switch (count) {
329 3 => byte.* &= 0b1101_1111,
330 else => unreachable,
331 };
332 }
333322
334 pub fn leading_opcode_0f(self: *@This()) void {323 pub fn lead_opc_0f_38(self: *Vex) void {
335 switch (count) {324 self.lead_opc = 0b0_0010;
336 3 => self.bytes[1] |= 0b0_0001,325 }
337 else => {},
338 }
339 }
340326
341 pub fn leading_opcode_0f_38(self: *@This()) void {327 pub fn lead_opc_0f_3a(self: *Vex) void {
342 switch (count) {328 self.lead_opc = 0b0_0011;
343 3 => self.bytes[1] |= 0b0_0010,329 }
344 else => unreachable,
345 }
346 }
347330
348 pub fn leading_opcode_0f_3a(self: *@This()) void {331 pub fn reg(self: *Vex, register: u4) void {
349 switch (count) {332 self.register = ~register;
350 3 => self.bytes[1] |= 0b0_0011,333 }
351 else => unreachable,
352 }
353 }
354334
355 pub fn reg(self: *@This(), register: u4) void {335 pub fn len_128(self: *Vex) void {
356 const byte = &self.bytes[count - 1];336 self.length = 0;
357 const mask = 0b1_0000_111;337 }
358 byte.* &= mask;
359 byte.* |= @intCast(u7, ~register) << 3;
360 }
361338
362 pub fn len_128(self: *@This()) void {339 pub fn len_256(self: *Vex) void {
363 const byte = &self.bytes[count - 1];340 assert(!self.lz);
364 byte.* &= 0b0_11;341 self.length = 1;
365 }342 }
366343
367 pub fn len_256(self: *@This()) void {344 pub fn simd_prefix_66(self: *Vex) void {
368 const byte = &self.bytes[count - 1];345 self.simd_prefix = 0b01;
369 byte.* |= 0b1_00;346 }
370 }
371347
372 pub fn simd_prefix_66(self: *@This()) void {348 pub fn simd_prefix_f3(self: *Vex) void {
373 const byte = &self.bytes[count - 1];349 self.simd_prefix = 0b10;
374 byte.* |= 0b01;350 }
375 }
376351
377 pub fn simd_prefix_f2(self: *@This()) void {352 pub fn simd_prefix_f2(self: *Vex) void {
378 const byte = &self.bytes[count - 1];353 self.simd_prefix = 0b11;
379 byte.* |= 0b11;354 }
355
356 pub fn wig(self: *Vex) void {
357 self.wig = true;
358 }
359
360 pub fn lig(self: *Vex) void {
361 self.lig = true;
362 }
363
364 pub fn lz(self: *Vex) void {
365 self.lz = true;
366 }
367
368 pub fn write(self: Vex, writer: anytype) usize {
369 var buf: [3]u8 = .{0} ** 3;
370 const form_3byte: bool = blk: {
371 if (self.rex_prefix.w and !self.wig) break :blk true;
372 if (self.rex_prefix.x or self.rex_prefix.b) break :blk true;
373 break :blk self.lead_opc != 0b0_0001;
374 };
375
376 if (self.lz) {
377 assert(self.length == 0);
380 }378 }
381379
382 pub fn simd_prefix_f3(self: *@This()) void {380 if (form_3byte) {
383 const byte = &self.bytes[count - 1];381 // First byte
384 byte.* |= 0b10;382 buf[0] = 0xc4;
383 // Second byte
384 const rxb_mask: u3 = @intCast(u3, @boolToInt(!self.rex_prefix.r)) << 2 |
385 @intCast(u2, @boolToInt(!self.rex_prefix.x)) << 1 |
386 @boolToInt(!self.rex_prefix.b);
387 buf[1] |= @intCast(u8, rxb_mask) << 5;
388 buf[1] |= self.lead_opc;
389 // Third byte
390 buf[2] |= @intCast(u8, @boolToInt(!self.rex_prefix.w)) << 7;
391 buf[2] |= @intCast(u7, self.register) << 3;
392 buf[2] |= @intCast(u3, self.length) << 2;
393 buf[2] |= self.simd_prefix;
394 } else {
395 // First byte
396 buf[0] = 0xc5;
397 // Second byte
398 buf[1] |= @intCast(u8, @boolToInt(!self.rex_prefix.r)) << 7;
399 buf[1] |= @intCast(u7, self.register) << 3;
400 buf[1] |= @intCast(u3, self.length) << 2;
401 buf[1] |= self.simd_prefix;
385 }402 }
386 };
387 }
388403
389 pub fn vex_2byte(self: Self, prefix: Vex(2)) void {404 const count: usize = if (form_3byte) 3 else 2;
390 self.code.appendSliceAssumeCapacity(&prefix.bytes);405 _ = writer.writeAll(buf[0..count]) catch unreachable;
391 }406 return count;
407 }
408 };
392409
393 pub fn vex_3byte(self: Self, prefix: Vex(3)) void {410 pub fn vex(self: Self, prefix: Vex) void {
394 self.code.appendSliceAssumeCapacity(&prefix.bytes);411 _ = prefix.write(self.code.writer());
395 }412 }
396413
397 /// From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB414 /// From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB
...@@ -759,39 +776,50 @@ test "Encoder helpers - general purpose registers" {...@@ -759,39 +776,50 @@ test "Encoder helpers - general purpose registers" {
759}776}
760777
761test "Encoder helpers - Vex prefix" {778test "Encoder helpers - Vex prefix" {
779 var buf: [3]u8 = undefined;
780 var stream = std.io.fixedBufferStream(&buf);
781 const writer = stream.writer();
782
762 {783 {
763 var vex_prefix = Encoder.Vex(2){};784 var vex_prefix = Encoder.Vex{};
764 vex_prefix.rex(.{785 vex_prefix.rex(.{
765 .r = true,786 .r = true,
766 });787 });
767 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x78 }, &vex_prefix.bytes);788 const nwritten = vex_prefix.write(writer);
789 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x78 }, buf[0..nwritten]);
768 }790 }
769791
770 {792 {
771 var vex_prefix = Encoder.Vex(2){};793 stream.reset();
794 var vex_prefix = Encoder.Vex{};
772 vex_prefix.reg(AvxRegister.xmm15.id());795 vex_prefix.reg(AvxRegister.xmm15.id());
773 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x80 }, &vex_prefix.bytes);796 const nwritten = vex_prefix.write(writer);
797 try testing.expectEqualSlices(u8, &[_]u8{ 0xc5, 0x80 }, buf[0..nwritten]);
774 }798 }
775799
776 {800 {
777 var vex_prefix = Encoder.Vex(3){};801 stream.reset();
802 var vex_prefix = Encoder.Vex{};
778 vex_prefix.rex(.{803 vex_prefix.rex(.{
779 .w = true,804 .w = true,
780 .x = true,805 .x = true,
781 });806 });
782 try testing.expectEqualSlices(u8, &[_]u8{ 0xc4, 0b101_0_0001, 0b0_1111_0_00 }, &vex_prefix.bytes);807 const nwritten = vex_prefix.write(writer);
808 try testing.expectEqualSlices(u8, &[_]u8{ 0xc4, 0b101_0_0001, 0b0_1111_0_00 }, buf[0..nwritten]);
783 }809 }
784810
785 {811 {
786 var vex_prefix = Encoder.Vex(3){};812 stream.reset();
813 var vex_prefix = Encoder.Vex{};
787 vex_prefix.rex(.{814 vex_prefix.rex(.{
788 .w = true,815 .w = true,
789 .r = true,816 .r = true,
790 });817 });
791 vex_prefix.len_256();818 vex_prefix.len_256();
792 vex_prefix.leading_opcode_0f();819 vex_prefix.lead_opc_0f();
793 vex_prefix.simd_prefix_66();820 vex_prefix.simd_prefix_66();
794 try testing.expectEqualSlices(u8, &[_]u8{ 0xc4, 0b011_0_0001, 0b0_1111_1_01 }, &vex_prefix.bytes);821 const nwritten = vex_prefix.write(writer);
822 try testing.expectEqualSlices(u8, &[_]u8{ 0xc4, 0b011_0_0001, 0b0_1111_1_01 }, buf[0..nwritten]);
795 }823 }
796824
797 var code = ArrayList(u8).init(testing.allocator);825 var code = ArrayList(u8).init(testing.allocator);
...@@ -800,9 +828,9 @@ test "Encoder helpers - Vex prefix" {...@@ -800,9 +828,9 @@ test "Encoder helpers - Vex prefix" {
800 {828 {
801 // vmovapd xmm1, xmm2829 // vmovapd xmm1, xmm2
802 const encoder = try Encoder.init(&code, 4);830 const encoder = try Encoder.init(&code, 4);
803 var vex = Encoder.Vex(2){};831 var vex = Encoder.Vex{};
804 vex.simd_prefix_66();832 vex.simd_prefix_66();
805 encoder.vex_2byte(vex); // use 64 bit operation833 encoder.vex(vex); // use 64 bit operation
806 encoder.opcode_1byte(0x28);834 encoder.opcode_1byte(0x28);
807 encoder.modRm_direct(0, AvxRegister.xmm1.lowId());835 encoder.modRm_direct(0, AvxRegister.xmm1.lowId());
808 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0xF9, 0x28, 0xC1 }, code.items);836 try testing.expectEqualSlices(u8, &[_]u8{ 0xC5, 0xF9, 0x28, 0xC1 }, code.items);
...@@ -813,13 +841,13 @@ test "Encoder helpers - Vex prefix" {...@@ -813,13 +841,13 @@ test "Encoder helpers - Vex prefix" {
813841
814 // vmovhpd xmm13, xmm1, qword ptr [rip]842 // vmovhpd xmm13, xmm1, qword ptr [rip]
815 const encoder = try Encoder.init(&code, 9);843 const encoder = try Encoder.init(&code, 9);
816 var vex = Encoder.Vex(2){};844 var vex = Encoder.Vex{};
817 vex.len_128();845 vex.len_128();
818 vex.simd_prefix_66();846 vex.simd_prefix_66();
819 vex.leading_opcode_0f();847 vex.lead_opc_0f();
820 vex.rex(.{ .r = true });848 vex.rex(.{ .r = true });
821 vex.reg(AvxRegister.xmm1.id());849 vex.reg(AvxRegister.xmm1.id());
822 encoder.vex_2byte(vex);850 encoder.vex(vex);
823 encoder.opcode_1byte(0x16);851 encoder.opcode_1byte(0x16);
824 encoder.modRm_RIPDisp32(AvxRegister.xmm13.lowId());852 encoder.modRm_RIPDisp32(AvxRegister.xmm13.lowId());
825 encoder.disp32(0);853 encoder.disp32(0);