mirror of
https://github.com/ziglang/zig.git
synced 2026-01-09 08:55:36 +00:00
x64: add lowering for single operand imul and idiv
This commit is contained in:
parent
2f0204aca3
commit
1f4aa5ef78
@ -138,6 +138,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
|
||||
.shr => try emit.mirShift(.shr, inst),
|
||||
.sar => try emit.mirShift(.sar, inst),
|
||||
|
||||
.imul => try emit.mirIMulIDiv(.imul, inst),
|
||||
.idiv => try emit.mirIMulIDiv(.idiv, inst),
|
||||
.imul_complex => try emit.mirIMulComplex(inst),
|
||||
|
||||
.push => try emit.mirPushPop(.push, inst),
|
||||
@ -683,6 +685,27 @@ fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
|
||||
}
|
||||
}
|
||||
|
||||
fn mirIMulIDiv(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
|
||||
const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
|
||||
if (ops.reg1 != .none) {
|
||||
assert(ops.reg2 == .none);
|
||||
return lowerToMEnc(tag, RegisterOrMemory.reg(ops.reg1), emit.code);
|
||||
}
|
||||
assert(ops.reg1 == .none);
|
||||
assert(ops.reg2 != .none);
|
||||
const imm = emit.mir.instructions.items(.data)[inst].imm;
|
||||
const ptr_size: Memory.PtrSize = switch (ops.flags) {
|
||||
0b00 => .byte_ptr,
|
||||
0b01 => .word_ptr,
|
||||
0b10 => .dword_ptr,
|
||||
0b11 => .qword_ptr,
|
||||
};
|
||||
return lowerToMEnc(tag, RegisterOrMemory.mem(ptr_size, .{
|
||||
.disp = imm,
|
||||
.base = ops.reg2,
|
||||
}), emit.code);
|
||||
}
|
||||
|
||||
fn mirIMulComplex(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
|
||||
const tag = emit.mir.instructions.items(.tag)[inst];
|
||||
assert(tag == .imul_complex);
|
||||
@ -1048,6 +1071,7 @@ const Tag = enum {
|
||||
brk,
|
||||
nop,
|
||||
imul,
|
||||
idiv,
|
||||
syscall,
|
||||
ret_near,
|
||||
ret_far,
|
||||
@ -1276,6 +1300,7 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
|
||||
.setnl, .setge => OpCode.twoByte(0x0f, 0x9d),
|
||||
.setle, .setng => OpCode.twoByte(0x0f, 0x9e),
|
||||
.setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
|
||||
.idiv, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
|
||||
else => null,
|
||||
},
|
||||
.o => return switch (tag) {
|
||||
@ -1409,6 +1434,8 @@ inline fn getModRmExt(tag: Tag) ?u3 {
|
||||
=> 0x4,
|
||||
.shr => 0x5,
|
||||
.sar => 0x7,
|
||||
.imul => 0x5,
|
||||
.idiv => 0x7,
|
||||
else => null,
|
||||
};
|
||||
}
|
||||
@ -2204,6 +2231,10 @@ test "lower M encoding" {
|
||||
try expectEqualHexStrings("\xFF\x24\x25\x10\x00\x00\x00", emit.lowered(), "jmp qword ptr [ds:0x10]");
|
||||
try lowerToMEnc(.seta, RegisterOrMemory.reg(.r11b), emit.code());
|
||||
try expectEqualHexStrings("\x41\x0F\x97\xC3", emit.lowered(), "seta r11b");
|
||||
try lowerToMEnc(.idiv, RegisterOrMemory.reg(.rax), emit.code());
|
||||
try expectEqualHexStrings("\x48\xF7\xF8", emit.lowered(), "idiv rax");
|
||||
try lowerToMEnc(.imul, RegisterOrMemory.reg(.al), emit.code());
|
||||
try expectEqualHexStrings("\xF6\xE8", emit.lowered(), "imul al");
|
||||
}
|
||||
|
||||
test "lower M1 and MC encodings" {
|
||||
|
||||
@ -220,8 +220,11 @@ pub const Inst = struct {
|
||||
sar_mem_index_imm,
|
||||
|
||||
/// ops flags: form:
|
||||
/// 0bX0 reg1
|
||||
/// 0bX1 [reg1 + imm32]
|
||||
/// 0b00 reg1
|
||||
/// 0b00 byte ptr [reg2 + imm32]
|
||||
/// 0b01 word ptr [reg2 + imm32]
|
||||
/// 0b10 dword ptr [reg2 + imm32]
|
||||
/// 0b11 qword ptr [reg2 + imm32]
|
||||
imul,
|
||||
idiv,
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user