authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 18:49:03+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-23 18:49:40+01:00
log8c664d3f6a59e412f33bca8c969f70ceb3545b11
treec8254a24e006ce4a2a3926547f47ebf0d37a7cbf
parentd23a1487bd397ce86108ae2727b67a1d0614f7a9

stage2: support multibyte opcodes and refactor 1byte opcode changes


1 files changed, 110 insertions(+), 114 deletions(-)

src/arch/x86_64/Emit.zig+110-114
......@@ -193,8 +193,7 @@ fn mirNop(emit: *Emit) InnerError!void {
193193}
194194
195195fn 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);
198197}
199198
200199fn mirPushPop(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
......@@ -470,6 +469,7 @@ const Tag = enum {
470469 @"test",
471470 brk,
472471 nop,
472 syscall,
473473 ret_near,
474474 ret_far,
475475};
......@@ -509,78 +509,104 @@ const Encoding = enum {
509509 td,
510510};
511511
512inline fn getOpCode(tag: Tag, enc: Encoding) ?u8 {
512const 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
537inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
513538 switch (enc) {
514539 .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),
519545 else => null,
520546 },
521547 .d => return switch (tag) {
522 .jmp_near => 0xe9,
523 .call_near => 0xe8,
548 .jmp_near => OpCode.oneByte(0xe9),
549 .call_near => OpCode.oneByte(0xe8),
524550 else => null,
525551 },
526552 .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),
529555 else => null,
530556 },
531557 .o => return switch (tag) {
532 .push => 0x50,
533 .pop => 0x58,
558 .push => OpCode.oneByte(0x50),
559 .pop => OpCode.oneByte(0x58),
534560 else => null,
535561 },
536562 .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),
541567 else => null,
542568 },
543569 .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),
547573 else => null,
548574 },
549575 .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),
559585 else => null,
560586 },
561587 .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),
572598 else => null,
573599 },
574600 .oi => return switch (tag) {
575 .mov => 0xb8,
601 .mov => OpCode.oneByte(if (is_one_byte) 0xb0 else 0xb8),
576602 else => null,
577603 },
578604 .fd => return switch (tag) {
579 .mov => 0xa1,
605 .mov => OpCode.oneByte(if (is_one_byte) 0xa0 else 0xa1),
580606 else => null,
581607 },
582608 .td => return switch (tag) {
583 .mov => 0xa3,
609 .mov => OpCode.oneByte(if (is_one_byte) 0xa2 else 0xa3),
584610 else => null,
585611 },
586612 }
......@@ -648,32 +674,25 @@ const RegisterOrMemory = union(enum) {
648674};
649675
650676fn lowerToZoEnc(tag: Tag, code: *std.ArrayList(u8)) InnerError!void {
651 const opc = getOpCode(tag, .zo).?;
677 const opc = getOpCode(tag, .zo, false).?;
652678 const encoder = try Encoder.init(code, 1);
653 encoder.opcode_1byte(opc);
679 opc.encode(encoder);
654680}
655681
656682fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
657 var opc = getOpCode(tag, .i).?;
658683 if (tag == .ret_far or tag == .ret_near) {
659684 const encoder = try Encoder.init(code, 3);
660 encoder.opcode_1byte(opc);
685 const opc = getOpCode(tag, .i, false).?;
686 opc.encode(encoder);
661687 encoder.imm16(@intCast(i16, imm));
662688 return;
663689 }
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).?;
672691 const encoder = try Encoder.init(code, 5);
673692 if (immOpSize(imm) == 16) {
674693 encoder.opcode_1byte(0x66);
675694 }
676 encoder.opcode_1byte(opc);
695 opc.encode(encoder);
677696 if (immOpSize(imm) == 8) {
678697 encoder.imm8(@intCast(i8, imm));
679698 } else if (immOpSize(imm) == 16) {
......@@ -685,7 +704,7 @@ fn lowerToIEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
685704
686705fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!void {
687706 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).?;
689708 const encoder = try Encoder.init(code, 3);
690709 if (reg.size() == 16) {
691710 encoder.opcode_1byte(0x66);
......@@ -694,18 +713,18 @@ fn lowerToOEnc(tag: Tag, reg: Register, code: *std.ArrayList(u8)) InnerError!voi
694713 .w = false,
695714 .b = reg.isExtended(),
696715 });
697 encoder.opcode_withReg(opc, reg.lowId());
716 opc.encodeWithReg(encoder, reg);
698717}
699718
700719fn lowerToDEnc(tag: Tag, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
701 const opc = getOpCode(tag, .d).?;
720 const opc = getOpCode(tag, .d, false).?;
702721 const encoder = try Encoder.init(code, 5);
703 encoder.opcode_1byte(opc);
722 opc.encode(encoder);
704723 encoder.imm32(imm);
705724}
706725
707726fn 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).?;
709728 const modrm_ext = getModRmExt(tag).?;
710729 switch (reg_or_mem) {
711730 .register => |reg| {
......@@ -715,7 +734,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
715734 .w = false,
716735 .b = reg.isExtended(),
717736 });
718 encoder.opcode_1byte(opc);
737 opc.encode(encoder);
719738 encoder.modRm_direct(modrm_ext, reg.lowId());
720739 },
721740 .memory => |mem_op| {
......@@ -726,7 +745,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
726745 .w = false,
727746 .b = reg.isExtended(),
728747 });
729 encoder.opcode_1byte(opc);
748 opc.encode(encoder);
730749 if (reg.lowId() == 4) {
731750 if (mem_op.disp == 0) {
732751 encoder.modRm_SIBDisp0(modrm_ext);
......@@ -752,7 +771,7 @@ fn lowerToMEnc(tag: Tag, reg_or_mem: RegisterOrMemory, code: *std.ArrayList(u8))
752771 }
753772 }
754773 } else {
755 encoder.opcode_1byte(opc);
774 opc.encode(encoder);
756775 if (mem_op.rip) {
757776 encoder.modRm_RIPDisp32(modrm_ext);
758777 } else {
......@@ -776,10 +795,10 @@ fn lowerToFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8)) I
776795fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8), td: bool) InnerError!void {
777796 if (reg.lowId() != Register.rax.lowId()) return error.EmitFail;
778797 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).?;
783802 const encoder = try Encoder.init(code, 10);
784803 if (reg.size() == 16) {
785804 encoder.opcode_1byte(0x66);
......@@ -787,7 +806,7 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
787806 encoder.rex(.{
788807 .w = reg.size() == 64,
789808 });
790 encoder.opcode_1byte(opc);
809 opc.encode(encoder);
791810 switch (reg.size()) {
792811 8 => {
793812 const moffs8 = try math.cast(i8, moffs);
......@@ -809,11 +828,8 @@ fn lowerToTdFdEnc(tag: Tag, reg: Register, moffs: i64, code: *std.ArrayList(u8),
809828}
810829
811830fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) InnerError!void {
812 var opc = getOpCode(tag, .oi).?;
813831 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).?;
817833 const encoder = try Encoder.init(code, 10);
818834 if (reg.size() == 16) {
819835 encoder.opcode_1byte(0x66);
......@@ -822,7 +838,7 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Inn
822838 .w = reg.size() == 64,
823839 .b = reg.isExtended(),
824840 });
825 encoder.opcode_withReg(opc, reg.lowId());
841 opc.encodeWithReg(encoder, reg);
826842 switch (reg.size()) {
827843 8 => {
828844 const imm8 = try math.cast(i8, imm);
......@@ -844,13 +860,10 @@ fn lowerToOiEnc(tag: Tag, reg: Register, imm: i64, code: *std.ArrayList(u8)) Inn
844860}
845861
846862fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.ArrayList(u8)) InnerError!void {
847 var opc = getOpCode(tag, .mi).?;
848863 const modrm_ext = getModRmExt(tag).?;
849864 switch (reg_or_mem) {
850865 .register => |dst_reg| {
851 if (dst_reg.size() == 8) {
852 opc -= 1;
853 }
866 const opc = getOpCode(tag, .mi, dst_reg.size() == 8).?;
854867 const encoder = try Encoder.init(code, 7);
855868 if (dst_reg.size() == 16) {
856869 // 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
862875 .w = dst_reg.size() == 64,
863876 .b = dst_reg.isExtended(),
864877 });
865 encoder.opcode_1byte(opc);
878 opc.encode(encoder);
866879 encoder.modRm_direct(modrm_ext, dst_reg.lowId());
867880 switch (dst_reg.size()) {
868881 8 => {
......@@ -878,6 +891,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
878891 }
879892 },
880893 .memory => |dst_mem| {
894 const opc = getOpCode(tag, .mi, false).?;
881895 const encoder = try Encoder.init(code, 12);
882896 if (dst_mem.reg) |dst_reg| {
883897 // 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
891905 .w = false,
892906 .b = dst_reg.isExtended(),
893907 });
894 encoder.opcode_1byte(opc);
908 opc.encode(encoder);
895909 if (dst_reg.lowId() == 4) {
896910 if (dst_mem.disp == 0) {
897911 encoder.modRm_SIBDisp0(modrm_ext);
......@@ -917,7 +931,7 @@ fn lowerToMiEnc(tag: Tag, reg_or_mem: RegisterOrMemory, imm: i32, code: *std.Arr
917931 }
918932 }
919933 } else {
920 encoder.opcode_1byte(opc);
934 opc.encode(encoder);
921935 if (dst_mem.rip) {
922936 encoder.modRm_RIPDisp32(modrm_ext);
923937 } else {
......@@ -937,10 +951,7 @@ fn lowerToRmEnc(
937951 reg_or_mem: RegisterOrMemory,
938952 code: *std.ArrayList(u8),
939953) 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).?;
944955 switch (reg_or_mem) {
945956 .register => |src_reg| {
946957 if (reg.size() != src_reg.size()) return error.EmitFail;
......@@ -950,7 +961,7 @@ fn lowerToRmEnc(
950961 .r = reg.isExtended(),
951962 .b = src_reg.isExtended(),
952963 });
953 encoder.opcode_1byte(opc);
964 opc.encode(encoder);
954965 encoder.modRm_direct(reg.lowId(), src_reg.lowId());
955966 },
956967 .memory => |src_mem| {
......@@ -967,7 +978,7 @@ fn lowerToRmEnc(
967978 .r = reg.isExtended(),
968979 .b = src_reg.isExtended(),
969980 });
970 encoder.opcode_1byte(opc);
981 opc.encode(encoder);
971982 if (src_reg.lowId() == 4) {
972983 if (src_mem.disp == 0) {
973984 encoder.modRm_SIBDisp0(reg.lowId());
......@@ -997,7 +1008,7 @@ fn lowerToRmEnc(
9971008 .w = reg.size() == 64,
9981009 .r = reg.isExtended(),
9991010 });
1000 encoder.opcode_1byte(opc);
1011 opc.encode(encoder);
10011012 if (src_mem.rip) {
10021013 encoder.modRm_RIPDisp32(reg.lowId());
10031014 } else {
......@@ -1022,10 +1033,7 @@ fn lowerToMrEnc(
10221033 // * reg is 32bit - dword ptr
10231034 // * reg is 16bit - word ptr
10241035 // * 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).?;
10291037 switch (reg_or_mem) {
10301038 .register => |dst_reg| {
10311039 if (dst_reg.size() != reg.size()) return error.EmitFail;
......@@ -1035,7 +1043,7 @@ fn lowerToMrEnc(
10351043 .r = reg.isExtended(),
10361044 .b = dst_reg.isExtended(),
10371045 });
1038 encoder.opcode_1byte(opc);
1046 opc.encode(encoder);
10391047 encoder.modRm_direct(reg.lowId(), dst_reg.lowId());
10401048 },
10411049 .memory => |dst_mem| {
......@@ -1050,7 +1058,7 @@ fn lowerToMrEnc(
10501058 .r = reg.isExtended(),
10511059 .b = dst_reg.isExtended(),
10521060 });
1053 encoder.opcode_1byte(opc);
1061 opc.encode(encoder);
10541062 if (dst_reg.lowId() == 4) {
10551063 if (dst_mem.disp == 0) {
10561064 encoder.modRm_SIBDisp0(reg.lowId());
......@@ -1080,7 +1088,7 @@ fn lowerToMrEnc(
10801088 .w = reg.size() == 64,
10811089 .r = reg.isExtended(),
10821090 });
1083 encoder.opcode_1byte(opc);
1091 opc.encode(encoder);
10841092 if (dst_mem.rip) {
10851093 encoder.modRm_RIPDisp32(reg.lowId());
10861094 } else {
......@@ -1168,10 +1176,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
11681176 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
11691177 const scale = ops.flags;
11701178 // 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).?;
11751180 const imm = emit.mir.instructions.items(.data)[inst].imm;
11761181 const encoder = try Encoder.init(emit.code, 8);
11771182 encoder.rex(.{
......@@ -1179,7 +1184,7 @@ fn mirArithScaleSrc(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
11791184 .r = ops.reg1.isExtended(),
11801185 .b = ops.reg2.isExtended(),
11811186 });
1182 encoder.opcode_1byte(opc);
1187 opc.encode(encoder);
11831188 if (imm <= math.maxInt(i8)) {
11841189 encoder.modRm_SIBDisp8(ops.reg1.lowId());
11851190 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
11981203
11991204 if (ops.reg2 == .none) {
12001205 // OP [reg1 + scale*rax + 0], imm32
1201 var opc = getOpCode(tag, .mi).?;
1206 const opc = getOpCode(tag, .mi, ops.reg1.size() == 8).?;
12021207 const modrm_ext = getModRmExt(tag).?;
1203 if (ops.reg1.size() == 8) {
1204 opc -= 1;
1205 }
12061208 const encoder = try Encoder.init(emit.code, 8);
12071209 encoder.rex(.{
12081210 .w = ops.reg1.size() == 64,
12091211 .b = ops.reg1.isExtended(),
12101212 });
1211 encoder.opcode_1byte(opc);
1213 opc.encode(encoder);
12121214 encoder.modRm_SIBDisp0(modrm_ext);
12131215 encoder.sib_scaleIndexBase(scale, Register.rax.lowId(), ops.reg1.lowId());
12141216 if (imm <= math.maxInt(i8)) {
......@@ -1222,17 +1224,14 @@ fn mirArithScaleDst(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void
12221224 }
12231225
12241226 // 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).?;
12291228 const encoder = try Encoder.init(emit.code, 8);
12301229 encoder.rex(.{
12311230 .w = ops.reg1.size() == 64,
12321231 .r = ops.reg2.isExtended(),
12331232 .b = ops.reg1.isExtended(),
12341233 });
1235 encoder.opcode_1byte(opc);
1234 opc.encode(encoder);
12361235 if (imm <= math.maxInt(i8)) {
12371236 encoder.modRm_SIBDisp8(ops.reg2.lowId());
12381237 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
12491248 const scale = ops.flags;
12501249 const payload = emit.mir.instructions.items(.data)[inst].payload;
12511250 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).?;
12561252 const modrm_ext = getModRmExt(tag).?;
12571253 const encoder = try Encoder.init(emit.code, 2);
12581254 encoder.rex(.{
12591255 .w = ops.reg1.size() == 64,
12601256 .b = ops.reg1.isExtended(),
12611257 });
1262 encoder.opcode_1byte(opc);
1258 opc.encode(encoder);
12631259 if (imm_pair.dest_off <= math.maxInt(i8)) {
12641260 encoder.modRm_SIBDisp8(modrm_ext);
12651261 encoder.sib_scaleIndexBaseDisp8(scale, Register.rax.lowId(), ops.reg1.lowId());