Skip to content

Commit

Permalink
Winch: Float conversion instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
jeffcharles committed Dec 15, 2023
1 parent 3b055d4 commit bc02d7d
Show file tree
Hide file tree
Showing 75 changed files with 2,844 additions and 6 deletions.
22 changes: 22 additions & 0 deletions fuzz/fuzz_targets/differential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,16 @@ fn winch_supports_module(module: &[u8]) -> bool {
| I64Extend8S { .. }
| I64Extend16S { .. }
| I64Extend32S { .. }
| I32TruncF32S { .. }
| I32TruncF32U { .. }
| I32TruncF64S { .. }
| I32TruncF64U { .. }
| I64TruncF32S { .. }
| I64TruncF32U { .. }
| I64TruncF64S { .. }
| I64TruncF64U { .. }
| I32ReinterpretF32 { .. }
| I64ReinterpretF64 { .. }
| LocalGet { .. }
| LocalSet { .. }
| LocalTee { .. }
Expand Down Expand Up @@ -428,6 +438,18 @@ fn winch_supports_module(module: &[u8]) -> bool {
| F64Le { .. }
| F32Ge { .. }
| F64Ge { .. }
| F32ConvertI32S { .. }
| F32ConvertI32U { .. }
| F32ConvertI64S { .. }
| F32ConvertI64U { .. }
| F64ConvertI32S { .. }
| F64ConvertI32U { .. }
| F64ConvertI64S { .. }
| F64ConvertI64U { .. }
| F32ReinterpretI32 { .. }
| F64ReinterpretI64 { .. }
| F32DemoteF64 { .. }
| F64PromoteF32 { .. }
| CallIndirect { .. }
| ElemDrop { .. }
| TableCopy { .. }
Expand Down
459 changes: 459 additions & 0 deletions tests/misc_testsuite/winch/conversions.wast

Large diffs are not rendered by default.

40 changes: 38 additions & 2 deletions winch/codegen/src/isa/aarch64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ use crate::{
codegen::{ptr_type_from_ptr_size, CodeGenContext, TableData},
isa::reg::Reg,
masm::{
CalleeKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind,
CalleeKind, ConvertKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind,
MacroAssembler as Masm, OperandSize, RegImm, RemKind, RoundingMode, SPOffset, ShiftKind,
StackSlot, TrapCode,
StackSlot, TrapCode, TruncateKind,
},
};
use cranelift_codegen::{settings, Final, MachBufferFinalized, MachLabel};
Expand Down Expand Up @@ -340,6 +340,42 @@ impl Masm for MacroAssembler {
todo!()
}

fn truncate(
&mut self,
_context: &mut CodeGenContext,
_src_size: OperandSize,
_dst_size: OperandSize,
_kind: TruncateKind,
) {
todo!()
}

fn convert(
&mut self,
_context: &mut CodeGenContext,
_src_size: OperandSize,
_dst_size: OperandSize,
_kind: ConvertKind,
) {
todo!()
}

fn reinterpret_float_as_int(&mut self, _context: &mut CodeGenContext, _size: OperandSize) {
todo!()
}

fn reinterpret_int_as_float(&mut self, _context: &mut CodeGenContext, _size: OperandSize) {
todo!()
}

fn demote(&mut self, _src: Reg, _dst: Reg) {
todo!()
}

fn promote(&mut self, _src: Reg, _dst: Reg) {
todo!()
}

fn push(&mut self, reg: Reg, _size: OperandSize) -> StackSlot {
let size = <Self::ABI as abi::ABI>::word_bytes();
self.reserve_stack(size);
Expand Down
120 changes: 120 additions & 0 deletions winch/codegen/src/isa/x64/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,126 @@ impl Assembler {
})
}

pub fn xmm_to_gpr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
let op = match size {
OperandSize::S32 => SseOpcode::Movd,
OperandSize::S64 => SseOpcode::Movq,
OperandSize::S128 => unreachable!(),
};

self.emit(Inst::XmmToGpr {
op,
src: src.into(),
dst: dst.into(),
dst_size: size.into(),
});
}

/// Convert float to signed int.
pub fn cvt_float_to_sint_seq(
&mut self,
src: Reg,
dst: Reg,
tmp_gpr: Reg,
tmp_xmm: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
self.emit(Inst::CvtFloatToSintSeq {
dst_size: dst_size.into(),
src_size: src_size.into(),
is_saturating: false,
src: src.into(),
dst: dst.into(),
tmp_gpr: tmp_gpr.into(),
tmp_xmm: tmp_xmm.into(),
});
}

/// Convert float to unsigned int.
pub fn cvt_float_to_uint_seq(
&mut self,
src: Reg,
dst: Reg,
tmp_gpr: Reg,
tmp_xmm: Reg,
tmp_xmm2: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
self.emit(Inst::CvtFloatToUintSeq {
dst_size: dst_size.into(),
src_size: src_size.into(),
is_saturating: false,
src: src.into(),
dst: dst.into(),
tmp_gpr: tmp_gpr.into(),
tmp_xmm: tmp_xmm.into(),
tmp_xmm2: tmp_xmm2.into(),
});
}

/// Convert signed int to float.
pub fn cvt_sint_to_float(
&mut self,
src: Reg,
dst: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
let op = match dst_size {
OperandSize::S32 => SseOpcode::Cvtsi2ss,
OperandSize::S64 => SseOpcode::Cvtsi2sd,
OperandSize::S128 => unreachable!(),
};
self.emit(Inst::CvtIntToFloat {
op,
src1: dst.into(),
src2: src.into(),
dst: dst.into(),
src2_size: src_size.into(),
});
}

/// Convert unsigned 64-bit int to float.
pub fn cvt_uint64_to_float_seq(
&mut self,
src: Reg,
dst: Reg,
tmp_gpr1: Reg,
tmp_gpr2: Reg,
dst_size: OperandSize,
) {
self.emit(Inst::CvtUint64ToFloatSeq {
dst_size: dst_size.into(),
src: src.into(),
dst: dst.into(),
tmp_gpr1: tmp_gpr1.into(),
tmp_gpr2: tmp_gpr2.into(),
});
}

/// Change precision of float.
pub fn cvt_float_to_float(
&mut self,
src: Reg,
dst: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
let op = match (src_size, dst_size) {
(OperandSize::S32, OperandSize::S64) => SseOpcode::Cvtss2sd,
(OperandSize::S64, OperandSize::S32) => SseOpcode::Cvtsd2ss,
_ => unimplemented!(),
};

self.emit(Inst::XmmUnaryRmRUnaligned {
op,
src: Xmm::new(src.into()).expect("valid xmm unaligned").into(),
dst: dst.into(),
});
}

pub fn or_rr(&mut self, src: Reg, dst: Reg, size: OperandSize) {
self.emit(Inst::AluRmiR {
size: size.into(),
Expand Down
131 changes: 129 additions & 2 deletions winch/codegen/src/isa/x64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use super::{
};

use crate::masm::{
DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm, OperandSize,
RegImm, RemKind, RoundingMode, ShiftKind, TrapCode,
ConvertKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind, MacroAssembler as Masm,
OperandSize, RegImm, RemKind, RoundingMode, ShiftKind, TrapCode, TruncateKind,
};
use crate::{
abi::ABI,
Expand Down Expand Up @@ -916,6 +916,133 @@ impl Masm for MacroAssembler {
}
}

fn truncate(
&mut self,
context: &mut CodeGenContext,
src_size: OperandSize,
dst_size: OperandSize,
kind: TruncateKind,
) {
let src = context.pop_to_reg(self, None);
let dst = context.any_gpr(self);

match kind {
TruncateKind::Signed => {
self.asm.cvt_float_to_sint_seq(
src.into(),
dst,
regs::scratch(),
regs::scratch_xmm(),
src_size,
dst_size,
);
}
TruncateKind::Unsigned => {
let tmp_xmm2 = context.reg_for_class(RegClass::Float, self);
self.asm.cvt_float_to_uint_seq(
src.into(),
dst,
regs::scratch(),
regs::scratch_xmm(),
tmp_xmm2,
src_size,
dst_size,
);
context.free_reg(tmp_xmm2);
}
};

context.free_reg(src);

let dst = match dst_size {
OperandSize::S32 => TypedReg::i32(dst),
OperandSize::S64 => TypedReg::i64(dst),
OperandSize::S128 => unreachable!(),
};
context.stack.push(dst.into());
}

fn convert(
&mut self,
context: &mut CodeGenContext,
src_size: OperandSize,
dst_size: OperandSize,
kind: ConvertKind,
) {
let src = context.pop_to_reg(self, None);
let dst = context.reg_for_class(RegClass::Float, self);

match kind {
ConvertKind::Signed => {
self.asm
.cvt_sint_to_float(src.into(), dst, src_size, dst_size);
}
ConvertKind::Unsigned => {
// Need to convert unsigned uint32 to uint64 for conversion instruction sequence.
if let OperandSize::S32 = src_size {
self.extend(src.into(), src.into(), ExtendKind::I64ExtendI32U);
}

let tmp_gpr = context.any_gpr(self);
self.asm.cvt_uint64_to_float_seq(
src.into(),
dst.into(),
regs::scratch(),
tmp_gpr,
dst_size,
);
context.free_reg(tmp_gpr);
}
}

context.free_reg(src);

let dst = match dst_size {
OperandSize::S32 => TypedReg::f32(dst),
OperandSize::S64 => TypedReg::f64(dst),
OperandSize::S128 => unreachable!(),
};
context.stack.push(dst.into());
}

fn reinterpret_float_as_int(&mut self, context: &mut CodeGenContext, size: OperandSize) {
let src = context.pop_to_reg(self, None);
let dst = context.any_gpr(self);

self.asm.xmm_to_gpr(src.into(), dst, size);

let dst = match size {
OperandSize::S32 => TypedReg::i32(dst),
OperandSize::S64 => TypedReg::i64(dst),
OperandSize::S128 => unreachable!(),
};
context.stack.push(dst.into());
}

fn reinterpret_int_as_float(&mut self, context: &mut CodeGenContext, size: OperandSize) {
let src = context.pop_to_reg(self, None);
let dst = context.reg_for_class(RegClass::Float, self);

self.asm.gpr_to_xmm(src.into(), dst, size);

let dst = match size {
OperandSize::S32 => TypedReg::f32(dst),
OperandSize::S64 => TypedReg::f64(dst),
OperandSize::S128 => unreachable!(),
};
context.stack.push(dst.into());
}

fn demote(&mut self, src: Reg, dst: Reg) {
self.asm
.cvt_float_to_float(src.into(), dst.into(), OperandSize::S64, OperandSize::S32);
}

fn promote(&mut self, src: Reg, dst: Reg) {
self.asm
.cvt_float_to_float(src.into(), dst.into(), OperandSize::S32, OperandSize::S64);
}

fn unreachable(&mut self) {
self.asm.trap(TrapCode::UnreachableCodeReached)
}
Expand Down
Loading

0 comments on commit bc02d7d

Please sign in to comment.