authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-03-21 23:54:36+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-21 23:54:36+01:00
logd71bd0300bb4dd7f1f90c1e517d197c71abeb277
tree89f567182eafa6e41ea38ef4319c9f3758caeef4
parenta9b6de693ce04f73f8aecce91e8033951024c123
parent355d0d0e7e061c86fbc08247f49900488e98acd1
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11195 from mparadinha/float-to-int

stage2: x86_64: implement `@floatToInt` for `f32` and `f64`

4 files changed, 124 insertions(+), 6 deletions(-)

src/arch/x86_64/CodeGen.zig+50-5
...@@ -5481,11 +5481,56 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {...@@ -5481,11 +5481,56 @@ fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void {
54815481
5482fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {5482fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void {
5483 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5483 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5484 const result: MCValue = if (self.liveness.isUnused(inst))5484 if (self.liveness.isUnused(inst))
5485 .dead5485 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
5486 else5486
5487 return self.fail("TODO implement airFloatToInt for {}", .{self.target.cpu.arch});5487 const src_ty = self.air.typeOf(ty_op.operand);
5488 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });5488 const dst_ty = self.air.typeOfIndex(inst);
5489 const operand = try self.resolveInst(ty_op.operand);
5490
5491 // move float src to ST(0)
5492 const stack_offset = switch (operand) {
5493 .stack_offset, .ptr_stack_offset => |offset| offset,
5494 else => blk: {
5495 const offset = @intCast(i32, try self.allocMem(
5496 inst,
5497 @intCast(u32, src_ty.abiSize(self.target.*)),
5498 src_ty.abiAlignment(self.target.*),
5499 ));
5500 try self.genSetStack(src_ty, offset, operand, .{});
5501 break :blk offset;
5502 },
5503 };
5504 _ = try self.addInst(.{
5505 .tag = .fld,
5506 .ops = (Mir.Ops{
5507 .flags = switch (src_ty.abiSize(self.target.*)) {
5508 4 => 0b01,
5509 8 => 0b10,
5510 else => |size| return self.fail("TODO load ST(0) with abiSize={}", .{size}),
5511 },
5512 .reg1 = .rbp,
5513 }).encode(),
5514 .data = .{ .imm = @bitCast(u32, -stack_offset) },
5515 });
5516
5517 // convert
5518 const stack_dst = try self.allocRegOrMem(inst, false);
5519 _ = try self.addInst(.{
5520 .tag = .fisttp,
5521 .ops = (Mir.Ops{
5522 .flags = switch (dst_ty.abiSize(self.target.*)) {
5523 1...2 => 0b00,
5524 3...4 => 0b01,
5525 5...8 => 0b10,
5526 else => |size| return self.fail("TODO convert float with abiSize={}", .{size}),
5527 },
5528 .reg1 = .rbp,
5529 }).encode(),
5530 .data = .{ .imm = @bitCast(u32, -stack_dst.stack_offset) },
5531 });
5532
5533 return self.finishAir(inst, stack_dst, .{ ty_op.operand, .none, .none });
5489}5534}
54905535
5491fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {5536fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
src/arch/x86_64/Emit.zig+60
...@@ -131,6 +131,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -131,6 +131,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
131131
132 .movabs => try emit.mirMovabs(inst),132 .movabs => try emit.mirMovabs(inst),
133133
134 .fisttp => try emit.mirFisttp(inst),
135 .fld => try emit.mirFld(inst),
136
134 .lea => try emit.mirLea(inst),137 .lea => try emit.mirLea(inst),
135 .lea_pie => try emit.mirLeaPie(inst),138 .lea_pie => try emit.mirLeaPie(inst),
136139
...@@ -686,6 +689,48 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -686,6 +689,48 @@ fn mirMovabs(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
686 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);689 return lowerToFdEnc(.mov, ops.reg1, imm, emit.code);
687}690}
688691
692fn mirFisttp(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
693 const tag = emit.mir.instructions.items(.tag)[inst];
694 assert(tag == .fisttp);
695 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
696
697 // the selecting between operand sizes for this particular `fisttp` instruction
698 // is done via opcode instead of the usual prefixes.
699
700 const opcode: Tag = switch (ops.flags) {
701 0b00 => .fisttp16,
702 0b01 => .fisttp32,
703 0b10 => .fisttp64,
704 else => unreachable,
705 };
706 const mem_or_reg = Memory{
707 .base = ops.reg1,
708 .disp = emit.mir.instructions.items(.data)[inst].imm,
709 .ptr_size = Memory.PtrSize.dword_ptr, // to prevent any prefix from being used
710 };
711 return lowerToMEnc(opcode, .{ .memory = mem_or_reg }, emit.code);
712}
713
714fn mirFld(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
715 const tag = emit.mir.instructions.items(.tag)[inst];
716 assert(tag == .fld);
717 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
718
719 // the selecting between operand sizes for this particular `fisttp` instruction
720 // is done via opcode instead of the usual prefixes.
721
722 const opcode: Tag = switch (ops.flags) {
723 0b01 => .fld32,
724 0b10 => .fld64,
725 else => unreachable,
726 };
727 const mem_or_reg = Memory{
728 .base = ops.reg1,
729 .disp = emit.mir.instructions.items(.data)[inst].imm,
730 .ptr_size = Memory.PtrSize.dword_ptr, // to prevent any prefix from being used
731 };
732 return lowerToMEnc(opcode, .{ .memory = mem_or_reg }, emit.code);
733}
689fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {734fn mirShift(emit: *Emit, tag: Tag, inst: Mir.Inst.Index) InnerError!void {
690 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);735 const ops = Mir.Ops.decode(emit.mir.instructions.items(.ops)[inst]);
691 switch (ops.flags) {736 switch (ops.flags) {
...@@ -1114,6 +1159,11 @@ const Tag = enum {...@@ -1114,6 +1159,11 @@ const Tag = enum {
1114 syscall,1159 syscall,
1115 ret_near,1160 ret_near,
1116 ret_far,1161 ret_far,
1162 fisttp16,
1163 fisttp32,
1164 fisttp64,
1165 fld32,
1166 fld64,
1117 jo,1167 jo,
1118 jno,1168 jno,
1119 jb,1169 jb,
...@@ -1352,6 +1402,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {...@@ -1352,6 +1402,11 @@ inline fn getOpCode(tag: Tag, enc: Encoding, is_one_byte: bool) ?OpCode {
1352 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),1402 .setle, .setng => OpCode.twoByte(0x0f, 0x9e),
1353 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),1403 .setnle, .setg => OpCode.twoByte(0x0f, 0x9f),
1354 .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),1404 .idiv, .div, .imul => OpCode.oneByte(if (is_one_byte) 0xf6 else 0xf7),
1405 .fisttp16 => OpCode.oneByte(0xdf),
1406 .fisttp32 => OpCode.oneByte(0xdb),
1407 .fisttp64 => OpCode.oneByte(0xdd),
1408 .fld32 => OpCode.oneByte(0xd9),
1409 .fld64 => OpCode.oneByte(0xdd),
1355 else => null,1410 else => null,
1356 },1411 },
1357 .o => return switch (tag) {1412 .o => return switch (tag) {
...@@ -1492,6 +1547,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {...@@ -1492,6 +1547,11 @@ inline fn getModRmExt(tag: Tag) ?u3 {
1492 .imul => 0x5,1547 .imul => 0x5,
1493 .idiv => 0x7,1548 .idiv => 0x7,
1494 .div => 0x6,1549 .div => 0x6,
1550 .fisttp16 => 0x1,
1551 .fisttp32 => 0x1,
1552 .fisttp64 => 0x1,
1553 .fld32 => 0x0,
1554 .fld64 => 0x0,
1495 else => null,1555 else => null,
1496 };1556 };
1497}1557}
src/arch/x86_64/Mir.zig+14
...@@ -256,6 +256,20 @@ pub const Inst = struct {...@@ -256,6 +256,20 @@ pub const Inst = struct {
256 /// TODO handle scaling256 /// TODO handle scaling
257 movabs,257 movabs,
258258
259 /// ops flags: form:
260 /// 0b00 word ptr [reg1 + imm32]
261 /// 0b01 dword ptr [reg1 + imm32]
262 /// 0b10 qword ptr [reg1 + imm32]
263 /// Notes:
264 /// * source is always ST(0)
265 /// * only supports memory operands as destination
266 fisttp,
267
268 /// ops flags: form:
269 /// 0b01 dword ptr [reg1 + imm32]
270 /// 0b10 qword ptr [reg1 + imm32]
271 fld,
272
259 /// ops flags: form:273 /// ops flags: form:
260 /// 0b00 inst274 /// 0b00 inst
261 /// 0b01 reg1275 /// 0b01 reg1
test/behavior/cast.zig-1
...@@ -118,7 +118,6 @@ test "@intToFloat" {...@@ -118,7 +118,6 @@ test "@intToFloat" {
118118
119test "@floatToInt" {119test "@floatToInt" {
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
121 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO121 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
123122
124 try testFloatToInts();123 try testFloatToInts();