| ... | ... | @@ -138,6 +138,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void { |
| 138 | 138 | .shr => try emit.mirShift(.shr, inst), |
| 139 | 139 | .sar => try emit.mirShift(.sar, inst), |
| 140 | 140 | |
| 141 | .imul => try emit.mirIMulIDiv(.imul, inst), |
| 142 | .idiv => try emit.mirIMulIDiv(.idiv, inst), |
| 141 | 143 | .imul_complex => try emit.mirIMulComplex(inst), |
| 142 | 144 | |
| 143 | 145 | .push => try emit.mirPushPop(.push, inst), |
| ... | ... | @@ -683,6 +685,27 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { |
| 683 | 685 | } |
| 684 | 686 | } |
| 685 | 687 | |
| 688 | fn 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 | |
| 686 | 709 | fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { |
| 687 | 710 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 688 | 711 | assert(tag == .imul_complex); |
| ... | ... | @@ -1048,6 +1071,7 @@ const Tag = enum { |
| 1048 | 1071 | brk, |
| 1049 | 1072 | nop, |
| 1050 | 1073 | imul, |
| 1074 | idiv, |
| 1051 | 1075 | syscall, |
| 1052 | 1076 | ret_near, |
| 1053 | 1077 | ret_far, |
| ... | ... | @@ -1276,6 +1300,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { |
| 1276 | 1300 | .setnl, .setge => OpCode.twoByte(0x0f, 0x9d), |
| 1277 | 1301 | .setle, .setng => OpCode.twoByte(0x0f, 0x9e), |
| 1278 | 1302 | .setnle, .setg => OpCode.twoByte(0x0f, 0x9f), |
| 1303 | .idiv, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), |
| 1279 | 1304 | else => null, |
| 1280 | 1305 | }, |
| 1281 | 1306 | .o => return switch (tag) { |
| ... | ... | @@ -1409,6 +1434,8 @@ inline fn getModRmExt(tag: Tag) ?u3 { |
| 1409 | 1434 | => 0x4, |
| 1410 | 1435 | .shr => 0x5, |
| 1411 | 1436 | .sar => 0x7, |
| 1437 | .imul => 0x5, |
| 1438 | .idiv => 0x7, |
| 1412 | 1439 | else => null, |
| 1413 | 1440 | }; |
| 1414 | 1441 | } |
| ... | ... | @@ -2204,6 +2231,10 @@ test "lower M encoding" { |
| 2204 | 2231 | try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", emit.lowered(), "jmp qword ptr [ds:0x10]"); |
| 2205 | 2232 | try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), emit.code()); |
| 2206 | 2233 | 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"); |
| 2207 | 2238 | } |
| 2208 | 2239 | |
| 2209 | 2240 | test "lower M1 and MC encodings" { |