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

stage2: x86_64: implement `@floatToInt` for `f32` and `f64`
This commit is contained in:
Jakub Konka 2022-03-21 23:54:36 +01:00 committed by GitHub
commit d71bd0300b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 6 deletions

View File

@ -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 {

View File

@ -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,
};
}

View File

@ -256,6 +256,20 @@ 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:
/// 0b01 dword ptr [reg1 + imm32]
/// 0b10 qword ptr [reg1 + imm32]
fld,
/// ops flags: form:
/// 0b00 inst
/// 0b01 reg1

View File

@ -118,7 +118,6 @@ test "@intToFloat" {
test "@floatToInt" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
try testFloatToInts();