diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2022-03-21 23:54:36 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-03-21 23:54:36 +0100 |
| commit | d71bd0300bb4dd7f1f90c1e517d197c71abeb277 (patch) | |
| tree | 89f567182eafa6e41ea38ef4319c9f3758caeef4 /src | |
| parent | a9b6de693ce04f73f8aecce91e8033951024c123 (diff) | |
| parent | 355d0d0e7e061c86fbc08247f49900488e98acd1 (diff) | |
| download | zig-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.zig | 55 | ||||
| -rw-r--r-- | src/arch/x86_64/Emit.zig | 60 | ||||
| -rw-r--r-- | src/arch/x86_64/Mir.zig | 14 |
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 |
