Add more float ops
This commit is contained in:
301
src/backend.rs
301
src/backend.rs
@@ -6,7 +6,7 @@ use self::registers::*;
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::microwasm::Value;
|
use crate::microwasm::Value;
|
||||||
use crate::module::{ModuleContext, RuntimeFunc};
|
use crate::module::{ModuleContext, RuntimeFunc};
|
||||||
use cranelift_codegen::binemit;
|
use cranelift_codegen::{binemit, ir};
|
||||||
use dynasmrt::x64::Assembler;
|
use dynasmrt::x64::Assembler;
|
||||||
use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, ExecutableBuffer};
|
use dynasmrt::{AssemblyOffset, DynamicLabel, DynasmApi, DynasmLabelApi, ExecutableBuffer};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -665,27 +665,30 @@ pub enum MemoryAccessMode {
|
|||||||
Unchecked,
|
Unchecked,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PendingLabel {
|
struct Pending<T> {
|
||||||
label: Label,
|
label: T,
|
||||||
is_defined: bool,
|
is_defined: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PendingLabel {
|
impl<T> Pending<T> {
|
||||||
fn undefined(label: Label) -> Self {
|
fn undefined(label: T) -> Self {
|
||||||
PendingLabel {
|
Pending {
|
||||||
label,
|
label,
|
||||||
is_defined: false,
|
is_defined: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn defined(label: Label) -> Self {
|
fn defined(label: T) -> Self {
|
||||||
PendingLabel {
|
Pending {
|
||||||
label,
|
label,
|
||||||
is_defined: true,
|
is_defined: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_undefined(&self) -> Option<Label> {
|
fn as_undefined(&self) -> Option<T>
|
||||||
|
where
|
||||||
|
T: Copy,
|
||||||
|
{
|
||||||
if !self.is_defined {
|
if !self.is_defined {
|
||||||
Some(self.label)
|
Some(self.label)
|
||||||
} else {
|
} else {
|
||||||
@@ -694,9 +697,9 @@ impl PendingLabel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Label> for PendingLabel {
|
impl<T> From<T> for Pending<T> {
|
||||||
fn from(label: Label) -> Self {
|
fn from(label: T) -> Self {
|
||||||
PendingLabel {
|
Pending {
|
||||||
label,
|
label,
|
||||||
is_defined: false,
|
is_defined: false,
|
||||||
}
|
}
|
||||||
@@ -706,12 +709,14 @@ impl From<Label> for PendingLabel {
|
|||||||
// TODO: We can share one trap/constant for all functions by reusing this struct
|
// TODO: We can share one trap/constant for all functions by reusing this struct
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Labels {
|
struct Labels {
|
||||||
trap: Option<PendingLabel>,
|
trap: Option<Pending<Label>>,
|
||||||
ret: Option<PendingLabel>,
|
ret: Option<Pending<Label>>,
|
||||||
neg_const_f32: Option<PendingLabel>,
|
neg_const_f32: Option<Pending<Label>>,
|
||||||
neg_const_f64: Option<PendingLabel>,
|
neg_const_f64: Option<Pending<Label>>,
|
||||||
abs_const_f32: Option<PendingLabel>,
|
abs_const_f32: Option<Pending<Label>>,
|
||||||
abs_const_f64: Option<PendingLabel>,
|
abs_const_f64: Option<Pending<Label>>,
|
||||||
|
copysign_consts_f32: Option<Pending<(Label, Label)>>,
|
||||||
|
copysign_consts_f64: Option<Pending<(Label, Label)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Context<'a, M> {
|
pub struct Context<'a, M> {
|
||||||
@@ -2624,6 +2629,110 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
self.push(out);
|
self.push(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn f32_sqrt(&mut self) {
|
||||||
|
let val = self.pop();
|
||||||
|
|
||||||
|
let out = if let Some(i) = val.imm_f32() {
|
||||||
|
ValueLocation::Immediate(
|
||||||
|
wasmparser::Ieee32(f32::from_bits(i.bits()).sqrt().to_bits()).into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let reg = self.into_temp_reg(GPRType::Rx, val);
|
||||||
|
|
||||||
|
dynasm!(self.asm
|
||||||
|
; sqrtss Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
ValueLocation::Reg(reg)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.push(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f64_sqrt(&mut self) {
|
||||||
|
let val = self.pop();
|
||||||
|
|
||||||
|
let out = if let Some(i) = val.imm_f64() {
|
||||||
|
ValueLocation::Immediate(
|
||||||
|
wasmparser::Ieee64(f64::from_bits(i.bits()).sqrt().to_bits()).into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let reg = self.into_temp_reg(GPRType::Rx, val);
|
||||||
|
|
||||||
|
dynasm!(self.asm
|
||||||
|
; sqrtsd Rx(reg.rx().unwrap()), Rx(reg.rx().unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
ValueLocation::Reg(reg)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.push(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f32_copysign(&mut self) {
|
||||||
|
let right = self.pop();
|
||||||
|
let left = self.pop();
|
||||||
|
|
||||||
|
let out = if let (Some(left), Some(right)) = (left.imm_f32(), right.imm_f32()) {
|
||||||
|
ValueLocation::Immediate(
|
||||||
|
wasmparser::Ieee32(
|
||||||
|
f32::from_bits(left.bits())
|
||||||
|
.copysign(f32::from_bits(right.bits()))
|
||||||
|
.to_bits(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let left = self.into_temp_reg(GPRType::Rx, left);
|
||||||
|
let right = self.into_reg(GPRType::Rx, right);
|
||||||
|
let (neg_zero, nan) = self.copysign_consts_f32_labels();
|
||||||
|
|
||||||
|
dynasm!(self.asm
|
||||||
|
; andps Rx(right.rx().unwrap()), [=>neg_zero.0]
|
||||||
|
; andps Rx(left.rx().unwrap()), [=>nan.0]
|
||||||
|
; orps Rx(left.rx().unwrap()), Rx(right.rx().unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
self.block_state.regs.release(right);
|
||||||
|
|
||||||
|
ValueLocation::Reg(left)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.push(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f64_copysign(&mut self) {
|
||||||
|
let right = self.pop();
|
||||||
|
let left = self.pop();
|
||||||
|
|
||||||
|
let out = if let (Some(left), Some(right)) = (left.imm_f64(), right.imm_f64()) {
|
||||||
|
ValueLocation::Immediate(
|
||||||
|
wasmparser::Ieee64(
|
||||||
|
f64::from_bits(left.bits())
|
||||||
|
.copysign(f64::from_bits(right.bits()))
|
||||||
|
.to_bits(),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let left = self.into_temp_reg(GPRType::Rx, left);
|
||||||
|
let right = self.into_reg(GPRType::Rx, right);
|
||||||
|
let (neg_zero, nan) = self.copysign_consts_f64_labels();
|
||||||
|
|
||||||
|
dynasm!(self.asm
|
||||||
|
; andpd Rx(right.rx().unwrap()), [=>neg_zero.0]
|
||||||
|
; andpd Rx(left.rx().unwrap()), [=>nan.0]
|
||||||
|
; orpd Rx(left.rx().unwrap()), Rx(right.rx().unwrap())
|
||||||
|
);
|
||||||
|
|
||||||
|
self.block_state.regs.release(right);
|
||||||
|
|
||||||
|
ValueLocation::Reg(left)
|
||||||
|
};
|
||||||
|
|
||||||
|
self.push(out);
|
||||||
|
}
|
||||||
|
|
||||||
unop!(i32_clz, lzcnt, Rd, u32, u32::leading_zeros);
|
unop!(i32_clz, lzcnt, Rd, u32, u32::leading_zeros);
|
||||||
unop!(i64_clz, lzcnt, Rq, u64, |a: u64| a.leading_zeros() as u64);
|
unop!(i64_clz, lzcnt, Rq, u64, |a: u64| a.leading_zeros() as u64);
|
||||||
unop!(i32_ctz, tzcnt, Rd, u32, u32::trailing_zeros);
|
unop!(i32_ctz, tzcnt, Rd, u32, u32::trailing_zeros);
|
||||||
@@ -2775,14 +2884,66 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
|
|
||||||
commutative_binop_f32!(f32_add, addss, |a, b| a + b);
|
commutative_binop_f32!(f32_add, addss, |a, b| a + b);
|
||||||
commutative_binop_f32!(f32_mul, mulss, |a, b| a * b);
|
commutative_binop_f32!(f32_mul, mulss, |a, b| a * b);
|
||||||
|
commutative_binop_f32!(f32_min, minss, f32::min);
|
||||||
|
commutative_binop_f32!(f32_max, maxss, f32::max);
|
||||||
binop_f32!(f32_sub, subss, |a, b| a - b);
|
binop_f32!(f32_sub, subss, |a, b| a - b);
|
||||||
binop_f32!(f32_div, divss, |a, b| a / b);
|
binop_f32!(f32_div, divss, |a, b| a / b);
|
||||||
|
|
||||||
|
pub fn f32_ceil(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::CeilF32),
|
||||||
|
iter::once(F32),
|
||||||
|
iter::once(F32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f32_floor(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::FloorF32),
|
||||||
|
iter::once(F32),
|
||||||
|
iter::once(F32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f32_nearest(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::NearestF32),
|
||||||
|
iter::once(F32),
|
||||||
|
iter::once(F32),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
commutative_binop_f64!(f64_add, addsd, |a, b| a + b);
|
commutative_binop_f64!(f64_add, addsd, |a, b| a + b);
|
||||||
commutative_binop_f64!(f64_mul, mulsd, |a, b| a * b);
|
commutative_binop_f64!(f64_mul, mulsd, |a, b| a * b);
|
||||||
|
commutative_binop_f64!(f64_min, minsd, f64::min);
|
||||||
|
commutative_binop_f64!(f64_max, maxsd, f64::max);
|
||||||
binop_f64!(f64_sub, subsd, |a, b| a - b);
|
binop_f64!(f64_sub, subsd, |a, b| a - b);
|
||||||
binop_f64!(f64_div, divsd, |a, b| a / b);
|
binop_f64!(f64_div, divsd, |a, b| a / b);
|
||||||
|
|
||||||
|
pub fn f64_ceil(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::CeilF64),
|
||||||
|
iter::once(F64),
|
||||||
|
iter::once(F64),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f64_floor(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::FloorF64),
|
||||||
|
iter::once(F64),
|
||||||
|
iter::once(F64),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn f64_nearest(&mut self) {
|
||||||
|
self.relocated_function_call(
|
||||||
|
&ir::ExternalName::LibCall(ir::LibCall::NearestF64),
|
||||||
|
iter::once(F64),
|
||||||
|
iter::once(F64),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
shift!(
|
shift!(
|
||||||
i32_shl,
|
i32_shl,
|
||||||
Rd,
|
Rd,
|
||||||
@@ -3572,37 +3733,27 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
/// conditional traps in `call_indirect` use)
|
/// conditional traps in `call_indirect` use)
|
||||||
pub fn epilogue(&mut self) {
|
pub fn epilogue(&mut self) {
|
||||||
// TODO: We don't want to redefine this label if we're sharing it between functions
|
// TODO: We don't want to redefine this label if we're sharing it between functions
|
||||||
if let Some(l) = self
|
if let Some(l) = self.labels.trap.as_ref().and_then(Pending::as_undefined) {
|
||||||
.labels
|
|
||||||
.trap
|
|
||||||
.as_ref()
|
|
||||||
.and_then(PendingLabel::as_undefined)
|
|
||||||
{
|
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
dynasm!(self.asm
|
dynasm!(self.asm
|
||||||
; ud2
|
; ud2
|
||||||
);
|
);
|
||||||
self.labels.trap = Some(PendingLabel::defined(l));
|
self.labels.trap = Some(Pending::defined(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = self
|
if let Some(l) = self.labels.ret.as_ref().and_then(Pending::as_undefined) {
|
||||||
.labels
|
|
||||||
.ret
|
|
||||||
.as_ref()
|
|
||||||
.and_then(PendingLabel::as_undefined)
|
|
||||||
{
|
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
dynasm!(self.asm
|
dynasm!(self.asm
|
||||||
; ret
|
; ret
|
||||||
);
|
);
|
||||||
self.labels.ret = Some(PendingLabel::defined(l));
|
self.labels.ret = Some(Pending::defined(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = self
|
if let Some(l) = self
|
||||||
.labels
|
.labels
|
||||||
.neg_const_f32
|
.neg_const_f32
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(PendingLabel::as_undefined)
|
.and_then(Pending::as_undefined)
|
||||||
{
|
{
|
||||||
self.align(16);
|
self.align(16);
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
@@ -3612,14 +3763,14 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
; .dword 0
|
; .dword 0
|
||||||
; .dword 0
|
; .dword 0
|
||||||
);
|
);
|
||||||
self.labels.neg_const_f32 = Some(PendingLabel::defined(l));
|
self.labels.neg_const_f32 = Some(Pending::defined(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = self
|
if let Some(l) = self
|
||||||
.labels
|
.labels
|
||||||
.neg_const_f64
|
.neg_const_f64
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(PendingLabel::as_undefined)
|
.and_then(Pending::as_undefined)
|
||||||
{
|
{
|
||||||
self.align(16);
|
self.align(16);
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
@@ -3629,14 +3780,14 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
; .dword 0
|
; .dword 0
|
||||||
; .dword 0
|
; .dword 0
|
||||||
);
|
);
|
||||||
self.labels.neg_const_f64 = Some(PendingLabel::defined(l));
|
self.labels.neg_const_f64 = Some(Pending::defined(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = self
|
if let Some(l) = self
|
||||||
.labels
|
.labels
|
||||||
.abs_const_f32
|
.abs_const_f32
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(PendingLabel::as_undefined)
|
.and_then(Pending::as_undefined)
|
||||||
{
|
{
|
||||||
self.align(16);
|
self.align(16);
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
@@ -3646,14 +3797,14 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
; .dword 2147483647
|
; .dword 2147483647
|
||||||
; .dword 2147483647
|
; .dword 2147483647
|
||||||
);
|
);
|
||||||
self.labels.abs_const_f32 = Some(PendingLabel::defined(l));
|
self.labels.abs_const_f32 = Some(Pending::defined(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(l) = self
|
if let Some(l) = self
|
||||||
.labels
|
.labels
|
||||||
.abs_const_f64
|
.abs_const_f64
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(PendingLabel::as_undefined)
|
.and_then(Pending::as_undefined)
|
||||||
{
|
{
|
||||||
self.align(16);
|
self.align(16);
|
||||||
self.define_label(l);
|
self.define_label(l);
|
||||||
@@ -3661,7 +3812,51 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
; .qword 9223372036854775807
|
; .qword 9223372036854775807
|
||||||
; .qword 9223372036854775807
|
; .qword 9223372036854775807
|
||||||
);
|
);
|
||||||
self.labels.abs_const_f64 = Some(PendingLabel::defined(l));
|
self.labels.abs_const_f64 = Some(Pending::defined(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((neg_zero, nan)) = self
|
||||||
|
.labels
|
||||||
|
.copysign_consts_f32
|
||||||
|
.as_ref()
|
||||||
|
.and_then(Pending::as_undefined)
|
||||||
|
{
|
||||||
|
self.align(16);
|
||||||
|
self.define_label(neg_zero);
|
||||||
|
dynasm!(self.asm
|
||||||
|
; .dword -2147483647
|
||||||
|
; .dword -2147483647
|
||||||
|
; .dword -2147483647
|
||||||
|
; .dword -2147483647
|
||||||
|
);
|
||||||
|
self.define_label(nan);
|
||||||
|
dynasm!(self.asm
|
||||||
|
; .dword 2147483647
|
||||||
|
; .dword 2147483647
|
||||||
|
; .dword 2147483647
|
||||||
|
; .dword 2147483647
|
||||||
|
);
|
||||||
|
self.labels.copysign_consts_f32 = Some(Pending::defined((neg_zero, nan)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((neg_zero, nan)) = self
|
||||||
|
.labels
|
||||||
|
.copysign_consts_f64
|
||||||
|
.as_ref()
|
||||||
|
.and_then(Pending::as_undefined)
|
||||||
|
{
|
||||||
|
self.align(16);
|
||||||
|
self.define_label(neg_zero);
|
||||||
|
dynasm!(self.asm
|
||||||
|
; .qword -9223372036854775808
|
||||||
|
; .qword -9223372036854775808
|
||||||
|
);
|
||||||
|
self.define_label(nan);
|
||||||
|
dynasm!(self.asm
|
||||||
|
; .qword 9223372036854775807
|
||||||
|
; .qword 9223372036854775807
|
||||||
|
);
|
||||||
|
self.labels.copysign_consts_f64 = Some(Pending::defined((neg_zero, nan)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3743,5 +3938,31 @@ impl<'module, M: ModuleContext> Context<'module, M> {
|
|||||||
self.labels.abs_const_f64 = Some(label.into());
|
self.labels.abs_const_f64 = Some(label.into());
|
||||||
label
|
label
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn copysign_consts_f32_labels(&mut self) -> (Label, Label) {
|
||||||
|
if let Some(l) = &self.labels.copysign_consts_f32 {
|
||||||
|
return l.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
let neg_zero = self.create_label();
|
||||||
|
let nan = self.create_label();
|
||||||
|
let labels = (neg_zero, nan);
|
||||||
|
self.labels.copysign_consts_f32 = Some(labels.into());
|
||||||
|
labels
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn copysign_consts_f64_labels(&mut self) -> (Label, Label) {
|
||||||
|
if let Some(l) = &self.labels.copysign_consts_f64 {
|
||||||
|
return l.label;
|
||||||
|
}
|
||||||
|
|
||||||
|
let neg_zero = self.create_label();
|
||||||
|
let nan = self.create_label();
|
||||||
|
let labels = (neg_zero, nan);
|
||||||
|
self.labels.copysign_consts_f32 = Some(labels.into());
|
||||||
|
labels
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -457,8 +457,15 @@ where
|
|||||||
Operator::Mul(F32) => ctx.f32_mul(),
|
Operator::Mul(F32) => ctx.f32_mul(),
|
||||||
Operator::Sub(F32) => ctx.f32_sub(),
|
Operator::Sub(F32) => ctx.f32_sub(),
|
||||||
Operator::Div(SF32) => ctx.f32_div(),
|
Operator::Div(SF32) => ctx.f32_div(),
|
||||||
|
Operator::Min(Size::_32) => ctx.f32_min(),
|
||||||
|
Operator::Max(Size::_32) => ctx.f32_max(),
|
||||||
|
Operator::Copysign(Size::_32) => ctx.f32_copysign(),
|
||||||
|
Operator::Sqrt(Size::_32) => ctx.f32_sqrt(),
|
||||||
Operator::Neg(Size::_32) => ctx.f32_neg(),
|
Operator::Neg(Size::_32) => ctx.f32_neg(),
|
||||||
Operator::Abs(Size::_32) => ctx.f32_abs(),
|
Operator::Abs(Size::_32) => ctx.f32_abs(),
|
||||||
|
Operator::Floor(Size::_32) => ctx.f32_floor(),
|
||||||
|
Operator::Ceil(Size::_32) => ctx.f32_ceil(),
|
||||||
|
Operator::Nearest(Size::_32) => ctx.f32_nearest(),
|
||||||
Operator::Eq(F32) => ctx.f32_eq(),
|
Operator::Eq(F32) => ctx.f32_eq(),
|
||||||
Operator::Ne(F32) => ctx.f32_ne(),
|
Operator::Ne(F32) => ctx.f32_ne(),
|
||||||
Operator::Gt(SF32) => ctx.f32_gt(),
|
Operator::Gt(SF32) => ctx.f32_gt(),
|
||||||
@@ -469,8 +476,15 @@ where
|
|||||||
Operator::Mul(F64) => ctx.f64_mul(),
|
Operator::Mul(F64) => ctx.f64_mul(),
|
||||||
Operator::Sub(F64) => ctx.f64_sub(),
|
Operator::Sub(F64) => ctx.f64_sub(),
|
||||||
Operator::Div(SF64) => ctx.f64_div(),
|
Operator::Div(SF64) => ctx.f64_div(),
|
||||||
|
Operator::Min(Size::_64) => ctx.f64_min(),
|
||||||
|
Operator::Max(Size::_64) => ctx.f64_max(),
|
||||||
|
Operator::Copysign(Size::_64) => ctx.f64_copysign(),
|
||||||
|
Operator::Sqrt(Size::_64) => ctx.f64_sqrt(),
|
||||||
Operator::Neg(Size::_64) => ctx.f64_neg(),
|
Operator::Neg(Size::_64) => ctx.f64_neg(),
|
||||||
Operator::Abs(Size::_64) => ctx.f64_abs(),
|
Operator::Abs(Size::_64) => ctx.f64_abs(),
|
||||||
|
Operator::Floor(Size::_64) => ctx.f64_floor(),
|
||||||
|
Operator::Ceil(Size::_64) => ctx.f64_ceil(),
|
||||||
|
Operator::Nearest(Size::_64) => ctx.f64_nearest(),
|
||||||
Operator::Eq(F64) => ctx.f64_eq(),
|
Operator::Eq(F64) => ctx.f64_eq(),
|
||||||
Operator::Ne(F64) => ctx.f64_ne(),
|
Operator::Ne(F64) => ctx.f64_ne(),
|
||||||
Operator::Gt(SF64) => ctx.f64_gt(),
|
Operator::Gt(SF64) => ctx.f64_gt(),
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
alloc_layout_extra,
|
alloc_layout_extra,
|
||||||
try_from,
|
try_from,
|
||||||
try_trait,
|
try_trait,
|
||||||
bind_by_move_pattern_guards
|
bind_by_move_pattern_guards,
|
||||||
|
copysign
|
||||||
)]
|
)]
|
||||||
#![plugin(dynasm)]
|
#![plugin(dynasm)]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user