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