| ... | ... | @@ -249,7 +249,7 @@ fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 249 | 249 | switch (ops.flags) { |
| 250 | 250 | 0b00 => { |
| 251 | 251 | // 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 | 254 | 0b01 => { |
| 255 | 255 | // PUSH/POP r/m64 |
| ... | ... | @@ -285,9 +285,9 @@ fn mirPushPopRegsFromCalleePreservedRegs(emit: *Emit, tag: Tag, inst: Mir.Inst.I |
| 285 | 285 | try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ |
| 286 | 286 | .disp = @bitCast(u32, -@intCast(i32, disp)), |
| 287 | 287 | .base = ops.reg1, |
| 288 | | }), .{ .register = reg.to64() }, emit.code); |
| 288 | }), Register.reg(reg.to64()), emit.code); |
| 289 | 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 | 291 | .disp = @bitCast(u32, -@intCast(i32, disp)), |
| 292 | 292 | .base = ops.reg1, |
| 293 | 293 | }), emit.code); |
| ... | ... | @@ -321,7 +321,7 @@ fn mirJmpCall(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 321 | 321 | return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{ .disp = imm }), emit.code); |
| 322 | 322 | } |
| 323 | 323 | // 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 | 326 | 0b10 => { |
| 327 | 327 | // JMP/CALL r/m64 |
| ... | ... | @@ -394,13 +394,13 @@ fn mirCondSetByte(emit: *Emit, mir_tag: Mir.Inst.Tag, inst: Mir.Inst.Index) Inne |
| 394 | 394 | }, |
| 395 | 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 | } |
| 399 | 399 | |
| 400 | 400 | fn mirCondMov(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 401 | 401 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 402 | 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 | 405 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 406 | 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 | 409 | 0b10 => .dword_ptr, |
| 410 | 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 | 413 | .disp = imm, |
| 414 | 414 | .base = ops.reg2, |
| 415 | 415 | }), emit.code); |
| ... | ... | @@ -430,13 +430,13 @@ fn mirTest(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 430 | 430 | // I |
| 431 | 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 | 435 | // TEST r/m64, r64 |
| 436 | 436 | return lowerToMrEnc( |
| 437 | 437 | .@"test", |
| 438 | | RegisterOrMemory.reg(.{ .register = ops.reg1 }), |
| 439 | | .{ .register = ops.reg2 }, |
| 438 | RegisterOrMemory.reg(ops.reg1), |
| 439 | Register.reg(ops.reg2), |
| 440 | 440 | emit.code, |
| 441 | 441 | ); |
| 442 | 442 | }, |
| ... | ... | @@ -478,18 +478,18 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 478 | 478 | // mov reg1, imm32 |
| 479 | 479 | // MI |
| 480 | 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 | 483 | // mov reg1, reg2 |
| 484 | 484 | // 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 | 487 | 0b01 => { |
| 488 | 488 | // mov reg1, [reg2 + imm32] |
| 489 | 489 | // RM |
| 490 | 490 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 491 | 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 | 493 | .disp = imm, |
| 494 | 494 | .base = src_reg, |
| 495 | 495 | }), emit.code); |
| ... | ... | @@ -504,7 +504,7 @@ fn mirArith(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 504 | 504 | return lowerToMrEnc(tag, RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg2.size()), .{ |
| 505 | 505 | .disp = imm, |
| 506 | 506 | .base = ops.reg1, |
| 507 | | }), .{ .register = ops.reg2 }, emit.code); |
| 507 | }), Register.reg(ops.reg2), emit.code); |
| 508 | 508 | }, |
| 509 | 509 | 0b11 => { |
| 510 | 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 | 562 | .scale = scale, |
| 563 | 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 | 566 | .disp = imm, |
| 567 | 567 | .base = ops.reg2, |
| 568 | 568 | .scale_index = scale_index, |
| ... | ... | @@ -590,7 +590,7 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 590 | 590 | .disp = imm, |
| 591 | 591 | .base = ops.reg1, |
| 592 | 592 | .scale_index = scale_index, |
| 593 | | }), .{ .register = ops.reg2 }, emit.code); |
| 593 | }), Register.reg(ops.reg2), emit.code); |
| 594 | 594 | } |
| 595 | 595 | |
| 596 | 596 | fn 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 | 641 | switch (ops.flags) { |
| 642 | 642 | 0b00 => { |
| 643 | 643 | const tag: Tag = if (ops.reg2.size() == 32) .movsxd else .movsx; |
| 644 | | return lowerToRmEnc( |
| 645 | | tag, |
| 646 | | .{ .register = ops.reg1 }, |
| 647 | | RegisterOrMemory.reg(.{ .register = ops.reg2 }), |
| 648 | | emit.code, |
| 649 | | ); |
| 644 | return lowerToRmEnc(tag, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code); |
| 650 | 645 | }, |
| 651 | 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 | 648 | .disp = imm, |
| 654 | 649 | .base = ops.reg2, |
| 655 | 650 | }), emit.code); |
| 656 | 651 | }, |
| 657 | 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 | 654 | .disp = imm, |
| 660 | 655 | .base = ops.reg2, |
| 661 | 656 | }), emit.code); |
| 662 | 657 | }, |
| 663 | 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 | 660 | .disp = imm, |
| 666 | 661 | .base = ops.reg2, |
| 667 | 662 | }), emit.code); |
| ... | ... | @@ -676,21 +671,16 @@ fn mirMovZeroExtend(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 676 | 671 | const imm = if (ops.flags != 0b00) emit.mir.instructions.items(.data)[inst].imm else undefined; |
| 677 | 672 | switch (ops.flags) { |
| 678 | 673 | 0b00 => { |
| 679 | | return lowerToRmEnc( |
| 680 | | .movzx, |
| 681 | | .{ .register = ops.reg1 }, |
| 682 | | RegisterOrMemory.reg(.{ .register = ops.reg2 }), |
| 683 | | emit.code, |
| 684 | | ); |
| 674 | return lowerToRmEnc(.movzx, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code); |
| 685 | 675 | }, |
| 686 | 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 | 678 | .disp = imm, |
| 689 | 679 | .base = ops.reg2, |
| 690 | 680 | }), emit.code); |
| 691 | 681 | }, |
| 692 | 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 | 684 | .disp = imm, |
| 695 | 685 | .base = ops.reg2, |
| 696 | 686 | }), emit.code); |
| ... | ... | @@ -713,16 +703,16 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 713 | 703 | if (ops.flags == 0b00) { |
| 714 | 704 | // movabs reg, imm64 |
| 715 | 705 | // 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 | 708 | if (ops.reg1 == .none) { |
| 719 | 709 | // movabs moffs64, rax |
| 720 | 710 | // 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 | 713 | // movabs rax, moffs64 |
| 724 | 714 | // FD |
| 725 | | return lowerToFdEnc(.mov, .{ .register = ops.reg1 }, imm, emit.code); |
| 715 | return lowerToFdEnc(.mov, Register.reg(ops.reg1), imm, emit.code); |
| 726 | 716 | } |
| 727 | 717 | |
| 728 | 718 | fn 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 | 763 | 0b00 => { |
| 774 | 764 | // sal reg1, 1 |
| 775 | 765 | // 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 | 768 | 0b01 => { |
| 779 | 769 | // sal reg1, .cl |
| 780 | 770 | // 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 | 773 | 0b10 => { |
| 784 | 774 | // sal reg1, imm8 |
| 785 | 775 | // MI |
| 786 | 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 | 779 | 0b11 => { |
| 790 | 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 | 786 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 797 | 787 | if (ops.reg1 != .none) { |
| 798 | 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 | 791 | assert(ops.reg1 == .none); |
| 802 | 792 | assert(ops.reg2 != .none); |
| ... | ... | @@ -819,35 +809,24 @@ fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 819 | 809 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 820 | 810 | switch (ops.flags) { |
| 821 | 811 | 0b00 => { |
| 822 | | return lowerToRmEnc( |
| 823 | | .imul, |
| 824 | | .{ .register = ops.reg1 }, |
| 825 | | RegisterOrMemory.reg(.{ .register = ops.reg2 }), |
| 826 | | emit.code, |
| 827 | | ); |
| 812 | return lowerToRmEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), emit.code); |
| 828 | 813 | }, |
| 829 | 814 | 0b01 => { |
| 830 | 815 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 831 | 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 | 818 | .disp = imm, |
| 834 | 819 | .base = src_reg, |
| 835 | 820 | }), emit.code); |
| 836 | 821 | }, |
| 837 | 822 | 0b10 => { |
| 838 | 823 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 839 | | return lowerToRmiEnc( |
| 840 | | .imul, |
| 841 | | .{ .register = ops.reg1 }, |
| 842 | | RegisterOrMemory.reg(.{ .register = ops.reg2 }), |
| 843 | | imm, |
| 844 | | emit.code, |
| 845 | | ); |
| 824 | return lowerToRmiEnc(.imul, Register.reg(ops.reg1), RegisterOrMemory.reg(ops.reg2), imm, emit.code); |
| 846 | 825 | }, |
| 847 | 826 | 0b11 => { |
| 848 | 827 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 849 | 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 | 830 | .disp = imm_pair.dest_off, |
| 852 | 831 | .base = ops.reg2, |
| 853 | 832 | }), imm_pair.operand, emit.code); |
| ... | ... | @@ -878,7 +857,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 878 | 857 | const src_reg: ?GpRegister = if (ops.reg2 == .none) null else ops.reg2; |
| 879 | 858 | return lowerToRmEnc( |
| 880 | 859 | .lea, |
| 881 | | .{ .register = ops.reg1 }, |
| 860 | Register.reg(ops.reg1), |
| 882 | 861 | RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 883 | 862 | .disp = imm, |
| 884 | 863 | .base = src_reg, |
| ... | ... | @@ -892,7 +871,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 892 | 871 | const start_offset = emit.code.items.len; |
| 893 | 872 | try lowerToRmEnc( |
| 894 | 873 | .lea, |
| 895 | | .{ .register = ops.reg1 }, |
| 874 | Register.reg(ops.reg1), |
| 896 | 875 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), |
| 897 | 876 | emit.code, |
| 898 | 877 | ); |
| ... | ... | @@ -913,7 +892,7 @@ fn mirLea(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 913 | 892 | }; |
| 914 | 893 | return lowerToRmEnc( |
| 915 | 894 | .lea, |
| 916 | | .{ .register = ops.reg1 }, |
| 895 | Register.reg(ops.reg1), |
| 917 | 896 | RegisterOrMemory.mem(Memory.PtrSize.fromBits(ops.reg1.size()), .{ |
| 918 | 897 | .disp = imm, |
| 919 | 898 | .base = src_reg, |
| ... | ... | @@ -936,7 +915,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 936 | 915 | // RM |
| 937 | 916 | try lowerToRmEnc( |
| 938 | 917 | .lea, |
| 939 | | .{ .register = ops.reg1 }, |
| 918 | Register.reg(ops.reg1), |
| 940 | 919 | RegisterOrMemory.rip(Memory.PtrSize.fromBits(ops.reg1.size()), 0), |
| 941 | 920 | emit.code, |
| 942 | 921 | ); |
| ... | ... | @@ -1666,8 +1645,12 @@ const RegisterOrMemory = union(enum) { |
| 1666 | 1645 | register: Register, |
| 1667 | 1646 | memory: Memory, |
| 1668 | 1647 | |
| 1669 | | fn reg(register: Register) RegisterOrMemory { |
| 1670 | | return .{ .register = register }; |
| 1648 | fn reg(register: GpRegister) RegisterOrMemory { |
| 1649 | return .{ .register = Register.reg(register) }; |
| 1650 | } |
| 1651 | |
| 1652 | fn avxReg(register: AvxRegister) RegisterOrMemory { |
| 1653 | return .{ .register = Register.avxReg(register) }; |
| 1671 | 1654 | } |
| 1672 | 1655 | |
| 1673 | 1656 | fn mem(ptr_size: Memory.PtrSize, args: struct { |
| ... | ... | @@ -1976,22 +1959,32 @@ fn lowerToMrEnc( |
| 1976 | 1959 | encoder.modRm_direct(reg.lowId(), dst_reg.lowId()); |
| 1977 | 1960 | }, |
| 1978 | 1961 | .memory => |dst_mem| { |
| 1979 | | const encoder = try Encoder.init(code, 9); |
| 1980 | | if (reg.size() == 16) { |
| 1981 | | encoder.prefix16BitMode(); |
| 1982 | | } |
| 1983 | | if (dst_mem.base) |base| { |
| 1984 | | encoder.rex(.{ |
| 1985 | | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1986 | | .r = reg.isExtended(), |
| 1987 | | .b = base.isExtended(), |
| 1988 | | }); |
| 1989 | | } else { |
| 1990 | | encoder.rex(.{ |
| 1991 | | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1992 | | .r = reg.isExtended(), |
| 1993 | | }); |
| 1994 | | } |
| 1962 | const encoder = blk: { |
| 1963 | switch (reg) { |
| 1964 | .register => { |
| 1965 | const encoder = try Encoder.init(code, 9); |
| 1966 | if (reg.size() == 16) { |
| 1967 | encoder.prefix16BitMode(); |
| 1968 | } |
| 1969 | if (dst_mem.base) |base| { |
| 1970 | encoder.rex(.{ |
| 1971 | .w = dst_mem.ptr_size == .qword_ptr or setRexWRegister(reg), |
| 1972 | .r = reg.isExtended(), |
| 1973 | .b = base.isExtended(), |
| 1974 | }); |
| 1975 | } else { |
| 1976 | encoder.rex(.{ |
| 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 | 1988 | opc.encode(encoder); |
| 1996 | 1989 | dst_mem.encode(encoder, reg.lowId()); |
| 1997 | 1990 | }, |
| ... | ... | @@ -2168,23 +2161,23 @@ test "lower MI encoding" { |
| 2168 | 2161 | test "lower RM encoding" { |
| 2169 | 2162 | var emit = TestEmit.init(); |
| 2170 | 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 | 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 | 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 | 2169 | try expectEqualHexStrings( |
| 2177 | 2170 | "\x4C\x03\x1C\x25\x00\x00\x00\x10", |
| 2178 | 2171 | emit.lowered(), |
| 2179 | 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 | 2175 | try expectEqualHexStrings( |
| 2183 | 2176 | "\x44\x02\x24\x25\x00\x00\x00\x10", |
| 2184 | 2177 | emit.lowered(), |
| 2185 | 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 | 2181 | .disp = 0x10000000, |
| 2189 | 2182 | .base = .r13, |
| 2190 | 2183 | }), emit.code()); |
| ... | ... | @@ -2193,7 +2186,7 @@ test "lower RM encoding" { |
| 2193 | 2186 | emit.lowered(), |
| 2194 | 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 | 2190 | .disp = 0x10000000, |
| 2198 | 2191 | .base = .r12, |
| 2199 | 2192 | }), emit.code()); |
| ... | ... | @@ -2202,14 +2195,14 @@ test "lower RM encoding" { |
| 2202 | 2195 | emit.lowered(), |
| 2203 | 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 | 2199 | .disp = @bitCast(u32, @as(i32, -4)), |
| 2207 | 2200 | .base = .rbp, |
| 2208 | 2201 | }), emit.code()); |
| 2209 | 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 | 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 | 2206 | .disp = @bitCast(u32, @as(i32, -8)), |
| 2214 | 2207 | .base = .rbp, |
| 2215 | 2208 | .scale_index = .{ |
| ... | ... | @@ -2218,7 +2211,7 @@ test "lower RM encoding" { |
| 2218 | 2211 | }, |
| 2219 | 2212 | }), emit.code()); |
| 2220 | 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 | 2215 | .disp = @bitCast(u32, @as(i32, -4)), |
| 2223 | 2216 | .base = .rbp, |
| 2224 | 2217 | .scale_index = .{ |
| ... | ... | @@ -2227,7 +2220,7 @@ test "lower RM encoding" { |
| 2227 | 2220 | }, |
| 2228 | 2221 | }), emit.code()); |
| 2229 | 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 | 2224 | .disp = @bitCast(u32, @as(i32, -8)), |
| 2232 | 2225 | .base = .rbp, |
| 2233 | 2226 | .scale_index = .{ |
| ... | ... | @@ -2236,7 +2229,7 @@ test "lower RM encoding" { |
| 2236 | 2229 | }, |
| 2237 | 2230 | }), emit.code()); |
| 2238 | 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 | 2233 | .disp = @bitCast(u32, @as(i32, -24)), |
| 2241 | 2234 | .base = .rsi, |
| 2242 | 2235 | .scale_index = .{ |
| ... | ... | @@ -2245,7 +2238,7 @@ test "lower RM encoding" { |
| 2245 | 2238 | }, |
| 2246 | 2239 | }), emit.code()); |
| 2247 | 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 | 2242 | .disp = 0, |
| 2250 | 2243 | .base = .rbp, |
| 2251 | 2244 | .scale_index = .{ |
| ... | ... | @@ -2259,20 +2252,20 @@ test "lower RM encoding" { |
| 2259 | 2252 | test "lower MR encoding" { |
| 2260 | 2253 | var emit = TestEmit.init(); |
| 2261 | 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 | 2256 | try expectEqualHexStrings("\x48\x89\xd8", emit.lowered(), "mov rax, rbx"); |
| 2264 | 2257 | try lowerToMrEnc(.mov, RegisterOrMemory.mem(.qword_ptr, .{ |
| 2265 | 2258 | .disp = @bitCast(u32, @as(i32, -4)), |
| 2266 | 2259 | .base = .rbp, |
| 2267 | | }), .r11, emit.code()); |
| 2260 | }), Register.reg(.r11), emit.code()); |
| 2268 | 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 | 2263 | try expectEqualHexStrings( |
| 2271 | 2264 | "\x44\x00\x24\x25\x00\x00\x00\x10", |
| 2272 | 2265 | emit.lowered(), |
| 2273 | 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 | 2269 | try expectEqualHexStrings( |
| 2277 | 2270 | "\x44\x01\x24\x25\x00\x00\x00\x10", |
| 2278 | 2271 | emit.lowered(), |
| ... | ... | @@ -2281,53 +2274,53 @@ test "lower MR encoding" { |
| 2281 | 2274 | try lowerToMrEnc(.sub, RegisterOrMemory.mem(.qword_ptr, .{ |
| 2282 | 2275 | .disp = 0x10000000, |
| 2283 | 2276 | .base = .r11, |
| 2284 | | }), .r12, emit.code()); |
| 2277 | }), Register.reg(.r12), emit.code()); |
| 2285 | 2278 | try expectEqualHexStrings( |
| 2286 | 2279 | "\x4D\x29\xA3\x00\x00\x00\x10", |
| 2287 | 2280 | emit.lowered(), |
| 2288 | 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 | 2284 | try expectEqualHexStrings("\x4C\x89\x25\x10\x00\x00\x00", emit.lowered(), "mov qword ptr [rip + 0x10], r12"); |
| 2292 | 2285 | } |
| 2293 | 2286 | |
| 2294 | 2287 | test "lower OI encoding" { |
| 2295 | 2288 | var emit = TestEmit.init(); |
| 2296 | 2289 | defer emit.deinit(); |
| 2297 | | try lowerToOiEnc(.mov, .rax, 0x1000000000000000, emit.code()); |
| 2290 | try lowerToOiEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code()); |
| 2298 | 2291 | try expectEqualHexStrings( |
| 2299 | 2292 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", |
| 2300 | 2293 | emit.lowered(), |
| 2301 | 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 | 2297 | try expectEqualHexStrings( |
| 2305 | 2298 | "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", |
| 2306 | 2299 | emit.lowered(), |
| 2307 | 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 | 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 | 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 | 2307 | try expectEqualHexStrings("\x41\xB3\x10", emit.lowered(), "mov r11b, 0x10"); |
| 2315 | 2308 | } |
| 2316 | 2309 | |
| 2317 | 2310 | test "lower FD/TD encoding" { |
| 2318 | 2311 | var emit = TestEmit.init(); |
| 2319 | 2312 | defer emit.deinit(); |
| 2320 | | try lowerToFdEnc(.mov, .rax, 0x1000000000000000, emit.code()); |
| 2313 | try lowerToFdEnc(.mov, Register.reg(.rax), 0x1000000000000000, emit.code()); |
| 2321 | 2314 | try expectEqualHexStrings( |
| 2322 | 2315 | "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10", |
| 2323 | 2316 | emit.lowered(), |
| 2324 | 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 | 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 | 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 | 2324 | try expectEqualHexStrings("\xa0\x10", emit.lowered(), "mov al, ds:0x10"); |
| 2332 | 2325 | } |
| 2333 | 2326 | |
| ... | ... | @@ -2403,16 +2396,16 @@ test "lower M1 and MC encodings" { |
| 2403 | 2396 | test "lower O encoding" { |
| 2404 | 2397 | var emit = TestEmit.init(); |
| 2405 | 2398 | defer emit.deinit(); |
| 2406 | | try lowerToOEnc(.pop, .r12, emit.code()); |
| 2399 | try lowerToOEnc(.pop, Register.reg(.r12), emit.code()); |
| 2407 | 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 | 2402 | try expectEqualHexStrings("\x66\x41\x54", emit.lowered(), "push r12w"); |
| 2410 | 2403 | } |
| 2411 | 2404 | |
| 2412 | 2405 | test "lower RMI encoding" { |
| 2413 | 2406 | var emit = TestEmit.init(); |
| 2414 | 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 | 2409 | .disp = @bitCast(u32, @as(i32, -8)), |
| 2417 | 2410 | .base = .rbp, |
| 2418 | 2411 | }), 0x10, emit.code()); |
| ... | ... | @@ -2421,18 +2414,18 @@ test "lower RMI encoding" { |
| 2421 | 2414 | emit.lowered(), |
| 2422 | 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 | 2418 | .disp = @bitCast(u32, @as(i32, -4)), |
| 2426 | 2419 | .base = .rbp, |
| 2427 | 2420 | }), 0x10, emit.code()); |
| 2428 | 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 | 2423 | .disp = @bitCast(u32, @as(i32, -2)), |
| 2431 | 2424 | .base = .rbp, |
| 2432 | 2425 | }), 0x10, emit.code()); |
| 2433 | 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 | 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 | 2430 | try expectEqualHexStrings("\x66\x45\x69\xE4\x10\x00", emit.lowered(), "imul r12w, r12w, 0x10"); |
| 2438 | 2431 | } |