Skip to content

Commit

Permalink
Winch: Float conversion instructions (#7773)
Browse files Browse the repository at this point in the history
* Winch: Float conversion instructions

* Add conversions suite to ignore list for Windows
  • Loading branch information
jeffcharles authored Jan 12, 2024
1 parent df270a4 commit b546a5f
Show file tree
Hide file tree
Showing 91 changed files with 3,242 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
"i32",
"i64",
"call_indirect",
"conversions",
"table_fill",
"table_init",
"table_copy",
Expand Down
22 changes: 22 additions & 0 deletions fuzz/fuzz_targets/differential.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,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 @@ -426,6 +436,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.

42 changes: 42 additions & 0 deletions winch/codegen/src/codegen/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,48 @@ impl<'a, 'builtins> CodeGenContext<'a, 'builtins> {
};
}

/// Prepares arguments for emitting a convert operation.
pub fn convert_op<F, M>(&mut self, masm: &mut M, dst_ty: WasmType, mut emit: F)
where
F: FnMut(&mut M, Reg, Reg, OperandSize),
M: MacroAssembler,
{
let src = self.pop_to_reg(masm, None);
let dst = self.reg_for_type(dst_ty, masm);
let dst_size = match dst_ty {
WasmType::I32 => OperandSize::S32,
WasmType::I64 => OperandSize::S64,
WasmType::F32 => OperandSize::S32,
WasmType::F64 => OperandSize::S64,
WasmType::V128 => unreachable!(),
WasmType::Ref(_) => unreachable!(),
};

emit(masm, dst, src.into(), dst_size);

self.free_reg(src);
self.stack.push(TypedReg::new(dst_ty, dst).into());
}

/// Prepares arguments for emitting a convert operation with a temporary
/// register.
pub fn convert_op_with_tmp_reg<F, M>(
&mut self,
masm: &mut M,
dst_ty: WasmType,
tmp_reg_class: RegClass,
mut emit: F,
) where
F: FnMut(&mut M, Reg, Reg, Reg, OperandSize),
M: MacroAssembler,
{
let tmp_gpr = self.reg_for_class(tmp_reg_class, masm);
self.convert_op(masm, dst_ty, |masm, dst, src, dst_size| {
emit(masm, dst, src, tmp_gpr, dst_size);
});
self.free_reg(tmp_gpr);
}

/// Drops the last `n` elements of the stack, calling the provided
/// function for each `n` stack value.
/// The values are dropped in top-to-bottom order.
Expand Down
58 changes: 58 additions & 0 deletions winch/codegen/src/isa/aarch64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,64 @@ impl Masm for MacroAssembler {
todo!()
}

fn signed_truncate(
&mut self,
_src: Reg,
_dst: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
) {
todo!()
}

fn unsigned_truncate(
&mut self,
_src: Reg,
_dst: Reg,
_tmp_fpr: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
) {
todo!()
}

fn signed_convert(
&mut self,
_src: Reg,
_dst: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
) {
todo!()
}

fn unsigned_convert(
&mut self,
_src: Reg,
_dst: Reg,
_tmp_gpr: Reg,
_src_size: OperandSize,
_dst_size: OperandSize,
) {
todo!()
}

fn reinterpret_float_as_int(&mut self, _src: Reg, _dst: Reg, _size: OperandSize) {
todo!()
}

fn reinterpret_int_as_float(&mut self, _src: Reg, _dst: Reg, _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
75 changes: 75 additions & 0 deletions winch/codegen/src/isa/x64/masm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,81 @@ impl Masm for MacroAssembler {
}
}

fn signed_truncate(
&mut self,
src: Reg,
dst: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
self.asm.cvt_float_to_sint_seq(
src,
dst,
regs::scratch(),
regs::scratch_xmm(),
src_size,
dst_size,
);
}

fn unsigned_truncate(
&mut self,
src: Reg,
dst: Reg,
tmp_fpr: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
self.asm.cvt_float_to_uint_seq(
src,
dst,
regs::scratch(),
regs::scratch_xmm(),
tmp_fpr,
src_size,
dst_size,
);
}

fn signed_convert(&mut self, src: Reg, dst: Reg, src_size: OperandSize, dst_size: OperandSize) {
self.asm.cvt_sint_to_float(src, dst, src_size, dst_size);
}

fn unsigned_convert(
&mut self,
src: Reg,
dst: Reg,
tmp_gpr: Reg,
src_size: OperandSize,
dst_size: OperandSize,
) {
// Need to convert unsigned uint32 to uint64 for conversion instruction sequence.
if let OperandSize::S32 = src_size {
self.extend(src, src, ExtendKind::I64ExtendI32U);
}

self.asm
.cvt_uint64_to_float_seq(src, dst, regs::scratch(), tmp_gpr, dst_size);
}

fn reinterpret_float_as_int(&mut self, src: Reg, dst: Reg, size: OperandSize) {
self.asm.xmm_to_gpr(src, dst, size);
}

fn reinterpret_int_as_float(&mut self, src: Reg, dst: Reg, size: OperandSize) {
self.asm.gpr_to_xmm(src.into(), dst, size);
}

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 b546a5f

Please sign in to comment.