From 972d923f09f90ac15a2f2b13863598b268022d88 Mon Sep 17 00:00:00 2001 From: mparadinha Date: Mon, 14 Mar 2022 15:00:45 +0000 Subject: [PATCH] stage2: x86_64: add new `fisttp` instruction this instruction does truncating conversion from floating point values to signed integers. --- src/arch/x86_64/Emit.zig | 33 +++++++++++++++++++++++++++++++++ src/arch/x86_64/Mir.zig | 9 +++++++++ 2 files changed, 42 insertions(+) diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index b6a3ffdf30..645fbf618c 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -131,6 +131,8 @@ pub fn lowerMir(emit: *Emit) InnerError!void { .movabs => try emit.mirMovabs(inst), + .fisttp => try emit.mirFisttp(inst), + .lea => try emit.mirLea(inst), .lea_pie => try emit.mirLeaPie(inst), @@ -686,6 +688,28 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { return lowerToFdEnc(.mov, ops.reg1, imm, emit.code); } +fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void { + const tag = emit.mir.instructions.items(.tag)[inst]; + assert(tag == .fisttp); + const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); + + // the selecting between operand sizes for this particular `fisttp` instruction + // is done via opcode instead of the usual prefixes. + + const opcode: Tag = switch (ops.flags) { + 0b00 => .fisttp16, + 0b01 => .fisttp32, + 0b10 => .fisttp64, + else => unreachable, + }; + const mem_or_reg = Memory{ + .base = ops.reg1, + .disp = emit.mir.instructions.items(.data)[inst].imm, + .ptr_size = Memory.PtrSize.dword_ptr, // to prevent any prefix from being used + }; + return lowerToMEnc(opcode, .{ .memory = mem_or_reg }, emit.code); +} + fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void { const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]); switch (ops.flags) { @@ -1114,6 +1138,9 @@ const Tag = enum { syscall, ret_near, ret_far, + fisttp16, + fisttp32, + fisttp64, jo, jno, jb, @@ -1352,6 +1379,9 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode { .setle, .setng => OpCode.twoByte(0x0f, 0x9e), .setnle, .setg => OpCode.twoByte(0x0f, 0x9f), .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7), + .fisttp16 => OpCode.oneByte(0xdf), + .fisttp32 => OpCode.oneByte(0xdb), + .fisttp64 => OpCode.oneByte(0xdd), else => null, }, .o => return switch (tag) { @@ -1492,6 +1522,9 @@ inline fn getModRmExt(tag: Tag) ?u3 { .imul => 0x5, .idiv => 0x7, .div => 0x6, + .fisttp16 => 0x1, + .fisttp32 => 0x1, + .fisttp64 => 0x1, else => null, }; } diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig index 9bb568a976..5ec028261a 100644 --- a/src/arch/x86_64/Mir.zig +++ b/src/arch/x86_64/Mir.zig @@ -256,6 +256,15 @@ pub const Inst = struct { /// TODO handle scaling movabs, + /// ops flags: form: + /// 0b00 word ptr [reg1 + imm32] + /// 0b01 dword ptr [reg1 + imm32] + /// 0b10 qword ptr [reg1 + imm32] + /// Notes: + /// * source is always ST(0) + /// * only supports memory operands as destination + fisttp, + /// ops flags: form: /// 0b00 inst /// 0b01 reg1