| ... | ... | @@ -193,8 +193,7 @@ fn mirNop(emit: *Emit) InnerError!void { |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | 195 | fn mirSyscall(emit: *Emit) InnerError!void { |
| 196 | | const encoder = try Encoder.init(emit.code, 2); |
| 197 | | encoder.opcode_2byte(0x0f, 0x05); |
| 196 | return lowerToZoEnc(.syscall, emit.code); |
| 198 | 197 | } |
| 199 | 198 | |
| 200 | 199 | fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| ... | ... | @@ -470,6 +469,7 @@ const Tag = enum { |
| 470 | 469 | @"test", |
| 471 | 470 | brk, |
| 472 | 471 | nop, |
| 472 | syscall, |
| 473 | 473 | ret_near, |
| 474 | 474 | ret_far, |
| 475 | 475 | }; |
| ... | ... | @@ -509,78 +509,104 @@ const Encoding = enum { |
| 509 | 509 | td, |
| 510 | 510 | }; |
| 511 | 511 | |
| 512 | | inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 { |
| 512 | const OpCode = union(enum) { |
| 513 | one_byte: u8, |
| 514 | two_byte: struct { _1: u8, _2: u8 }, |
| 515 | |
| 516 | fn oneByte(opc: u8) OpCode { |
| 517 | return .{ .one_byte = opc }; |
| 518 | } |
| 519 | |
| 520 | fn twoByte(opc1: u8, opc2: u8) OpCode { |
| 521 | return .{ .two_byte = .{ ._1 = opc1, ._2 = opc2 } }; |
| 522 | } |
| 523 | |
| 524 | fn encode(opc: OpCode, encoder: Encoder) void { |
| 525 | switch (opc) { |
| 526 | .one_byte => |v| encoder.opcode_1byte(v), |
| 527 | .two_byte => |v| encoder.opcode_2byte(v._1, v._2), |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | fn encodeWithReg(opc: OpCode, encoder: Encoder, reg: Register) void { |
| 532 | assert(opc == .one_byte); |
| 533 | encoder.opcode_withReg(opc.one_byte, reg.lowId()); |
| 534 | } |
| 535 | }; |
| 536 | |
| 537 | inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 513 | 538 | switch (enc) { |
| 514 | 539 | .zo => return switch (tag) { |
| 515 | | .ret_near => 0xc3, |
| 516 | | .ret_far => 0xcb, |
| 517 | | .brk => 0xcc, |
| 518 | | .nop => 0x90, |
| 540 | .ret_near => OpCode.oneByte(0xc3), |
| 541 | .ret_far => OpCode.oneByte(0xcb), |
| 542 | .brk => OpCode.oneByte(0xcc), |
| 543 | .nop => OpCode.oneByte(0x90), |
| 544 | .syscall => OpCode.twoByte(0x0f, 0x05), |
| 519 | 545 | else => null, |
| 520 | 546 | }, |
| 521 | 547 | .d => return switch (tag) { |
| 522 | | .jmp_near => 0xe9, |
| 523 | | .call_near => 0xe8, |
| 548 | .jmp_near => OpCode.oneByte(0xe9), |
| 549 | .call_near => OpCode.oneByte(0xe8), |
| 524 | 550 | else => null, |
| 525 | 551 | }, |
| 526 | 552 | .m => return switch (tag) { |
| 527 | | .jmp_near, .call_near, .push => 0xff, |
| 528 | | .pop => 0x8f, |
| 553 | .jmp_near, .call_near, .push => OpCode.oneByte(0xff), |
| 554 | .pop => OpCode.oneByte(0x8f), |
| 529 | 555 | else => null, |
| 530 | 556 | }, |
| 531 | 557 | .o => return switch (tag) { |
| 532 | | .push => 0x50, |
| 533 | | .pop => 0x58, |
| 558 | .push => OpCode.oneByte(0x50), |
| 559 | .pop => OpCode.oneByte(0x58), |
| 534 | 560 | else => null, |
| 535 | 561 | }, |
| 536 | 562 | .i => return switch (tag) { |
| 537 | | .push => 0x68, |
| 538 | | .@"test" => 0xa9, |
| 539 | | .ret_near => 0xc2, |
| 540 | | .ret_far => 0xca, |
| 563 | .push => OpCode.oneByte(if (is_one_byte) 0x6a else 0x68), |
| 564 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xa8 else 0xa9), |
| 565 | .ret_near => OpCode.oneByte(0xc2), |
| 566 | .ret_far => OpCode.oneByte(0xca), |
| 541 | 567 | else => null, |
| 542 | 568 | }, |
| 543 | 569 | .mi => return switch (tag) { |
| 544 | | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81, |
| 545 | | .mov => 0xc7, |
| 546 | | .@"test" => 0xf7, |
| 570 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => OpCode.oneByte(if (is_one_byte) 0x80 else 0x81), |
| 571 | .mov => OpCode.oneByte(if (is_one_byte) 0xc6 else 0xc7), |
| 572 | .@"test" => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), |
| 547 | 573 | else => null, |
| 548 | 574 | }, |
| 549 | 575 | .mr => return switch (tag) { |
| 550 | | .adc => 0x11, |
| 551 | | .add => 0x01, |
| 552 | | .sub => 0x29, |
| 553 | | .xor => 0x31, |
| 554 | | .@"and" => 0x21, |
| 555 | | .@"or" => 0x09, |
| 556 | | .sbb => 0x19, |
| 557 | | .cmp => 0x39, |
| 558 | | .mov => 0x89, |
| 576 | .adc => OpCode.oneByte(if (is_one_byte) 0x10 else 0x11), |
| 577 | .add => OpCode.oneByte(if (is_one_byte) 0x00 else 0x01), |
| 578 | .sub => OpCode.oneByte(if (is_one_byte) 0x28 else 0x29), |
| 579 | .xor => OpCode.oneByte(if (is_one_byte) 0x30 else 0x31), |
| 580 | .@"and" => OpCode.oneByte(if (is_one_byte) 0x20 else 0x21), |
| 581 | .@"or" => OpCode.oneByte(if (is_one_byte) 0x08 else 0x09), |
| 582 | .sbb => OpCode.oneByte(if (is_one_byte) 0x18 else 0x19), |
| 583 | .cmp => OpCode.oneByte(if (is_one_byte) 0x38 else 0x39), |
| 584 | .mov => OpCode.oneByte(if (is_one_byte) 0x88 else 0x89), |
| 559 | 585 | else => null, |
| 560 | 586 | }, |
| 561 | 587 | .rm => return switch (tag) { |
| 562 | | .adc => 0x13, |
| 563 | | .add => 0x03, |
| 564 | | .sub => 0x2b, |
| 565 | | .xor => 0x33, |
| 566 | | .@"and" => 0x23, |
| 567 | | .@"or" => 0x0b, |
| 568 | | .sbb => 0x1b, |
| 569 | | .cmp => 0x3b, |
| 570 | | .mov => 0x8b, |
| 571 | | .lea => 0x8d, |
| 588 | .adc => OpCode.oneByte(if (is_one_byte) 0x12 else 0x13), |
| 589 | .add => OpCode.oneByte(if (is_one_byte) 0x02 else 0x03), |
| 590 | .sub => OpCode.oneByte(if (is_one_byte) 0x2a else 0x2b), |
| 591 | .xor => OpCode.oneByte(if (is_one_byte) 0x32 else 0x33), |
| 592 | .@"and" => OpCode.oneByte(if (is_one_byte) 0x22 else 0x23), |
| 593 | .@"or" => OpCode.oneByte(if (is_one_byte) 0x0b else 0x0b), |
| 594 | .sbb => OpCode.oneByte(if (is_one_byte) 0x1a else 0x1b), |
| 595 | .cmp => OpCode.oneByte(if (is_one_byte) 0x3a else 0x3b), |
| 596 | .mov => OpCode.oneByte(if (is_one_byte) 0x8a else 0x8b), |
| 597 | .lea => OpCode.oneByte(if (is_one_byte) 0x8c else 0x8d), |
| 572 | 598 | else => null, |
| 573 | 599 | }, |
| 574 | 600 | .oi => return switch (tag) { |
| 575 | | .mov => 0xb8, |
| 601 | .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8), |
| 576 | 602 | else => null, |
| 577 | 603 | }, |
| 578 | 604 | .fd => return switch (tag) { |
| 579 | | .mov => 0xa1, |
| 605 | .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1), |
| 580 | 606 | else => null, |
| 581 | 607 | }, |
| 582 | 608 | .td => return switch (tag) { |
| 583 | | .mov => 0xa3, |
| 609 | .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3), |
| 584 | 610 | else => null, |
| 585 | 611 | }, |
| 586 | 612 | } |
| ... | ... | @@ -648,32 +674,25 @@ const RegisterOrMemory = union(enum) { |
| 648 | 674 | }; |
| 649 | 675 | |
| 650 | 676 | fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void { |
| 651 | | const opc = getOpCode(tag, .zo).?; |
| 677 | const opc = getOpCode(tag, .zo, false).?; |
| 652 | 678 | const encoder = try Encoder.init(code, 1); |
| 653 | | encoder.opcode_1byte(opc); |
| 679 | opc.encode(encoder); |
| 654 | 680 | } |
| 655 | 681 | |
| 656 | 682 | fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 657 | | var opc = getOpCode(tag, .i).?; |
| 658 | 683 | if (tag == .ret_far or tag == .ret_near) { |
| 659 | 684 | const encoder = try Encoder.init(code, 3); |
| 660 | | encoder.opcode_1byte(opc); |
| 685 | const opc = getOpCode(tag, .i, false).?; |
| 686 | opc.encode(encoder); |
| 661 | 687 | encoder.imm16(@intCast(i16, imm)); |
| 662 | 688 | return; |
| 663 | 689 | } |
| 664 | | if (immOpSize(imm) == 8) { |
| 665 | | // TODO I think getOpCode should track this |
| 666 | | switch (tag) { |
| 667 | | .push => opc += 2, |
| 668 | | .@"test" => opc -= 1, |
| 669 | | else => return error.EmitFail, |
| 670 | | } |
| 671 | | } |
| 690 | const opc = getOpCode(tag, .i, immOpSize(imm) == 8).?; |
| 672 | 691 | const encoder = try Encoder.init(code, 5); |
| 673 | 692 | if (immOpSize(imm) == 16) { |
| 674 | 693 | encoder.opcode_1byte(0x66); |
| 675 | 694 | } |
| 676 | | encoder.opcode_1byte(opc); |
| 695 | opc.encode(encoder); |
| 677 | 696 | if (immOpSize(imm) == 8) { |
| 678 | 697 | encoder.imm8(@intCast(i8, imm)); |
| 679 | 698 | } else if (immOpSize(imm) == 16) { |
| ... | ... | @@ -685,7 +704,7 @@ fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 685 | 704 | |
| 686 | 705 | fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void { |
| 687 | 706 | if (reg.size() != 16 and reg.size() != 64) return error.EmitFail; // TODO correct for push/pop, but is it universal? |
| 688 | | const opc = getOpCode(tag, .o).?; |
| 707 | const opc = getOpCode(tag, .o, false).?; |
| 689 | 708 | const encoder = try Encoder.init(code, 3); |
| 690 | 709 | if (reg.size() == 16) { |
| 691 | 710 | encoder.opcode_1byte(0x66); |
| ... | ... | @@ -694,18 +713,18 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi |
| 694 | 713 | .w = false, |
| 695 | 714 | .b = reg.isExtended(), |
| 696 | 715 | }); |
| 697 | | encoder.opcode_withReg(opc, reg.lowId()); |
| 716 | opc.encodeWithReg(encoder, reg); |
| 698 | 717 | } |
| 699 | 718 | |
| 700 | 719 | fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 701 | | const opc = getOpCode(tag, .d).?; |
| 720 | const opc = getOpCode(tag, .d, false).?; |
| 702 | 721 | const encoder = try Encoder.init(code, 5); |
| 703 | | encoder.opcode_1byte(opc); |
| 722 | opc.encode(encoder); |
| 704 | 723 | encoder.imm32(imm); |
| 705 | 724 | } |
| 706 | 725 | |
| 707 | 726 | fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) InnerError!void { |
| 708 | | const opc = getOpCode(tag, .m).?; |
| 727 | const opc = getOpCode(tag, .m, false).?; |
| 709 | 728 | const modrm_ext = getModRmExt(tag).?; |
| 710 | 729 | switch (reg_or_mem) { |
| 711 | 730 | .register => |reg| { |
| ... | ... | @@ -715,7 +734,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 715 | 734 | .w = false, |
| 716 | 735 | .b = reg.isExtended(), |
| 717 | 736 | }); |
| 718 | | encoder.opcode_1byte(opc); |
| 737 | opc.encode(encoder); |
| 719 | 738 | encoder.modRm_direct(modrm_ext, reg.lowId()); |
| 720 | 739 | }, |
| 721 | 740 | .memory => |mem_op| { |
| ... | ... | @@ -726,7 +745,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 726 | 745 | .w = false, |
| 727 | 746 | .b = reg.isExtended(), |
| 728 | 747 | }); |
| 729 | | encoder.opcode_1byte(opc); |
| 748 | opc.encode(encoder); |
| 730 | 749 | if (reg.lowId() == 4) { |
| 731 | 750 | if (mem_op.disp == 0) { |
| 732 | 751 | encoder.modRm_SIBDisp0(modrm_ext); |
| ... | ... | @@ -752,7 +771,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8)) |
| 752 | 771 | } |
| 753 | 772 | } |
| 754 | 773 | } else { |
| 755 | | encoder.opcode_1byte(opc); |
| 774 | opc.encode(encoder); |
| 756 | 775 | if (mem_op.rip) { |
| 757 | 776 | encoder.modRm_RIPDisp32(modrm_ext); |
| 758 | 777 | } else { |
| ... | ... | @@ -776,10 +795,10 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8)) I |
| 776 | 795 | fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), td: bool) InnerError!void { |
| 777 | 796 | if (reg.lowId() != Register.rax.lowId()) return error.EmitFail; |
| 778 | 797 | if (reg.size() != immOpSize(moffs)) return error.EmitFail; |
| 779 | | var opc = if (td) getOpCode(tag, .td).? else getOpCode(tag, .fd).?; |
| 780 | | if (reg.size() == 8) { |
| 781 | | opc -= 1; |
| 782 | | } |
| 798 | const opc = if (td) |
| 799 | getOpCode(tag, .td, reg.size() == 8).? |
| 800 | else |
| 801 | getOpCode(tag, .fd, reg.size() == 8).?; |
| 783 | 802 | const encoder = try Encoder.init(code, 10); |
| 784 | 803 | if (reg.size() == 16) { |
| 785 | 804 | encoder.opcode_1byte(0x66); |
| ... | ... | @@ -787,7 +806,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), |
| 787 | 806 | encoder.rex(.{ |
| 788 | 807 | .w = reg.size() == 64, |
| 789 | 808 | }); |
| 790 | | encoder.opcode_1byte(opc); |
| 809 | opc.encode(encoder); |
| 791 | 810 | switch (reg.size()) { |
| 792 | 811 | 8 => { |
| 793 | 812 | const moffs8 = try math.cast(i8, moffs); |
| ... | ... | @@ -809,11 +828,8 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), |
| 809 | 828 | } |
| 810 | 829 | |
| 811 | 830 | fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) InnerError!void { |
| 812 | | var opc = getOpCode(tag, .oi).?; |
| 813 | 831 | if (reg.size() != immOpSize(imm)) return error.EmitFail; |
| 814 | | if (reg.size() == 8) { |
| 815 | | opc -= 8; |
| 816 | | } |
| 832 | const opc = getOpCode(tag, .oi, reg.size() == 8).?; |
| 817 | 833 | const encoder = try Encoder.init(code, 10); |
| 818 | 834 | if (reg.size() == 16) { |
| 819 | 835 | encoder.opcode_1byte(0x66); |
| ... | ... | @@ -822,7 +838,7 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Inn |
| 822 | 838 | .w = reg.size() == 64, |
| 823 | 839 | .b = reg.isExtended(), |
| 824 | 840 | }); |
| 825 | | encoder.opcode_withReg(opc, reg.lowId()); |
| 841 | opc.encodeWithReg(encoder, reg); |
| 826 | 842 | switch (reg.size()) { |
| 827 | 843 | 8 => { |
| 828 | 844 | const imm8 = try math.cast(i8, imm); |
| ... | ... | @@ -844,13 +860,10 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Inn |
| 844 | 860 | } |
| 845 | 861 | |
| 846 | 862 | fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.ArrayList(u8)) InnerError!void { |
| 847 | | var opc = getOpCode(tag, .mi).?; |
| 848 | 863 | const modrm_ext = getModRmExt(tag).?; |
| 849 | 864 | switch (reg_or_mem) { |
| 850 | 865 | .register => |dst_reg| { |
| 851 | | if (dst_reg.size() == 8) { |
| 852 | | opc -= 1; |
| 853 | | } |
| 866 | const opc = getOpCode(tag, .mi, dst_reg.size() == 8).?; |
| 854 | 867 | const encoder = try Encoder.init(code, 7); |
| 855 | 868 | if (dst_reg.size() == 16) { |
| 856 | 869 | // 0x66 prefix switches to the non-default size; here we assume a switch from |
| ... | ... | @@ -862,7 +875,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr |
| 862 | 875 | .w = dst_reg.size() == 64, |
| 863 | 876 | .b = dst_reg.isExtended(), |
| 864 | 877 | }); |
| 865 | | encoder.opcode_1byte(opc); |
| 878 | opc.encode(encoder); |
| 866 | 879 | encoder.modRm_direct(modrm_ext, dst_reg.lowId()); |
| 867 | 880 | switch (dst_reg.size()) { |
| 868 | 881 | 8 => { |
| ... | ... | @@ -878,6 +891,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr |
| 878 | 891 | } |
| 879 | 892 | }, |
| 880 | 893 | .memory => |dst_mem| { |
| 894 | const opc = getOpCode(tag, .mi, false).?; |
| 881 | 895 | const encoder = try Encoder.init(code, 12); |
| 882 | 896 | if (dst_mem.reg) |dst_reg| { |
| 883 | 897 | // Register dst_reg can either be 64bit or 32bit in size. |
| ... | ... | @@ -891,7 +905,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr |
| 891 | 905 | .w = false, |
| 892 | 906 | .b = dst_reg.isExtended(), |
| 893 | 907 | }); |
| 894 | | encoder.opcode_1byte(opc); |
| 908 | opc.encode(encoder); |
| 895 | 909 | if (dst_reg.lowId() == 4) { |
| 896 | 910 | if (dst_mem.disp == 0) { |
| 897 | 911 | encoder.modRm_SIBDisp0(modrm_ext); |
| ... | ... | @@ -917,7 +931,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr |
| 917 | 931 | } |
| 918 | 932 | } |
| 919 | 933 | } else { |
| 920 | | encoder.opcode_1byte(opc); |
| 934 | opc.encode(encoder); |
| 921 | 935 | if (dst_mem.rip) { |
| 922 | 936 | encoder.modRm_RIPDisp32(modrm_ext); |
| 923 | 937 | } else { |
| ... | ... | @@ -937,10 +951,7 @@ fn lowerToRmEnc( |
| 937 | 951 | reg_or_mem: RegisterOrMemory, |
| 938 | 952 | code: *std.ArrayList(u8), |
| 939 | 953 | ) InnerError!void { |
| 940 | | var opc = getOpCode(tag, .rm).?; |
| 941 | | if (reg.size() == 8) { |
| 942 | | opc -= 1; |
| 943 | | } |
| 954 | const opc = getOpCode(tag, .rm, reg.size() == 8).?; |
| 944 | 955 | switch (reg_or_mem) { |
| 945 | 956 | .register => |src_reg| { |
| 946 | 957 | if (reg.size() != src_reg.size()) return error.EmitFail; |
| ... | ... | @@ -950,7 +961,7 @@ fn lowerToRmEnc( |
| 950 | 961 | .r = reg.isExtended(), |
| 951 | 962 | .b = src_reg.isExtended(), |
| 952 | 963 | }); |
| 953 | | encoder.opcode_1byte(opc); |
| 964 | opc.encode(encoder); |
| 954 | 965 | encoder.modRm_direct(reg.lowId(), src_reg.lowId()); |
| 955 | 966 | }, |
| 956 | 967 | .memory => |src_mem| { |
| ... | ... | @@ -967,7 +978,7 @@ fn lowerToRmEnc( |
| 967 | 978 | .r = reg.isExtended(), |
| 968 | 979 | .b = src_reg.isExtended(), |
| 969 | 980 | }); |
| 970 | | encoder.opcode_1byte(opc); |
| 981 | opc.encode(encoder); |
| 971 | 982 | if (src_reg.lowId() == 4) { |
| 972 | 983 | if (src_mem.disp == 0) { |
| 973 | 984 | encoder.modRm_SIBDisp0(reg.lowId()); |
| ... | ... | @@ -997,7 +1008,7 @@ fn lowerToRmEnc( |
| 997 | 1008 | .w = reg.size() == 64, |
| 998 | 1009 | .r = reg.isExtended(), |
| 999 | 1010 | }); |
| 1000 | | encoder.opcode_1byte(opc); |
| 1011 | opc.encode(encoder); |
| 1001 | 1012 | if (src_mem.rip) { |
| 1002 | 1013 | encoder.modRm_RIPDisp32(reg.lowId()); |
| 1003 | 1014 | } else { |
| ... | ... | @@ -1022,10 +1033,7 @@ fn lowerToMrEnc( |
| 1022 | 1033 | // * reg is 32bit - dword ptr |
| 1023 | 1034 | // * reg is 16bit - word ptr |
| 1024 | 1035 | // * reg is 8bit - byte ptr |
| 1025 | | var opc = getOpCode(tag, .mr).?; |
| 1026 | | if (reg.size() == 8) { |
| 1027 | | opc -= 1; |
| 1028 | | } |
| 1036 | const opc = getOpCode(tag, .mr, reg.size() == 8).?; |
| 1029 | 1037 | switch (reg_or_mem) { |
| 1030 | 1038 | .register => |dst_reg| { |
| 1031 | 1039 | if (dst_reg.size() != reg.size()) return error.EmitFail; |
| ... | ... | @@ -1035,7 +1043,7 @@ fn lowerToMrEnc( |
| 1035 | 1043 | .r = reg.isExtended(), |
| 1036 | 1044 | .b = dst_reg.isExtended(), |
| 1037 | 1045 | }); |
| 1038 | | encoder.opcode_1byte(opc); |
| 1046 | opc.encode(encoder); |
| 1039 | 1047 | encoder.modRm_direct(reg.lowId(), dst_reg.lowId()); |
| 1040 | 1048 | }, |
| 1041 | 1049 | .memory => |dst_mem| { |
| ... | ... | @@ -1050,7 +1058,7 @@ fn lowerToMrEnc( |
| 1050 | 1058 | .r = reg.isExtended(), |
| 1051 | 1059 | .b = dst_reg.isExtended(), |
| 1052 | 1060 | }); |
| 1053 | | encoder.opcode_1byte(opc); |
| 1061 | opc.encode(encoder); |
| 1054 | 1062 | if (dst_reg.lowId() == 4) { |
| 1055 | 1063 | if (dst_mem.disp == 0) { |
| 1056 | 1064 | encoder.modRm_SIBDisp0(reg.lowId()); |
| ... | ... | @@ -1080,7 +1088,7 @@ fn lowerToMrEnc( |
| 1080 | 1088 | .w = reg.size() == 64, |
| 1081 | 1089 | .r = reg.isExtended(), |
| 1082 | 1090 | }); |
| 1083 | | encoder.opcode_1byte(opc); |
| 1091 | opc.encode(encoder); |
| 1084 | 1092 | if (dst_mem.rip) { |
| 1085 | 1093 | encoder.modRm_RIPDisp32(reg.lowId()); |
| 1086 | 1094 | } else { |
| ... | ... | @@ -1168,10 +1176,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1168 | 1176 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1169 | 1177 | const scale = ops.flags; |
| 1170 | 1178 | // OP reg1, [reg2 + scale*rcx + imm32] |
| 1171 | | var opc = getOpCode(tag, .rm).?; |
| 1172 | | if (ops.reg1.size() == 8) { |
| 1173 | | opc -= 1; |
| 1174 | | } |
| 1179 | const opc = getOpCode(tag, .rm, ops.reg1.size() == 8).?; |
| 1175 | 1180 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 1176 | 1181 | const encoder = try Encoder.init(emit.code, 8); |
| 1177 | 1182 | encoder.rex(.{ |
| ... | ... | @@ -1179,7 +1184,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1179 | 1184 | .r = ops.reg1.isExtended(), |
| 1180 | 1185 | .b = ops.reg2.isExtended(), |
| 1181 | 1186 | }); |
| 1182 | | encoder.opcode_1byte(opc); |
| 1187 | opc.encode(encoder); |
| 1183 | 1188 | if (imm <= math.maxInt(i8)) { |
| 1184 | 1189 | encoder.modRm_SIBDisp8(ops.reg1.lowId()); |
| 1185 | 1190 | encoder.sib_scaleIndexBaseDisp8(scale, Register.rcx.lowId(), ops.reg2.lowId()); |
| ... | ... | @@ -1198,17 +1203,14 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1198 | 1203 | |
| 1199 | 1204 | if (ops.reg2 == .none) { |
| 1200 | 1205 | // OP [reg1 + scale*rax + 0], imm32 |
| 1201 | | var opc = getOpCode(tag, .mi).?; |
| 1206 | const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?; |
| 1202 | 1207 | const modrm_ext = getModRmExt(tag).?; |
| 1203 | | if (ops.reg1.size() == 8) { |
| 1204 | | opc -= 1; |
| 1205 | | } |
| 1206 | 1208 | const encoder = try Encoder.init(emit.code, 8); |
| 1207 | 1209 | encoder.rex(.{ |
| 1208 | 1210 | .w = ops.reg1.size() == 64, |
| 1209 | 1211 | .b = ops.reg1.isExtended(), |
| 1210 | 1212 | }); |
| 1211 | | encoder.opcode_1byte(opc); |
| 1213 | opc.encode(encoder); |
| 1212 | 1214 | encoder.modRm_SIBDisp0(modrm_ext); |
| 1213 | 1215 | encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId()); |
| 1214 | 1216 | if (imm <= math.maxInt(i8)) { |
| ... | ... | @@ -1222,17 +1224,14 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1222 | 1224 | } |
| 1223 | 1225 | |
| 1224 | 1226 | // OP [reg1 + scale*rax + imm32], reg2 |
| 1225 | | var opc = getOpCode(tag, .mr).?; |
| 1226 | | if (ops.reg1.size() == 8) { |
| 1227 | | opc -= 1; |
| 1228 | | } |
| 1227 | const opc = getOpCode(tag, .mr, ops.reg1.size() == 8).?; |
| 1229 | 1228 | const encoder = try Encoder.init(emit.code, 8); |
| 1230 | 1229 | encoder.rex(.{ |
| 1231 | 1230 | .w = ops.reg1.size() == 64, |
| 1232 | 1231 | .r = ops.reg2.isExtended(), |
| 1233 | 1232 | .b = ops.reg1.isExtended(), |
| 1234 | 1233 | }); |
| 1235 | | encoder.opcode_1byte(opc); |
| 1234 | opc.encode(encoder); |
| 1236 | 1235 | if (imm <= math.maxInt(i8)) { |
| 1237 | 1236 | encoder.modRm_SIBDisp8(ops.reg2.lowId()); |
| 1238 | 1237 | encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); |
| ... | ... | @@ -1249,17 +1248,14 @@ fn mirArithScaleImm(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void |
| 1249 | 1248 | const scale = ops.flags; |
| 1250 | 1249 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 1251 | 1250 | const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data; |
| 1252 | | var opc = getOpCode(tag, .mi).?; |
| 1253 | | if (ops.reg1.size() == 8) { |
| 1254 | | opc -= 1; |
| 1255 | | } |
| 1251 | const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?; |
| 1256 | 1252 | const modrm_ext = getModRmExt(tag).?; |
| 1257 | 1253 | const encoder = try Encoder.init(emit.code, 2); |
| 1258 | 1254 | encoder.rex(.{ |
| 1259 | 1255 | .w = ops.reg1.size() == 64, |
| 1260 | 1256 | .b = ops.reg1.isExtended(), |
| 1261 | 1257 | }); |
| 1262 | | encoder.opcode_1byte(opc); |
| 1258 | opc.encode(encoder); |
| 1263 | 1259 | if (imm_pair.dest_off <= math.maxInt(i8)) { |
| 1264 | 1260 | encoder.modRm_SIBDisp8(modrm_ext); |
| 1265 | 1261 | encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); |