| ... | @@ -541,61 +541,64 @@ const Encoding = enum { | ... | @@ -541,61 +541,64 @@ const Encoding = enum { |
| 541 | | 541 | |
| 542 | /// OP r64, r/m64 | 542 | /// OP r64, r/m64 |
| 543 | rm, | 543 | rm, |
| 544 | }; | | |
| 545 | | 544 | |
| 546 | const OpCode = struct { | 545 | /// OP r64, imm64 |
| 547 | opc: u8, | 546 | oi, |
| 548 | /// Only used if `Encoding == .mi`. | | |
| 549 | modrm_ext: u3, | | |
| 550 | }; | 547 | }; |
| 551 | | 548 | |
| 552 | inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) OpCode { | 549 | inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 { |
| 553 | switch (enc) { | 550 | switch (enc) { |
| 554 | .mi => return switch (tag) { | 551 | .mi => return switch (tag) { |
| 555 | .adc => .{ .opc = 0x81, .modrm_ext = 0x2 }, | 552 | .adc, .add, .sub, .xor, .@"and", .@"or", .sbb, .cmp => 0x81, |
| 556 | .add => .{ .opc = 0x81, .modrm_ext = 0x0 }, | 553 | .mov => 0xc7, |
| 557 | .sub => .{ .opc = 0x81, .modrm_ext = 0x5 }, | | |
| 558 | .xor => .{ .opc = 0x81, .modrm_ext = 0x6 }, | | |
| 559 | .@"and" => .{ .opc = 0x81, .modrm_ext = 0x4 }, | | |
| 560 | .@"or" => .{ .opc = 0x81, .modrm_ext = 0x1 }, | | |
| 561 | .sbb => .{ .opc = 0x81, .modrm_ext = 0x3 }, | | |
| 562 | .cmp => .{ .opc = 0x81, .modrm_ext = 0x7 }, | | |
| 563 | .mov => .{ .opc = 0xc7, .modrm_ext = 0x0 }, | | |
| 564 | else => unreachable, | 554 | else => unreachable, |
| 565 | }, | 555 | }, |
| 566 | .mr => { | 556 | .mr => return switch (tag) { |
| 567 | const opc: u8 = switch (tag) { | 557 | .adc => 0x11, |
| 568 | .adc => 0x11, | 558 | .add => 0x01, |
| 569 | .add => 0x01, | 559 | .sub => 0x29, |
| 570 | .sub => 0x29, | 560 | .xor => 0x31, |
| 571 | .xor => 0x31, | 561 | .@"and" => 0x21, |
| 572 | .@"and" => 0x21, | 562 | .@"or" => 0x09, |
| 573 | .@"or" => 0x09, | 563 | .sbb => 0x19, |
| 574 | .sbb => 0x19, | 564 | .cmp => 0x39, |
| 575 | .cmp => 0x39, | 565 | .mov => 0x89, |
| 576 | .mov => 0x89, | 566 | else => unreachable, |
| 577 | else => unreachable, | | |
| 578 | }; | | |
| 579 | return .{ .opc = opc, .modrm_ext = undefined }; | | |
| 580 | }, | 567 | }, |
| 581 | .rm => { | 568 | .rm => return switch (tag) { |
| 582 | const opc: u8 = switch (tag) { | 569 | .adc => 0x13, |
| 583 | .adc => 0x13, | 570 | .add => 0x03, |
| 584 | .add => 0x03, | 571 | .sub => 0x2b, |
| 585 | .sub => 0x2b, | 572 | .xor => 0x33, |
| 586 | .xor => 0x33, | 573 | .@"and" => 0x23, |
| 587 | .@"and" => 0x23, | 574 | .@"or" => 0x0b, |
| 588 | .@"or" => 0x0b, | 575 | .sbb => 0x1b, |
| 589 | .sbb => 0x1b, | 576 | .cmp => 0x3b, |
| 590 | .cmp => 0x3b, | 577 | .mov => 0x8b, |
| 591 | .mov => 0x8b, | 578 | else => unreachable, |
| 592 | else => unreachable, | 579 | }, |
| 593 | }; | 580 | .oi => return switch (tag) { |
| 594 | return .{ .opc = opc, .modrm_ext = undefined }; | 581 | .mov => 0xb8, |
| | 582 | else => unreachable, |
| 595 | }, | 583 | }, |
| 596 | } | 584 | } |
| 597 | } | 585 | } |
| 598 | | 586 | |
| | 587 | inline fn getMiModRmExt(tag: Mir.Inst.Tag) u3 { |
| | 588 | return switch (tag) { |
| | 589 | .adc => 0x2, |
| | 590 | .add => 0x0, |
| | 591 | .sub => 0x5, |
| | 592 | .xor => 0x6, |
| | 593 | .@"and" => 0x4, |
| | 594 | .@"or" => 0x1, |
| | 595 | .sbb => 0x3, |
| | 596 | .cmp => 0x7, |
| | 597 | .mov => 0x0, |
| | 598 | else => unreachable, |
| | 599 | }; |
| | 600 | } |
| | 601 | |
| 599 | const ScaleIndexBase = struct { | 602 | const ScaleIndexBase = struct { |
| 600 | scale: u2, | 603 | scale: u2, |
| 601 | index_reg: ?Register, | 604 | index_reg: ?Register, |
| ... | @@ -626,16 +629,56 @@ const RegisterOrMemory = union(enum) { | ... | @@ -626,16 +629,56 @@ const RegisterOrMemory = union(enum) { |
| 626 | } | 629 | } |
| 627 | }; | 630 | }; |
| 628 | | 631 | |
| | 632 | fn lowerToOiEnc( |
| | 633 | tag: Mir.Inst.Tag, |
| | 634 | reg: Register, |
| | 635 | imm: i64, |
| | 636 | code: *std.ArrayList(u8), |
| | 637 | ) InnerError!void { |
| | 638 | var opc = getOpCode(tag, .oi); |
| | 639 | if (reg.size() != immOpSize(imm)) return error.EmitFail; |
| | 640 | if (reg.size() == 8) { |
| | 641 | opc -= 8; |
| | 642 | } |
| | 643 | const encoder = try Encoder.init(code, 10); |
| | 644 | encoder.rex(.{ |
| | 645 | .w = reg.size() == 64, |
| | 646 | .b = reg.isExtended(), |
| | 647 | }); |
| | 648 | encoder.opcode_withReg(opc, reg.lowId()); |
| | 649 | switch (reg.size()) { |
| | 650 | 8 => { |
| | 651 | const imm8 = try math.cast(i8, imm); |
| | 652 | encoder.imm8(imm8); |
| | 653 | }, |
| | 654 | 16 => { |
| | 655 | const imm16 = try math.cast(i16, imm); |
| | 656 | encoder.imm16(imm16); |
| | 657 | }, |
| | 658 | 32 => { |
| | 659 | const imm32 = try math.cast(i32, imm); |
| | 660 | encoder.imm32(imm32); |
| | 661 | }, |
| | 662 | 64 => { |
| | 663 | encoder.imm64(@bitCast(u64, imm)); |
| | 664 | }, |
| | 665 | else => unreachable, |
| | 666 | } |
| | 667 | } |
| | 668 | |
| 629 | fn lowerToMiEnc( | 669 | fn lowerToMiEnc( |
| 630 | tag: Mir.Inst.Tag, | 670 | tag: Mir.Inst.Tag, |
| 631 | reg_or_mem: RegisterOrMemory, | 671 | reg_or_mem: RegisterOrMemory, |
| 632 | imm: i32, | 672 | imm: i32, |
| 633 | code: *std.ArrayList(u8), | 673 | code: *std.ArrayList(u8), |
| 634 | ) InnerError!void { | 674 | ) InnerError!void { |
| 635 | const opcode = getOpCode(tag, .mi); | 675 | var opc = getOpCode(tag, .mi); |
| | 676 | const modrm_ext = getMiModRmExt(tag); |
| 636 | switch (reg_or_mem) { | 677 | switch (reg_or_mem) { |
| 637 | .register => |dst_reg| { | 678 | .register => |dst_reg| { |
| 638 | const opc: u8 = if (dst_reg.size() == 8) opcode.opc - 1 else opcode.opc; | 679 | if (dst_reg.size() == 8) { |
| | 680 | opc -= 1; |
| | 681 | } |
| 639 | const encoder = try Encoder.init(code, 7); | 682 | const encoder = try Encoder.init(code, 7); |
| 640 | if (dst_reg.size() == 16) { | 683 | if (dst_reg.size() == 16) { |
| 641 | // 0x66 prefix switches to the non-default size; here we assume a switch from | 684 | // 0x66 prefix switches to the non-default size; here we assume a switch from |
| ... | @@ -648,7 +691,7 @@ fn lowerToMiEnc( | ... | @@ -648,7 +691,7 @@ fn lowerToMiEnc( |
| 648 | .b = dst_reg.isExtended(), | 691 | .b = dst_reg.isExtended(), |
| 649 | }); | 692 | }); |
| 650 | encoder.opcode_1byte(opc); | 693 | encoder.opcode_1byte(opc); |
| 651 | encoder.modRm_direct(opcode.modrm_ext, dst_reg.lowId()); | 694 | encoder.modRm_direct(modrm_ext, dst_reg.lowId()); |
| 652 | switch (dst_reg.size()) { | 695 | switch (dst_reg.size()) { |
| 653 | 8 => { | 696 | 8 => { |
| 654 | const imm8 = try math.cast(i8, imm); | 697 | const imm8 = try math.cast(i8, imm); |
| ... | @@ -676,25 +719,25 @@ fn lowerToMiEnc( | ... | @@ -676,25 +719,25 @@ fn lowerToMiEnc( |
| 676 | .w = false, | 719 | .w = false, |
| 677 | .b = dst_reg.isExtended(), | 720 | .b = dst_reg.isExtended(), |
| 678 | }); | 721 | }); |
| 679 | encoder.opcode_1byte(opcode.opc); | 722 | encoder.opcode_1byte(opc); |
| 680 | if (dst_mem.disp == 0) { | 723 | if (dst_mem.disp == 0) { |
| 681 | encoder.modRm_indirectDisp0(opcode.modrm_ext, dst_reg.lowId()); | 724 | encoder.modRm_indirectDisp0(modrm_ext, dst_reg.lowId()); |
| 682 | } else if (immOpSize(dst_mem.disp) == 8) { | 725 | } else if (immOpSize(dst_mem.disp) == 8) { |
| 683 | encoder.modRm_indirectDisp8(opcode.modrm_ext, dst_reg.lowId()); | 726 | encoder.modRm_indirectDisp8(modrm_ext, dst_reg.lowId()); |
| 684 | encoder.disp8(@intCast(i8, dst_mem.disp)); | 727 | encoder.disp8(@intCast(i8, dst_mem.disp)); |
| 685 | } else { | 728 | } else { |
| 686 | if (dst_reg.lowId() == 4) { | 729 | if (dst_reg.lowId() == 4) { |
| 687 | encoder.modRm_SIBDisp32(opcode.modrm_ext); | 730 | encoder.modRm_SIBDisp32(modrm_ext); |
| 688 | encoder.sib_baseDisp32(dst_reg.lowId()); | 731 | encoder.sib_baseDisp32(dst_reg.lowId()); |
| 689 | encoder.disp32(dst_mem.disp); | 732 | encoder.disp32(dst_mem.disp); |
| 690 | } else { | 733 | } else { |
| 691 | encoder.modRm_indirectDisp32(opcode.modrm_ext, dst_reg.lowId()); | 734 | encoder.modRm_indirectDisp32(modrm_ext, dst_reg.lowId()); |
| 692 | encoder.disp32(dst_mem.disp); | 735 | encoder.disp32(dst_mem.disp); |
| 693 | } | 736 | } |
| 694 | } | 737 | } |
| 695 | } else { | 738 | } else { |
| 696 | encoder.opcode_1byte(opcode.opc); | 739 | encoder.opcode_1byte(opc); |
| 697 | encoder.modRm_SIBDisp0(opcode.modrm_ext); | 740 | encoder.modRm_SIBDisp0(modrm_ext); |
| 698 | encoder.sib_disp32(); | 741 | encoder.sib_disp32(); |
| 699 | encoder.disp32(dst_mem.disp); | 742 | encoder.disp32(dst_mem.disp); |
| 700 | } | 743 | } |
| ... | @@ -709,8 +752,10 @@ fn lowerToRmEnc( | ... | @@ -709,8 +752,10 @@ fn lowerToRmEnc( |
| 709 | reg_or_mem: RegisterOrMemory, | 752 | reg_or_mem: RegisterOrMemory, |
| 710 | code: *std.ArrayList(u8), | 753 | code: *std.ArrayList(u8), |
| 711 | ) InnerError!void { | 754 | ) InnerError!void { |
| 712 | const opcode = getOpCode(tag, .rm); | 755 | var opc = getOpCode(tag, .rm); |
| 713 | const opc: u8 = if (reg.size() == 8) opcode.opc - 1 else opcode.opc; | 756 | if (reg.size() == 8) { |
| | 757 | opc -= 1; |
| | 758 | } |
| 714 | switch (reg_or_mem) { | 759 | switch (reg_or_mem) { |
| 715 | .register => |src_reg| { | 760 | .register => |src_reg| { |
| 716 | if (reg.size() != src_reg.size()) return error.EmitFail; | 761 | if (reg.size() != src_reg.size()) return error.EmitFail; |
| ... | @@ -779,8 +824,10 @@ fn lowerToMrEnc( | ... | @@ -779,8 +824,10 @@ fn lowerToMrEnc( |
| 779 | // * reg is 32bit - dword ptr | 824 | // * reg is 32bit - dword ptr |
| 780 | // * reg is 16bit - word ptr | 825 | // * reg is 16bit - word ptr |
| 781 | // * reg is 8bit - byte ptr | 826 | // * reg is 8bit - byte ptr |
| 782 | const opcode = getOpCode(tag, .mr); | 827 | var opc = getOpCode(tag, .mr); |
| 783 | const opc: u8 = if (reg.size() == 8) opcode.opc - 1 else opcode.opc; | 828 | if (reg.size() == 8) { |
| | 829 | opc -= 1; |
| | 830 | } |
| 784 | switch (reg_or_mem) { | 831 | switch (reg_or_mem) { |
| 785 | .register => |dst_reg| { | 832 | .register => |dst_reg| { |
| 786 | if (dst_reg.size() != reg.size()) return error.EmitFail; | 833 | if (dst_reg.size() != reg.size()) return error.EmitFail; |
| ... | @@ -890,7 +937,7 @@ fn mirArith(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!voi | ... | @@ -890,7 +937,7 @@ fn mirArith(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!voi |
| 890 | } | 937 | } |
| 891 | } | 938 | } |
| 892 | | 939 | |
| 893 | fn immOpSize(imm: i32) u8 { | 940 | fn immOpSize(imm: i64) u8 { |
| 894 | blk: { | 941 | blk: { |
| 895 | _ = math.cast(i8, imm) catch break :blk; | 942 | _ = math.cast(i8, imm) catch break :blk; |
| 896 | return 8; | 943 | return 8; |
| ... | @@ -899,15 +946,21 @@ fn immOpSize(imm: i32) u8 { | ... | @@ -899,15 +946,21 @@ fn immOpSize(imm: i32) u8 { |
| 899 | _ = math.cast(i16, imm) catch break :blk; | 946 | _ = math.cast(i16, imm) catch break :blk; |
| 900 | return 16; | 947 | return 16; |
| 901 | } | 948 | } |
| 902 | return 32; | 949 | blk: { |
| | 950 | _ = math.cast(i32, imm) catch break :blk; |
| | 951 | return 32; |
| | 952 | } |
| | 953 | return 64; |
| 903 | } | 954 | } |
| 904 | | 955 | |
| 905 | fn mirArithScaleSrc(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { | 956 | fn mirArithScaleSrc(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerError!void { |
| 906 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 957 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 907 | const scale = ops.flags; | 958 | const scale = ops.flags; |
| 908 | // OP reg1, [reg2 + scale*rcx + imm32] | 959 | // OP reg1, [reg2 + scale*rcx + imm32] |
| 909 | const opcode = getOpCode(tag, .rm); | 960 | var opc = getOpCode(tag, .rm); |
| 910 | const opc = if (ops.reg1.size() == 8) opcode.opc - 1 else opcode.opc; | 961 | if (ops.reg1.size() == 8) { |
| | 962 | opc -= 1; |
| | 963 | } |
| 911 | const imm = emit.mir.instructions.items(.data)[inst].imm; | 964 | const imm = emit.mir.instructions.items(.data)[inst].imm; |
| 912 | const encoder = try Encoder.init(emit.code, 8); | 965 | const encoder = try Encoder.init(emit.code, 8); |
| 913 | encoder.rex(.{ | 966 | encoder.rex(.{ |
| ... | @@ -934,15 +987,18 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE | ... | @@ -934,15 +987,18 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE |
| 934 | | 987 | |
| 935 | if (ops.reg2 == .none) { | 988 | if (ops.reg2 == .none) { |
| 936 | // OP [reg1 + scale*rax + 0], imm32 | 989 | // OP [reg1 + scale*rax + 0], imm32 |
| 937 | const opcode = getOpCode(tag, .mi); | 990 | var opc = getOpCode(tag, .mi); |
| 938 | const opc = if (ops.reg1.size() == 8) opcode.opc - 1 else opcode.opc; | 991 | const modrm_ext = getMiModRmExt(tag); |
| | 992 | if (ops.reg1.size() == 8) { |
| | 993 | opc -= 1; |
| | 994 | } |
| 939 | const encoder = try Encoder.init(emit.code, 8); | 995 | const encoder = try Encoder.init(emit.code, 8); |
| 940 | encoder.rex(.{ | 996 | encoder.rex(.{ |
| 941 | .w = ops.reg1.size() == 64, | 997 | .w = ops.reg1.size() == 64, |
| 942 | .b = ops.reg1.isExtended(), | 998 | .b = ops.reg1.isExtended(), |
| 943 | }); | 999 | }); |
| 944 | encoder.opcode_1byte(opc); | 1000 | encoder.opcode_1byte(opc); |
| 945 | encoder.modRm_SIBDisp0(opcode.modrm_ext); | 1001 | encoder.modRm_SIBDisp0(modrm_ext); |
| 946 | encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId()); | 1002 | encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId()); |
| 947 | if (imm <= math.maxInt(i8)) { | 1003 | if (imm <= math.maxInt(i8)) { |
| 948 | encoder.imm8(@intCast(i8, imm)); | 1004 | encoder.imm8(@intCast(i8, imm)); |
| ... | @@ -955,8 +1011,10 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE | ... | @@ -955,8 +1011,10 @@ fn mirArithScaleDst(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE |
| 955 | } | 1011 | } |
| 956 | | 1012 | |
| 957 | // OP [reg1 + scale*rax + imm32], reg2 | 1013 | // OP [reg1 + scale*rax + imm32], reg2 |
| 958 | const opcode = getOpCode(tag, .mr); | 1014 | var opc = getOpCode(tag, .mr); |
| 959 | const opc = if (ops.reg1.size() == 8) opcode.opc - 1 else opcode.opc; | 1015 | if (ops.reg1.size() == 8) { |
| | 1016 | opc -= 1; |
| | 1017 | } |
| 960 | const encoder = try Encoder.init(emit.code, 8); | 1018 | const encoder = try Encoder.init(emit.code, 8); |
| 961 | encoder.rex(.{ | 1019 | encoder.rex(.{ |
| 962 | .w = ops.reg1.size() == 64, | 1020 | .w = ops.reg1.size() == 64, |
| ... | @@ -980,8 +1038,11 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE | ... | @@ -980,8 +1038,11 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE |
| 980 | const scale = ops.flags; | 1038 | const scale = ops.flags; |
| 981 | const payload = emit.mir.instructions.items(.data)[inst].payload; | 1039 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| 982 | const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data; | 1040 | const imm_pair = emit.mir.extraData(Mir.ImmPair, payload).data; |
| 983 | const opcode = getOpCode(tag, .mi); | 1041 | var opc = getOpCode(tag, .mi); |
| 984 | const opc = if (ops.reg1.size() == 8) opcode.opc - 1 else opcode.opc; | 1042 | if (ops.reg1.size() == 8) { |
| | 1043 | opc -= 1; |
| | 1044 | } |
| | 1045 | const modrm_ext = getMiModRmExt(tag); |
| 985 | const encoder = try Encoder.init(emit.code, 2); | 1046 | const encoder = try Encoder.init(emit.code, 2); |
| 986 | encoder.rex(.{ | 1047 | encoder.rex(.{ |
| 987 | .w = ops.reg1.size() == 64, | 1048 | .w = ops.reg1.size() == 64, |
| ... | @@ -989,11 +1050,11 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE | ... | @@ -989,11 +1050,11 @@ fn mirArithScaleImm(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE |
| 989 | }); | 1050 | }); |
| 990 | encoder.opcode_1byte(opc); | 1051 | encoder.opcode_1byte(opc); |
| 991 | if (imm_pair.dest_off <= math.maxInt(i8)) { | 1052 | if (imm_pair.dest_off <= math.maxInt(i8)) { |
| 992 | encoder.modRm_SIBDisp8(opcode.modrm_ext); | 1053 | encoder.modRm_SIBDisp8(modrm_ext); |
| 993 | encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); | 1054 | encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId()); |
| 994 | encoder.disp8(@intCast(i8, imm_pair.dest_off)); | 1055 | encoder.disp8(@intCast(i8, imm_pair.dest_off)); |
| 995 | } else { | 1056 | } else { |
| 996 | encoder.modRm_SIBDisp32(opcode.modrm_ext); | 1057 | encoder.modRm_SIBDisp32(modrm_ext); |
| 997 | encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId()); | 1058 | encoder.sib_scaleIndexBaseDisp32(scale, Register.rax.lowId(), ops.reg1.lowId()); |
| 998 | encoder.disp32(imm_pair.dest_off); | 1059 | encoder.disp32(imm_pair.dest_off); |
| 999 | } | 1060 | } |
| ... | @@ -1005,21 +1066,19 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { | ... | @@ -1005,21 +1066,19 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 1005 | assert(tag == .movabs); | 1066 | assert(tag == .movabs); |
| 1006 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); | 1067 | const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); |
| 1007 | | 1068 | |
| | 1069 | if (ops.flags == 0b00) { |
| | 1070 | // movabs reg, imm64 |
| | 1071 | // OI |
| | 1072 | const imm: i64 = if (ops.reg1.size() == 64) blk: { |
| | 1073 | const payload = emit.mir.instructions.items(.data)[inst].payload; |
| | 1074 | const imm = emit.mir.extraData(Mir.Imm64, payload).data; |
| | 1075 | break :blk @bitCast(i64, imm.decode()); |
| | 1076 | } else emit.mir.instructions.items(.data)[inst].imm; |
| | 1077 | return lowerToOiEnc(.mov, ops.reg1, imm, emit.code); |
| | 1078 | } |
| | 1079 | |
| 1008 | const encoder = try Encoder.init(emit.code, 10); | 1080 | const encoder = try Encoder.init(emit.code, 10); |
| 1009 | const is_64 = blk: { | 1081 | const is_64 = blk: { |
| 1010 | if (ops.flags == 0b00) { | | |
| 1011 | // movabs reg, imm64 | | |
| 1012 | const opc: u8 = if (ops.reg1.size() == 8) 0xb0 else 0xb8; | | |
| 1013 | if (ops.reg1.size() == 64) { | | |
| 1014 | encoder.rex(.{ | | |
| 1015 | .w = true, | | |
| 1016 | .b = ops.reg1.isExtended(), | | |
| 1017 | }); | | |
| 1018 | encoder.opcode_withReg(opc, ops.reg1.lowId()); | | |
| 1019 | break :blk true; | | |
| 1020 | } | | |
| 1021 | break :blk false; | | |
| 1022 | } | | |
| 1023 | if (ops.reg1 == .none) { | 1082 | if (ops.reg1 == .none) { |
| 1024 | // movabs moffs64, rax | 1083 | // movabs moffs64, rax |
| 1025 | const opc: u8 = if (ops.reg2.size() == 8) 0xa2 else 0xa3; | 1084 | const opc: u8 = if (ops.reg2.size() == 8) 0xa2 else 0xa3; |
| ... | @@ -1486,3 +1545,24 @@ test "lower MR encoding" { | ... | @@ -1486,3 +1545,24 @@ test "lower MR encoding" { |
| 1486 | "sub qword ptr [r11 + 0x10000000], r12", | 1545 | "sub qword ptr [r11 + 0x10000000], r12", |
| 1487 | ); | 1546 | ); |
| 1488 | } | 1547 | } |
| | 1548 | |
| | 1549 | test "lower OI encoding" { |
| | 1550 | var code = TestEmitCode.init(); |
| | 1551 | defer code.deinit(); |
| | 1552 | try lowerToOiEnc(.mov, .rax, 0x1000000000000000, code.buffer()); |
| | 1553 | try expectEqualHexStrings( |
| | 1554 | "\x48\xB8\x00\x00\x00\x00\x00\x00\x00\x10", |
| | 1555 | code.emitted(), |
| | 1556 | "movabs rax, 0x1000000000000000", |
| | 1557 | ); |
| | 1558 | try lowerToOiEnc(.mov, .r11, 0x1000000000000000, code.buffer()); |
| | 1559 | try expectEqualHexStrings( |
| | 1560 | "\x49\xBB\x00\x00\x00\x00\x00\x00\x00\x10", |
| | 1561 | code.emitted(), |
| | 1562 | "movabs r11, 0x1000000000000000", |
| | 1563 | ); |
| | 1564 | try lowerToOiEnc(.mov, .r11d, 0x10000000, code.buffer()); |
| | 1565 | try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", code.emitted(), "mov r11d, 0x10000000"); |
| | 1566 | try lowerToOiEnc(.mov, .r11b, 0x10, code.buffer()); |
| | 1567 | try expectEqualHexStrings("\x41\xB3\x10", code.emitted(), "mov r11b, 0x10"); |
| | 1568 | } |