aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2022-03-21 23:54:36 +0100
committerGitHub <noreply@github.com>2022-03-21 23:54:36 +0100
commitd71bd0300bb4dd7f1f90c1e517d197c71abeb277 (patch)
tree89f567182eafa6e41ea38ef4319c9f3758caeef4 /src
parenta9b6de693ce04f73f8aecce91e8033951024c123 (diff)
parent355d0d0e7e061c86fbc08247f49900488e98acd1 (diff)
downloadzig-d71bd0300bb4dd7f1f90c1e517d197c71abeb277.tar.gz
zig-d71bd0300bb4dd7f1f90c1e517d197c71abeb277.zip
Merge pull request #11195 from mparadinha/float-to-int
stage2: x86_64: implement `@floatToInt` for `f32` and `f64`
Diffstat (limited to 'src')
-rw-r--r--src/arch/x86_64/CodeGen.zig55
-rw-r--r--src/arch/x86_64/Emit.zig60
-rw-r--r--src/arch/x86_64/Mir.zig14
3 files changed, 124 insertions, 5 deletions
diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig
index ce049a4541..72f12cf4e9 100644
--- a/src/arch/x86_64/CodeGen.zig
+++ b/src/arch/x86_64/CodeGen.zig
@@ -5481,11 +5481,56 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
- const result: MCValue = if (self.liveness.isUnused(inst))
- .dead
- else
- return self.fail("TODO implement airFloatToInt for {}", .{self.target.cpu.arch});
- return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
+ if (self.liveness.isUnused(inst))
+ return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
+
+ const src_ty = self.air.typeOf(ty_op.operand);
+ const dst_ty = self.air.typeOfIndex(inst);
+ const operand = try self.resolveInst(ty_op.operand);
+
+ // move float src to ST(0)
+ const stack_offset = switch (operand) {
+ .stack_offset, .ptr_stack_offset => |offset| offset,
+ else => blk: {
+ const offset = @intCast(i32, try self.allocMem(
+ inst,
+ @intCast(u32, src_ty.abiSize(self.target.*)),
+ src_ty.abiAlignment(self.target.*),
+ ));
+ try self.genSetStack(src_ty, offset, operand, .{});
+ break :blk offset;
+ },
+ };
+ _ = try self.addInst(.{
+ .tag = .fld,
+ .ops = (Mir.Ops{
+ .flags = switch (src_ty.abiSize(self.target.*)) {
+ 4 => 0b01,
+ 8 => 0b10,
+ else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),
+ },
+ .reg1 = .rbp,
+ }).encode(),
+ .data = .{ .imm = @bitCast(u32, -stack_offset) },
+ });
+
+ // convert
+ const stack_dst = try self.allocRegOrMem(inst, false);
+ _ = try self.addInst(.{
+ .tag = .fisttp,
+ .ops = (Mir.Ops{
+ .flags = switch (dst_ty.abiSize(self.target.*)) {
+ 1...2 => 0b00,
+ 3...4 => 0b01,
+ 5...8 => 0b10,
+ else => |size| return self.fail("TODO convert float with abiSize={}", .{size}),
+ },
+ .reg1 = .rbp,
+ }).encode(),
+ .data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) },
+ });
+
+ return self.finishAir(inst, stack_dst, .{ ty_op.operand, .none, .none });
}
fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig
index b6a3ffdf30..0543496750 100644
--- a/src/arch/x86_64/Emit.zig
+++ b/src/arch/x86_64/Emit.zig
@@ -131,6 +131,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
.movabs => try emit.mirMovabs(inst),
+ .fisttp => try emit.mirFisttp(inst),
+ .fld => try emit.mirFld(inst),
+
.lea => try emit.mirLea(inst),
.lea_pie => try emit.mirLeaPie(inst),
@@ -686,6 +689,48 @@ 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 mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
+ const tag = emit.mir.instructions.items(.tag)[inst];
+ assert(tag == .fld);
+ 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) {
+ 0b01 => .fld32,
+ 0b10 => .fld64,
+ 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 +1159,11 @@ const Tag = enum {
syscall,
ret_near,
ret_far,
+ fisttp16,
+ fisttp32,
+ fisttp64,
+ fld32,
+ fld64,
jo,
jno,
jb,
@@ -1352,6 +1402,11 @@ 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),
+ .fld32 => OpCode.oneByte(0xd9),
+ .fld64 => OpCode.oneByte(0xdd),
else => null,
},
.o => return switch (tag) {
@@ -1492,6 +1547,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
.imul => 0x5,
.idiv => 0x7,
.div => 0x6,
+ .fisttp16 => 0x1,
+ .fisttp32 => 0x1,
+ .fisttp64 => 0x1,
+ .fld32 => 0x0,
+ .fld64 => 0x0,
else => null,
};
}
diff --git a/src/arch/x86_64/Mir.zig b/src/arch/x86_64/Mir.zig
index 9bb568a976..f4d6f454ae 100644
--- a/src/arch/x86_64/Mir.zig
+++ b/src/arch/x86_64/Mir.zig
@@ -257,6 +257,20 @@ pub const Inst = struct {
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:
+ /// 0b01 dword ptr [reg1 + imm32]
+ /// 0b10 qword ptr [reg1 + imm32]
+ fld,
+
+ /// ops flags: form:
/// 0b00 inst
/// 0b01 reg1
/// 0b01 [imm32] if reg1 is none