diff --git a/cranelift/filetests/filetests/runtests/fmax-pseudo.clif b/cranelift/filetests/filetests/runtests/fmax-pseudo.clif new file mode 100644 index 0000000000..acd7b290dd --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fmax-pseudo.clif @@ -0,0 +1,107 @@ +test interpret +test run +target x86_64 +target aarch64 + +function %fmax_p_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fmax_pseudo v0, v1 + return v2 +} +; run: %fmax_p_f32(0x1.0, 0x2.0) == 0x2.0 +; run: %fmax_p_f32(0x1.0p10, 0x1.0p11) == 0x1.0p11 + +; run: %fmax_p_f32(0x0.0, -0x0.0) == 0x0.0 +; run: %fmax_p_f32(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmax_p_f32(+Inf, 0x0.0) == +Inf +; run: %fmax_p_f32(0x0.0, +Inf) == +Inf +; run: %fmax_p_f32(-Inf, 0x0.0) == 0x0.0 +; run: %fmax_p_f32(0x0.0, -Inf) == 0x0.0 +; run: %fmax_p_f32(+Inf, -Inf) == +Inf + +; F32 Epsilon / Max / Min Positive +; run: %fmax_p_f32(0x1.000002p-23, 0x1.000000p-23) == 0x1.000002p-23 +; run: %fmax_p_f32(0x1.fffffcp127, 0x1.fffffep127) == 0x1.fffffep127 +; run: %fmax_p_f32(0x1.000000p-126, 0x1.000000p-126) == 0x1.000000p-126 + +; F32 Subnormals +; run: %fmax_p_f32(0x0.800002p-126, 0x0.800000p-126) == 0x0.800002p-126 +; run: %fmax_p_f32(-0x0.800002p-126, -0x0.800000p-126) == -0x0.800000p-126 + +; F32 NaN's +; fmax_pseudo returns the first argument if the second is NaN +; Returns a NaN otherwise + +; run: %fmax_p_f32(0x0.0, +NaN) == 0x0.0 +; run: %fmax_p_f32(0x0.0, +NaN:0x0) == 0x0.0 +; run: %fmax_p_f32(0x0.0, +NaN:0x1) == 0x0.0 +; run: %fmax_p_f32(0x0.0, +NaN:0x300001) == 0x0.0 +; run: %fmax_p_f32(0x0.0, +sNaN:0x1) == 0x0.0 +; run: %fmax_p_f32(0x0.0, +sNaN:0x200001) == 0x0.0 + +function %fmax_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fmax_pseudo v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmax_is_nan_f32(-NaN, 0x0.0) == 1 +; run: %fmax_is_nan_f32(-NaN:0x0, 0x0.0) == 1 +; run: %fmax_is_nan_f32(-NaN:0x1, 0x0.0) == 1 +; run: %fmax_is_nan_f32(-NaN:0x300001, 0x0.0) == 1 +; run: %fmax_is_nan_f32(-sNaN:0x1, 0x0.0) == 1 +; run: %fmax_is_nan_f32(-sNaN:0x200001, 0x0.0) == 1 + + + +function %fmax_p_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fmax_pseudo v0, v1 + return v2 +} +; run: %fmax_p_f64(0x1.0, 0x2.0) == 0x2.0 +; run: %fmax_p_f64(0x1.0p10, 0x1.0p11) == 0x1.0p11 + +; run: %fmax_p_f64(0x0.0, -0x0.0) == 0x0.0 +; run: %fmax_p_f64(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmax_p_f64(+Inf, 0x0.0) == +Inf +; run: %fmax_p_f64(0x0.0, +Inf) == +Inf +; run: %fmax_p_f64(-Inf, 0x0.0) == 0x0.0 +; run: %fmax_p_f64(0x0.0, -Inf) == 0x0.0 +; run: %fmax_p_f64(+Inf, -Inf) == +Inf + +; F64 Epsilon / Max / Min Positive +; run: %fmax_p_f64(0x1.0000000000002p-52, 0x1.0000000000000p-52) == 0x1.0000000000002p-52 +; run: %fmax_p_f64(0x1.ffffffffffffcp1023, 0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023 +; run: %fmax_p_f64(0x1.0000000000000p-1022, 0x1.0000000000000p-1022) == 0x1.0000000000000p-1022 + +; F64 Subnormals +; run: %fmax_p_f64(0x0.8000000000002p-1022, 0x0.8000000000000p-1022) == 0x0.8000000000002p-1022 +; run: %fmax_p_f64(-0x0.8000000000002p-1022, -0x0.8000000000000p-1022) == -0x0.8000000000000p-1022 + + + +; F64 NaN's +; fmax_pseudo returns the first argument if the second is NaN +; Returns a NaN otherwise +; run: %fmax_p_f64(0x0.0, +NaN) == 0x0.0 +; run: %fmax_p_f64(0x0.0, +NaN:0x0) == 0x0.0 +; run: %fmax_p_f64(0x0.0, +NaN:0x1) == 0x0.0 +; run: %fmax_p_f64(0x0.0, +NaN:0x4000000000001) == 0x0.0 +; run: %fmax_p_f64(0x0.0, +sNaN:0x4000000000001) == 0x0.0 +; run: %fmax_p_f64(0x0.0, +sNaN:0x1) == 0x0.0 + +function %fmax_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fmax_pseudo v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmax_is_nan_f64(-NaN, 0x0.0) == 1 +; run: %fmax_is_nan_f64(-NaN:0x0, 0x0.0) == 1 +; run: %fmax_is_nan_f64(-NaN:0x1, 0x0.0) == 1 +; run: %fmax_is_nan_f64(-NaN:0x4000000000001, 0x0.0) == 1 +; run: %fmax_is_nan_f64(-sNaN:0x1, 0x0.0) == 1 +; run: %fmax_is_nan_f64(-sNaN:0x4000000000001, 0x0.0) == 1 diff --git a/cranelift/filetests/filetests/runtests/fmin-max-pseudo.clif b/cranelift/filetests/filetests/runtests/fmin-max-pseudo.clif deleted file mode 100644 index 628dcc15a9..0000000000 --- a/cranelift/filetests/filetests/runtests/fmin-max-pseudo.clif +++ /dev/null @@ -1,50 +0,0 @@ -test run -; target s390x TODO: Not yet implemented on s390x -target aarch64 -set enable_simd -target x86_64 skylake - -function %fmin_pseudo_f32(f32, f32) -> f32 { -block0(v0:f32, v1:f32): - v2 = fmin_pseudo v0, v1 - return v2 -} -; run: %fmin_pseudo_f32(0x1.0, 0x2.0) == 0x1.0 -; run: %fmin_pseudo_f32(NaN, 0x2.0) == NaN -; run: %fmin_pseudo_f32(0x0.1, NaN) == 0x0.1 -; run: %fmin_pseudo_f32(0x0.0, -0x0.0) == 0x0.0 -; run: %fmin_pseudo_f32(-0x0.0, 0x0.0) == -0x0.0 - -function %fmax_pseudo_f32(f32, f32) -> f32 { -block0(v0:f32, v1:f32): - v2 = fmax_pseudo v0, v1 - return v2 -} -; run: %fmax_pseudo_f32(0x1.0, 0x2.0) == 0x2.0 -; run: %fmax_pseudo_f32(NaN, 0x2.0) == NaN -; run: %fmax_pseudo_f32(0x0.1, NaN) == 0x0.1 -; run: %fmax_pseudo_f32(0x0.0, 0x0.0) == 0x0.0 -; run: %fmax_pseudo_f32(-0x0.0, 0x0.0) == -0x0.0 - -function %fmin_pseudo_f64(f64, f64) -> f64 { -block0(v0:f64, v1:f64): - v2 = fmin_pseudo v0, v1 - return v2 -} -; run: %fmin_pseudo_f64(0x1.0, 0x2.0) == 0x1.0 -; run: %fmin_pseudo_f64(NaN, 0x2.0) == NaN -; run: %fmin_pseudo_f64(0x0.1, NaN) == 0x0.1 -; run: %fmin_pseudo_f64(0x0.0, -0x0.0) == 0x0.0 -; run: %fmin_pseudo_f64(-0x0.0, 0x0.0) == -0x0.0 - -function %fmax_pseudo_f64(f64, f64) -> f64 { -block0(v0:f64, v1:f64): - v2 = fmax_pseudo v0, v1 - return v2 -} -; run: %fmax_pseudo_f64(0x1.0, 0x2.0) == 0x2.0 -; run: %fmax_pseudo_f64(NaN, 0x2.0) == NaN -; run: %fmax_pseudo_f64(0x0.1, NaN) == 0x0.1 -; run: %fmax_pseudo_f64(0x0.0, 0x0.0) == 0x0.0 -; run: %fmax_pseudo_f64(-0x0.0, 0x0.0) == -0x0.0 - diff --git a/cranelift/filetests/filetests/runtests/fmin-pseudo.clif b/cranelift/filetests/filetests/runtests/fmin-pseudo.clif new file mode 100644 index 0000000000..fc88e34611 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/fmin-pseudo.clif @@ -0,0 +1,107 @@ +test interpret +test run +target x86_64 +target aarch64 + +function %fmin_p_f32(f32, f32) -> f32 { +block0(v0: f32, v1: f32): + v2 = fmin_pseudo v0, v1 + return v2 +} +; run: %fmin_p_f32(0x1.0, 0x2.0) == 0x1.0 +; run: %fmin_p_f32(0x1.0p10, 0x1.0p11) == 0x1.0p10 + +; run: %fmin_p_f32(0x0.0, -0x0.0) == 0x0.0 +; run: %fmin_p_f32(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmin_p_f32(+Inf, 0x0.0) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +Inf) == 0x0.0 +; run: %fmin_p_f32(-Inf, 0x0.0) == -Inf +; run: %fmin_p_f32(0x0.0, -Inf) == -Inf +; run: %fmin_p_f32(+Inf, -Inf) == -Inf + +; F32 Epsilon / Max / Min Positive +; run: %fmin_p_f32(0x1.000002p-23, 0x1.000000p-23) == 0x1.000000p-23 +; run: %fmin_p_f32(0x1.fffffcp127, 0x1.fffffep127) == 0x1.fffffcp127 +; run: %fmin_p_f32(0x1.000000p-126, 0x1.000000p-126) == 0x1.000000p-126 + +; F32 Subnormals +; run: %fmin_p_f32(0x0.800002p-126, 0x0.800000p-126) == 0x0.800000p-126 +; run: %fmin_p_f32(-0x0.800002p-126, -0x0.800000p-126) == -0x0.800002p-126 + +; F32 NaN's +; fmin_pseudo returns the first argument if the second is NaN +; Returns a NaN otherwise + +; run: %fmin_p_f32(0x0.0, +NaN) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +NaN:0x0) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +NaN:0x1) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +NaN:0x300001) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +sNaN:0x1) == 0x0.0 +; run: %fmin_p_f32(0x0.0, +sNaN:0x200001) == 0x0.0 + +function %fmin_is_nan_f32(f32, f32) -> i32 { +block0(v0: f32, v1: f32): + v2 = fmin_pseudo v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmin_is_nan_f32(-NaN, 0x0.0) == 1 +; run: %fmin_is_nan_f32(-NaN:0x0, 0x0.0) == 1 +; run: %fmin_is_nan_f32(-NaN:0x1, 0x0.0) == 1 +; run: %fmin_is_nan_f32(-NaN:0x300001, 0x0.0) == 1 +; run: %fmin_is_nan_f32(-sNaN:0x1, 0x0.0) == 1 +; run: %fmin_is_nan_f32(-sNaN:0x200001, 0x0.0) == 1 + + + +function %fmin_p_f64(f64, f64) -> f64 { +block0(v0: f64, v1: f64): + v2 = fmin_pseudo v0, v1 + return v2 +} +; run: %fmin_p_f64(0x1.0, 0x2.0) == 0x1.0 +; run: %fmin_p_f64(0x1.0p10, 0x1.0p11) == 0x1.0p10 + +; run: %fmin_p_f64(0x0.0, -0x0.0) == 0x0.0 +; run: %fmin_p_f64(-0x0.0, 0x0.0) == -0x0.0 +; run: %fmin_p_f64(+Inf, 0x0.0) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +Inf) == 0x0.0 +; run: %fmin_p_f64(-Inf, 0x0.0) == -Inf +; run: %fmin_p_f64(0x0.0, -Inf) == -Inf +; run: %fmin_p_f64(+Inf, -Inf) == -Inf + +; F64 Epsilon / Max / Min Positive +; run: %fmin_p_f64(0x1.0000000000002p-52, 0x1.0000000000000p-52) == 0x1.0000000000000p-52 +; run: %fmin_p_f64(0x1.ffffffffffffcp1023, 0x1.fffffffffffffp1023) == 0x1.ffffffffffffcp1023 +; run: %fmin_p_f64(0x1.0000000000000p-1022, 0x1.0000000000000p-1022) == 0x1.0000000000000p-1022 + +; F64 Subnormals +; run: %fmin_p_f64(0x0.8000000000002p-1022, 0x0.8000000000000p-1022) == 0x0.8000000000000p-1022 +; run: %fmin_p_f64(-0x0.8000000000002p-1022, -0x0.8000000000000p-1022) == -0x0.8000000000002p-1022 + + + +; F64 NaN's +; fmin_pseudo returns the first argument if the second is NaN +; Returns a NaN otherwise +; run: %fmin_p_f64(0x0.0, +NaN) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +NaN:0x0) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +NaN:0x1) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +NaN:0x4000000000001) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +sNaN:0x4000000000001) == 0x0.0 +; run: %fmin_p_f64(0x0.0, +sNaN:0x1) == 0x0.0 + +function %fmin_is_nan_f64(f64, f64) -> i32 { +block0(v0: f64, v1: f64): + v2 = fmin_pseudo v0, v1 + v3 = fcmp ne v2, v2 + v4 = bint.i32 v3 + return v4 +} +; run: %fmin_is_nan_f64(-NaN, 0x0.0) == 1 +; run: %fmin_is_nan_f64(-NaN:0x0, 0x0.0) == 1 +; run: %fmin_is_nan_f64(-NaN:0x1, 0x0.0) == 1 +; run: %fmin_is_nan_f64(-NaN:0x4000000000001, 0x0.0) == 1 +; run: %fmin_is_nan_f64(-sNaN:0x1, 0x0.0) == 1 +; run: %fmin_is_nan_f64(-sNaN:0x4000000000001, 0x0.0) == 1 diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index cf045673f8..3f416ce21e 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -705,7 +705,11 @@ where (a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => b, (a, b) => a.min(b)?, }), - Opcode::FminPseudo => unimplemented!("FminPseudo"), + Opcode::FminPseudo => assign(match (arg(0)?, arg(1)?) { + (a, b) if a.is_nan()? || b.is_nan()? => a, + (a, b) if a.is_zero()? && b.is_zero()? => a, + (a, b) => a.min(b)?, + }), Opcode::Fmax => assign(match (arg(0)?, arg(1)?) { (a, _) if a.is_nan()? => a, (_, b) if b.is_nan()? => b, @@ -713,7 +717,11 @@ where (a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => a, (a, b) => a.max(b)?, }), - Opcode::FmaxPseudo => unimplemented!("FmaxPseudo"), + Opcode::FmaxPseudo => assign(match (arg(0)?, arg(1)?) { + (a, b) if a.is_nan()? || b.is_nan()? => a, + (a, b) if a.is_zero()? && b.is_zero()? => a, + (a, b) => a.max(b)?, + }), Opcode::Ceil => unimplemented!("Ceil"), Opcode::Floor => unimplemented!("Floor"), Opcode::Trunc => unimplemented!("Trunc"),