authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-22 22:36:56+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-12-22 22:36:56+01:00
logb40e5adf54de878c2745bcf6e266239b7f5c40b6
tree35dda51469f7bdd11b8c7bb1b4eb95b79bbf8eb4
parentb9a6f81d1ac0e04381b5872413f49ff54b872e04

stage2: add lowering for FD/TD encodings


1 files changed, 107 insertions(+), 40 deletions(-)

src/arch/x86_64/Emit.zig+107-40
...@@ -544,6 +544,12 @@ const Encoding = enum {...@@ -544,6 +544,12 @@ const Encoding = enum {
544544
545 /// OP r64, imm64545 /// OP r64, imm64
546 oi,546 oi,
547
548 /// OP al/ax/eax/rax, moffs
549 fd,
550
551 /// OP moffs, al/ax/eax/rax
552 td,
547};553};
548554
549inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {555inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
...@@ -581,6 +587,14 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {...@@ -581,6 +587,14 @@ inline fn getOpCode(tag: Mir.Inst.Tag, enc: Encoding) u8 {
581 .mov => 0xb8,587 .mov => 0xb8,
582 else => unreachable,588 else => unreachable,
583 },589 },
590 .fd => return switch (tag) {
591 .mov => 0xa1,
592 else => unreachable,
593 },
594 .td => return switch (tag) {
595 .mov => 0xa3,
596 else => unreachable,
597 },
584 }598 }
585}599}
586600
...@@ -629,6 +643,65 @@ const RegisterOrMemory = union(enum) {...@@ -629,6 +643,65 @@ const RegisterOrMemory = union(enum) {
629 }643 }
630};644};
631645
646fn lowerToTdEnc(
647 tag: Mir.Inst.Tag,
648 moffs: i64,
649 reg: Register,
650 code: *std.ArrayList(u8),
651) InnerError!void {
652 return lowerToTdFdEnc(tag, reg, moffs, code, true);
653}
654
655fn lowerToFdEnc(
656 tag: Mir.Inst.Tag,
657 reg: Register,
658 moffs: i64,
659 code: *std.ArrayList(u8),
660) InnerError!void {
661 return lowerToTdFdEnc(tag, reg, moffs, code, false);
662}
663
664fn lowerToTdFdEnc(
665 tag: Mir.Inst.Tag,
666 reg: Register,
667 moffs: i64,
668 code: *std.ArrayList(u8),
669 td: bool,
670) InnerError!void {
671 if (reg.lowId() != Register.rax.lowId()) return error.EmitFail;
672 if (reg.size() != immOpSize(moffs)) return error.EmitFail;
673 var opc = if (td) getOpCode(tag, .td) else getOpCode(tag, .fd);
674 if (reg.size() == 8) {
675 opc -= 1;
676 }
677 const encoder = try Encoder.init(code, 10);
678 if (reg.size() == 16) {
679 encoder.opcode_1byte(0x66);
680 }
681 encoder.rex(.{
682 .w = reg.size() == 64,
683 });
684 encoder.opcode_1byte(opc);
685 switch (reg.size()) {
686 8 => {
687 const moffs8 = try math.cast(i8, moffs);
688 encoder.imm8(moffs8);
689 },
690 16 => {
691 const moffs16 = try math.cast(i16, moffs);
692 encoder.imm16(moffs16);
693 },
694 32 => {
695 const moffs32 = try math.cast(i32, moffs);
696 encoder.imm32(moffs32);
697 },
698 64 => {
699 encoder.imm64(@bitCast(u64, moffs));
700 },
701 else => unreachable,
702 }
703}
704
632fn lowerToOiEnc(705fn lowerToOiEnc(
633 tag: Mir.Inst.Tag,706 tag: Mir.Inst.Tag,
634 reg: Register,707 reg: Register,
...@@ -641,6 +714,9 @@ fn lowerToOiEnc(...@@ -641,6 +714,9 @@ fn lowerToOiEnc(
641 opc -= 8;714 opc -= 8;
642 }715 }
643 const encoder = try Encoder.init(code, 10);716 const encoder = try Encoder.init(code, 10);
717 if (reg.size() == 16) {
718 encoder.opcode_1byte(0x66);
719 }
644 encoder.rex(.{720 encoder.rex(.{
645 .w = reg.size() == 64,721 .w = reg.size() == 64,
646 .b = reg.isExtended(),722 .b = reg.isExtended(),
...@@ -1065,52 +1141,24 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -1065,52 +1141,24 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
1065 const tag = emit.mir.instructions.items(.tag)[inst];1141 const tag = emit.mir.instructions.items(.tag)[inst];
1066 assert(tag == .movabs);1142 assert(tag == .movabs);
1067 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);1143 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
10681144 const imm: i64 = if (ops.reg1.size() == 64) blk: {
1145 const payload = emit.mir.instructions.items(.data)[inst].payload;
1146 const imm = emit.mir.extraData(Mir.Imm64, payload).data;
1147 break :blk @bitCast(i64, imm.decode());
1148 } else emit.mir.instructions.items(.data)[inst].imm;
1069 if (ops.flags == 0b00) {1149 if (ops.flags == 0b00) {
1070 // movabs reg, imm641150 // movabs reg, imm64
1071 // OI1151 // 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);1152 return lowerToOiEnc(.mov, ops.reg1, imm, emit.code);
1078 }1153 }
10791154 if (ops.reg1 == .none) {
1080 const encoder = try Encoder.init(emit.code, 10);1155 // movabs moffs64, rax
1081 const is_64 = blk: {1156 // TD
1082 if (ops.reg1 == .none) {1157 return lowerToTdEnc(.mov, imm, ops.reg2, emit.code);
1083 // movabs moffs64, rax
1084 const opc: u8 = if (ops.reg2.size() == 8) 0xa2 else 0xa3;
1085 encoder.rex(.{
1086 .w = ops.reg2.size() == 64,
1087 });
1088 encoder.opcode_1byte(opc);
1089 break :blk ops.reg2.size() == 64;
1090 } else {
1091 // movabs rax, moffs64
1092 const opc: u8 = if (ops.reg2.size() == 8) 0xa0 else 0xa1;
1093 encoder.rex(.{
1094 .w = ops.reg1.size() == 64,
1095 });
1096 encoder.opcode_1byte(opc);
1097 break :blk ops.reg1.size() == 64;
1098 }
1099 };
1100
1101 if (is_64) {
1102 const payload = emit.mir.instructions.items(.data)[inst].payload;
1103 const imm64 = emit.mir.extraData(Mir.Imm64, payload).data;
1104 encoder.imm64(imm64.decode());
1105 } else {1158 } else {
1106 const imm = emit.mir.instructions.items(.data)[inst].imm;1159 // movabs rax, moffs64
1107 if (imm <= math.maxInt(i8)) {1160 // FD
1108 encoder.imm8(@intCast(i8, imm));1161 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
1109 } else if (imm <= math.maxInt(i16)) {
1110 encoder.imm16(@intCast(i16, imm));
1111 } else {
1112 encoder.imm32(imm);
1113 }
1114 }1162 }
1115}1163}
11161164
...@@ -1563,6 +1611,25 @@ test "lower OI encoding" {...@@ -1563,6 +1611,25 @@ test "lower OI encoding" {
1563 );1611 );
1564 try lowerToOiEnc(.mov, .r11d, 0x10000000, code.buffer());1612 try lowerToOiEnc(.mov, .r11d, 0x10000000, code.buffer());
1565 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", code.emitted(), "mov r11d, 0x10000000");1613 try expectEqualHexStrings("\x41\xBB\x00\x00\x00\x10", code.emitted(), "mov r11d, 0x10000000");
1614 try lowerToOiEnc(.mov, .r11w, 0x1000, code.buffer());
1615 try expectEqualHexStrings("\x66\x41\xBB\x00\x10", code.emitted(), "mov r11w, 0x1000");
1566 try lowerToOiEnc(.mov, .r11b, 0x10, code.buffer());1616 try lowerToOiEnc(.mov, .r11b, 0x10, code.buffer());
1567 try expectEqualHexStrings("\x41\xB3\x10", code.emitted(), "mov r11b, 0x10");1617 try expectEqualHexStrings("\x41\xB3\x10", code.emitted(), "mov r11b, 0x10");
1568}1618}
1619
1620test "lower FD/TD encoding" {
1621 var code = TestEmitCode.init();
1622 defer code.deinit();
1623 try lowerToFdEnc(.mov, .rax, 0x1000000000000000, code.buffer());
1624 try expectEqualHexStrings(
1625 "\x48\xa1\x00\x00\x00\x00\x00\x00\x00\x10",
1626 code.emitted(),
1627 "mov rax, ds:0x1000000000000000",
1628 );
1629 try lowerToFdEnc(.mov, .eax, 0x10000000, code.buffer());
1630 try expectEqualHexStrings("\xa1\x00\x00\x00\x10", code.emitted(), "mov eax, ds:0x10000000");
1631 try lowerToFdEnc(.mov, .ax, 0x1000, code.buffer());
1632 try expectEqualHexStrings("\x66\xa1\x00\x10", code.emitted(), "mov ax, ds:0x1000");
1633 try lowerToFdEnc(.mov, .al, 0x10, code.buffer());
1634 try expectEqualHexStrings("\xa0\x10", code.emitted(), "mov al, ds:0x10");
1635}