authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-17 18:55:25+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-19 14:24:03+01:00
log1f4aa5ef78f4b516530f26aaeedf3794a0a9f585
tree6536916f537cd2f37bdcf9e6871262b6947584f7
parent2f0204aca303daf899a97c740719a62398adc206

x64: add lowering for single operand imul and idiv


2 files changed, 36 insertions(+), 2 deletions(-)

src/arch/x86_64/Emit.zig+31
......@@ -138,6 +138,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
138138 .shr => try emit.mirShift(.shr, inst),
139139 .sar => try emit.mirShift(.sar, inst),
140140
141 .imul => try emit.mirIMulIDiv(.imul, inst),
142 .idiv => try emit.mirIMulIDiv(.idiv, inst),
141143 .imul_complex => try emit.mirIMulComplex(inst),
142144
143145 .push => try emit.mirPushPop(.push, inst),
......@@ -683,6 +685,27 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
683685 }
684686}
685687
688fn mirIMulIDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
689 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
690 if (ops.reg1 != .none) {
691 assert(ops.reg2 == .none);
692 return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
693 }
694 assert(ops.reg1 == .none);
695 assert(ops.reg2 != .none);
696 const imm = emit.mir.instructions.items(.data)[inst].imm;
697 const ptr_size: Memory.PtrSize = switch (ops.flags) {
698 0b00 => .byte_ptr,
699 0b01 => .word_ptr,
700 0b10 => .dword_ptr,
701 0b11 => .qword_ptr,
702 };
703 return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
704 .disp = imm,
705 .base = ops.reg2,
706 }), emit.code);
707}
708
686709fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
687710 const tag = emit.mir.instructions.items(.tag)[inst];
688711 assert(tag == .imul_complex);
......@@ -1048,6 +1071,7 @@ const Tag = enum {
10481071 brk,
10491072 nop,
10501073 imul,
1074 idiv,
10511075 syscall,
10521076 ret_near,
10531077 ret_far,
......@@ -1276,6 +1300,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
12761300 .setnl, .setge => OpCode.twoByte(0x0f, 0x9d),
12771301 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),
12781302 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
1303 .idiv, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
12791304 else => null,
12801305 },
12811306 .o => return switch (tag) {
......@@ -1409,6 +1434,8 @@ inline fn getModRmExt(tag: Tag) ?u3 {
14091434 => 0x4,
14101435 .shr => 0x5,
14111436 .sar => 0x7,
1437 .imul => 0x5,
1438 .idiv => 0x7,
14121439 else => null,
14131440 };
14141441}
......@@ -2204,6 +2231,10 @@ test "lower M encoding" {
22042231 try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", emit.lowered(), "jmp qword ptr [ds:0x10]");
22052232 try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), emit.code());
22062233 try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");
2234 try lowerToMEnc(.idiv, RegisterOrMemory.reg(.rax), emit.code());
2235 try expectEqualHexStrings("\x48\xF7\xF8", emit.lowered(), "idiv rax");
2236 try lowerToMEnc(.imul, RegisterOrMemory.reg(.al), emit.code());
2237 try expectEqualHexStrings("\xF6\xE8", emit.lowered(), "imul al");
22072238}
22082239
22092240test "lower M1 and MC encodings" {
src/arch/x86_64/Mir.zig+5-2
......@@ -220,8 +220,11 @@ pub const Inst = struct {
220220 sar_mem_index_imm,
221221
222222 /// ops flags: form:
223 /// 0bX0 reg1
224 /// 0bX1 [reg1 + imm32]
223 /// 0b00 reg1
224 /// 0b00 byte ptr [reg2 + imm32]
225 /// 0b01 word ptr [reg2 + imm32]
226 /// 0b10 dword ptr [reg2 + imm32]
227 /// 0b11 qword ptr [reg2 + imm32]
225228 imul,
226229 idiv,
227230