From 1a7f00f0afe9f4756f6e5d236218143dc8377015 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Thu, 3 Oct 2019 18:19:12 -0700 Subject: [PATCH 1/3] Rewrite Min/Max to handle all cases correctly. Fixes 545 spectest failures. --- lib/llvm-backend/src/code.rs | 374 +++++++++++++++++--- lib/llvm-backend/src/intrinsics.rs | 10 +- lib/spectests/tests/excludes.txt | 548 ----------------------------- 3 files changed, 343 insertions(+), 589 deletions(-) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index 8ac76fe269b..a1c69c08262 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2693,31 +2693,139 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { } Operator::F32Min => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f32_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F64Min => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.minimum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = intrinsics.f64_ty.const_float(-0.0); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F32x4Min => { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } @@ -2725,41 +2833,187 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.minimum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OLT, v1, v2, ""); + let negative_zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_ty.const_float(-0.0).as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + negative_zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } Operator::F32Max => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f32, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f32_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F64Max => { let (v1, v2) = state.pop2()?; - let res = builder - .build_call(intrinsics.maximum_f64, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64_ty, "") + .into_int_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64_ty, "") + .into_int_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + intrinsics.f64_zero, + v2, + "", + ) + .into_float_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); state.push1(res); } Operator::F32x4Max => { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f32x4, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f32x4_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f32x4_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i32x4_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i32x4_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f32_zero.as_basic_value_enum(), + intrinsics.f32x4_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } @@ -2767,11 +3021,51 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); - let res = builder - .build_call(intrinsics.maximum_f64x2, &[v1, v2], &state.var_name()) - .try_as_basic_value() - .left() - .unwrap(); + let v1 = canonicalize_nans(builder, intrinsics, v1); + let v2 = canonicalize_nans(builder, intrinsics, v2); + let (v1, v2) = (v1.into_vector_value(), v2.into_vector_value()); + let v1_is_nan = builder.build_float_compare( + FloatPredicate::UNO, + v1, + intrinsics.f64x2_zero, + "nan", + ); + let v2_is_not_nan = builder.build_float_compare( + FloatPredicate::ORD, + v2, + intrinsics.f64x2_zero, + "notnan", + ); + let v1_repr = builder + .build_bitcast(v1, intrinsics.i64x2_ty, "") + .into_vector_value(); + let v2_repr = builder + .build_bitcast(v2, intrinsics.i64x2_ty, "") + .into_vector_value(); + let repr_ne = builder.build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); + let float_eq = builder.build_float_compare(FloatPredicate::OEQ, v1, v2, ""); + let min_cmp = builder.build_float_compare(FloatPredicate::OGT, v1, v2, ""); + let zero = splat_vector( + builder, + intrinsics, + intrinsics.f64_zero.as_basic_value_enum(), + intrinsics.f64x2_ty, + "", + ); + let v2 = builder + .build_select( + builder.build_and( + builder.build_and(float_eq, repr_ne, ""), + v2_is_not_nan, + "", + ), + zero, + v2, + "", + ) + .into_vector_value(); + let res = + builder.build_select(builder.build_or(v1_is_nan, min_cmp, ""), v1, v2, ""); let res = builder.build_bitcast(res, intrinsics.i128_ty, ""); state.push1(res); } diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs index 278e087bb41..afd3bf8ad2a 100644 --- a/lib/llvm-backend/src/intrinsics.rs +++ b/lib/llvm-backend/src/intrinsics.rs @@ -6,7 +6,9 @@ use inkwell::{ types::{ BasicType, FloatType, FunctionType, IntType, PointerType, StructType, VectorType, VoidType, }, - values::{BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue}, + values::{ + BasicValue, BasicValueEnum, FloatValue, FunctionValue, IntValue, PointerValue, VectorValue, + }, AddressSpace, }; use std::collections::HashMap; @@ -125,6 +127,8 @@ pub struct Intrinsics { pub i128_zero: IntValue, pub f32_zero: FloatValue, pub f64_zero: FloatValue, + pub f32x4_zero: VectorValue, + pub f64x2_zero: VectorValue, pub trap_unreachable: BasicValueEnum, pub trap_call_indirect_sig: BasicValueEnum, @@ -191,6 +195,8 @@ impl Intrinsics { let i128_zero = i128_ty.const_int(0, false); let f32_zero = f32_ty.const_float(0.0); let f64_zero = f64_ty.const_float(0.0); + let f32x4_zero = f32x4_ty.const_zero(); + let f64x2_zero = f64x2_ty.const_zero(); let i1_ty_basic = i1_ty.as_basic_type_enum(); let i32_ty_basic = i32_ty.as_basic_type_enum(); @@ -455,6 +461,8 @@ impl Intrinsics { i128_zero, f32_zero, f64_zero, + f32x4_zero, + f64x2_zero, trap_unreachable: i32_zero.as_basic_value_enum(), trap_call_indirect_sig: i32_ty.const_int(1, false).as_basic_value_enum(), diff --git a/lib/spectests/tests/excludes.txt b/lib/spectests/tests/excludes.txt index 56c6a2d5613..cb641ea5361 100644 --- a/lib/spectests/tests/excludes.txt +++ b/lib/spectests/tests/excludes.txt @@ -265,554 +265,6 @@ clif:fail:data.wast:266:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:186:windows # AssertUnlinkable - caught panic Any clif:fail:data.wast:194:windows # AssertUnlinkable - caught panic Any -# LLVM bug with min/max over NaNs -llvm:skip:f32.wast:1651 -llvm:skip:f32.wast:1652 -llvm:skip:f32.wast:1653 -llvm:skip:f32.wast:1654 -llvm:skip:f32.wast:1655 -llvm:skip:f32.wast:1656 -llvm:skip:f32.wast:1657 -llvm:skip:f32.wast:1658 -llvm:skip:f32.wast:1691 -llvm:skip:f32.wast:1692 -llvm:skip:f32.wast:1693 -llvm:skip:f32.wast:1694 -llvm:skip:f32.wast:1695 -llvm:skip:f32.wast:1696 -llvm:skip:f32.wast:1697 -llvm:skip:f32.wast:1698 -llvm:skip:f32.wast:1731 -llvm:skip:f32.wast:1732 -llvm:skip:f32.wast:1733 -llvm:skip:f32.wast:1734 -llvm:skip:f32.wast:1735 -llvm:skip:f32.wast:1736 -llvm:skip:f32.wast:1737 -llvm:skip:f32.wast:1738 -llvm:skip:f32.wast:1771 -llvm:skip:f32.wast:1772 -llvm:skip:f32.wast:1773 -llvm:skip:f32.wast:1774 -llvm:skip:f32.wast:1775 -llvm:skip:f32.wast:1776 -llvm:skip:f32.wast:1777 -llvm:skip:f32.wast:1778 -llvm:skip:f32.wast:1811 -llvm:skip:f32.wast:1812 -llvm:skip:f32.wast:1813 -llvm:skip:f32.wast:1814 -llvm:skip:f32.wast:1815 -llvm:skip:f32.wast:1816 -llvm:skip:f32.wast:1817 -llvm:skip:f32.wast:1818 -llvm:skip:f32.wast:1851 -llvm:skip:f32.wast:1852 -llvm:skip:f32.wast:1853 -llvm:skip:f32.wast:1854 -llvm:skip:f32.wast:1855 -llvm:skip:f32.wast:1856 -llvm:skip:f32.wast:1857 -llvm:skip:f32.wast:1858 -llvm:skip:f32.wast:1891 -llvm:skip:f32.wast:1892 -llvm:skip:f32.wast:1893 -llvm:skip:f32.wast:1894 -llvm:skip:f32.wast:1895 -llvm:skip:f32.wast:1896 -llvm:skip:f32.wast:1897 -llvm:skip:f32.wast:1898 -llvm:skip:f32.wast:1931 -llvm:skip:f32.wast:1932 -llvm:skip:f32.wast:1933 -llvm:skip:f32.wast:1934 -llvm:skip:f32.wast:1935 -llvm:skip:f32.wast:1936 -llvm:skip:f32.wast:1937 -llvm:skip:f32.wast:1938 -llvm:skip:f32.wast:1939 -llvm:skip:f32.wast:1940 -llvm:skip:f32.wast:1941 -llvm:skip:f32.wast:1942 -llvm:skip:f32.wast:1943 -llvm:skip:f32.wast:1944 -llvm:skip:f32.wast:1945 -llvm:skip:f32.wast:1946 -llvm:skip:f32.wast:1947 -llvm:skip:f32.wast:1948 -llvm:skip:f32.wast:1949 -llvm:skip:f32.wast:1950 -llvm:skip:f32.wast:1951 -llvm:skip:f32.wast:1952 -llvm:skip:f32.wast:1953 -llvm:skip:f32.wast:1954 -llvm:skip:f32.wast:1955 -llvm:skip:f32.wast:1956 -llvm:skip:f32.wast:1957 -llvm:skip:f32.wast:1958 -llvm:skip:f32.wast:1959 -llvm:skip:f32.wast:1960 -llvm:skip:f32.wast:1961 -llvm:skip:f32.wast:1962 -llvm:skip:f32.wast:1963 -llvm:skip:f32.wast:1964 -llvm:skip:f32.wast:1965 -llvm:skip:f32.wast:1966 -llvm:skip:f32.wast:1967 -llvm:skip:f32.wast:1968 -llvm:skip:f32.wast:1969 -llvm:skip:f32.wast:1970 -llvm:skip:f32.wast:1971 -llvm:skip:f32.wast:1972 -llvm:skip:f32.wast:1973 -llvm:skip:f32.wast:1974 -llvm:skip:f32.wast:1975 -llvm:skip:f32.wast:1976 -llvm:skip:f32.wast:1977 -llvm:skip:f32.wast:1978 -llvm:skip:f32.wast:1979 -llvm:skip:f32.wast:1980 -llvm:skip:f32.wast:1981 -llvm:skip:f32.wast:1982 -llvm:skip:f32.wast:1983 -llvm:skip:f32.wast:1984 -llvm:skip:f32.wast:1985 -llvm:skip:f32.wast:1986 -llvm:skip:f32.wast:1987 -llvm:skip:f32.wast:1988 -llvm:skip:f32.wast:1989 -llvm:skip:f32.wast:1990 -llvm:skip:f32.wast:1991 -llvm:skip:f32.wast:1992 -llvm:skip:f32.wast:1993 -llvm:skip:f32.wast:1994 -llvm:skip:f32.wast:1995 -llvm:skip:f32.wast:1996 -llvm:skip:f32.wast:1997 -llvm:skip:f32.wast:1998 -llvm:skip:f32.wast:1999 -llvm:skip:f32.wast:2000 -llvm:skip:f32.wast:2001 -llvm:skip:f32.wast:2002 -llvm:skip:f32.wast:2005 -llvm:skip:f32.wast:2006 -llvm:skip:f32.wast:2009 -llvm:skip:f32.wast:2010 -llvm:skip:f32.wast:2013 -llvm:skip:f32.wast:2014 -llvm:skip:f32.wast:2017 -llvm:skip:f32.wast:2018 -llvm:skip:f32.wast:2051 -llvm:skip:f32.wast:2052 -llvm:skip:f32.wast:2053 -llvm:skip:f32.wast:2054 -llvm:skip:f32.wast:2055 -llvm:skip:f32.wast:2056 -llvm:skip:f32.wast:2057 -llvm:skip:f32.wast:2058 -llvm:skip:f32.wast:2091 -llvm:skip:f32.wast:2092 -llvm:skip:f32.wast:2093 -llvm:skip:f32.wast:2094 -llvm:skip:f32.wast:2095 -llvm:skip:f32.wast:2096 -llvm:skip:f32.wast:2097 -llvm:skip:f32.wast:2098 -llvm:skip:f32.wast:2131 -llvm:skip:f32.wast:2132 -llvm:skip:f32.wast:2133 -llvm:skip:f32.wast:2134 -llvm:skip:f32.wast:2135 -llvm:skip:f32.wast:2136 -llvm:skip:f32.wast:2137 -llvm:skip:f32.wast:2138 -llvm:skip:f32.wast:2171 -llvm:skip:f32.wast:2172 -llvm:skip:f32.wast:2173 -llvm:skip:f32.wast:2174 -llvm:skip:f32.wast:2175 -llvm:skip:f32.wast:2176 -llvm:skip:f32.wast:2177 -llvm:skip:f32.wast:2178 -llvm:skip:f32.wast:2211 -llvm:skip:f32.wast:2212 -llvm:skip:f32.wast:2213 -llvm:skip:f32.wast:2214 -llvm:skip:f32.wast:2215 -llvm:skip:f32.wast:2216 -llvm:skip:f32.wast:2217 -llvm:skip:f32.wast:2218 -llvm:skip:f32.wast:2251 -llvm:skip:f32.wast:2252 -llvm:skip:f32.wast:2253 -llvm:skip:f32.wast:2254 -llvm:skip:f32.wast:2255 -llvm:skip:f32.wast:2256 -llvm:skip:f32.wast:2257 -llvm:skip:f32.wast:2258 -llvm:skip:f32.wast:2291 -llvm:skip:f32.wast:2292 -llvm:skip:f32.wast:2293 -llvm:skip:f32.wast:2294 -llvm:skip:f32.wast:2295 -llvm:skip:f32.wast:2296 -llvm:skip:f32.wast:2297 -llvm:skip:f32.wast:2298 -llvm:skip:f32.wast:2331 -llvm:skip:f32.wast:2332 -llvm:skip:f32.wast:2333 -llvm:skip:f32.wast:2334 -llvm:skip:f32.wast:2335 -llvm:skip:f32.wast:2336 -llvm:skip:f32.wast:2337 -llvm:skip:f32.wast:2338 -llvm:skip:f32.wast:2339 -llvm:skip:f32.wast:2340 -llvm:skip:f32.wast:2341 -llvm:skip:f32.wast:2342 -llvm:skip:f32.wast:2343 -llvm:skip:f32.wast:2344 -llvm:skip:f32.wast:2345 -llvm:skip:f32.wast:2346 -llvm:skip:f32.wast:2347 -llvm:skip:f32.wast:2348 -llvm:skip:f32.wast:2349 -llvm:skip:f32.wast:2350 -llvm:skip:f32.wast:2351 -llvm:skip:f32.wast:2352 -llvm:skip:f32.wast:2353 -llvm:skip:f32.wast:2354 -llvm:skip:f32.wast:2355 -llvm:skip:f32.wast:2356 -llvm:skip:f32.wast:2357 -llvm:skip:f32.wast:2358 -llvm:skip:f32.wast:2359 -llvm:skip:f32.wast:2360 -llvm:skip:f32.wast:2361 -llvm:skip:f32.wast:2362 -llvm:skip:f32.wast:2363 -llvm:skip:f32.wast:2364 -llvm:skip:f32.wast:2365 -llvm:skip:f32.wast:2366 -llvm:skip:f32.wast:2367 -llvm:skip:f32.wast:2368 -llvm:skip:f32.wast:2369 -llvm:skip:f32.wast:2370 -llvm:skip:f32.wast:2371 -llvm:skip:f32.wast:2372 -llvm:skip:f32.wast:2373 -llvm:skip:f32.wast:2374 -llvm:skip:f32.wast:2375 -llvm:skip:f32.wast:2376 -llvm:skip:f32.wast:2377 -llvm:skip:f32.wast:2378 -llvm:skip:f32.wast:2379 -llvm:skip:f32.wast:2380 -llvm:skip:f32.wast:2381 -llvm:skip:f32.wast:2382 -llvm:skip:f32.wast:2383 -llvm:skip:f32.wast:2384 -llvm:skip:f32.wast:2385 -llvm:skip:f32.wast:2386 -llvm:skip:f32.wast:2387 -llvm:skip:f32.wast:2388 -llvm:skip:f32.wast:2389 -llvm:skip:f32.wast:2390 -llvm:skip:f32.wast:2391 -llvm:skip:f32.wast:2392 -llvm:skip:f32.wast:2393 -llvm:skip:f32.wast:2394 -llvm:skip:f32.wast:2395 -llvm:skip:f32.wast:2396 -llvm:skip:f32.wast:2397 -llvm:skip:f32.wast:2398 -llvm:skip:f32.wast:2399 -llvm:skip:f32.wast:2400 -llvm:skip:f32.wast:2401 -llvm:skip:f32.wast:2402 -llvm:skip:f32.wast:2403 -llvm:skip:f32.wast:2404 -llvm:skip:f32.wast:2405 -llvm:skip:f32.wast:2406 -llvm:skip:f32.wast:2409 -llvm:skip:f32.wast:2410 -llvm:skip:f32.wast:2413 -llvm:skip:f32.wast:2414 -llvm:skip:f32.wast:2417 -llvm:skip:f32.wast:2418 -llvm:skip:f64.wast:1651 -llvm:skip:f64.wast:1652 -llvm:skip:f64.wast:1653 -llvm:skip:f64.wast:1654 -llvm:skip:f64.wast:1655 -llvm:skip:f64.wast:1656 -llvm:skip:f64.wast:1657 -llvm:skip:f64.wast:1658 -llvm:skip:f64.wast:1691 -llvm:skip:f64.wast:1692 -llvm:skip:f64.wast:1693 -llvm:skip:f64.wast:1694 -llvm:skip:f64.wast:1695 -llvm:skip:f64.wast:1696 -llvm:skip:f64.wast:1697 -llvm:skip:f64.wast:1698 -llvm:skip:f64.wast:1731 -llvm:skip:f64.wast:1732 -llvm:skip:f64.wast:1733 -llvm:skip:f64.wast:1734 -llvm:skip:f64.wast:1735 -llvm:skip:f64.wast:1736 -llvm:skip:f64.wast:1737 -llvm:skip:f64.wast:1738 -llvm:skip:f64.wast:1771 -llvm:skip:f64.wast:1772 -llvm:skip:f64.wast:1773 -llvm:skip:f64.wast:1774 -llvm:skip:f64.wast:1775 -llvm:skip:f64.wast:1776 -llvm:skip:f64.wast:1777 -llvm:skip:f64.wast:1778 -llvm:skip:f64.wast:1811 -llvm:skip:f64.wast:1812 -llvm:skip:f64.wast:1813 -llvm:skip:f64.wast:1814 -llvm:skip:f64.wast:1815 -llvm:skip:f64.wast:1816 -llvm:skip:f64.wast:1817 -llvm:skip:f64.wast:1818 -llvm:skip:f64.wast:1851 -llvm:skip:f64.wast:1852 -llvm:skip:f64.wast:1853 -llvm:skip:f64.wast:1854 -llvm:skip:f64.wast:1855 -llvm:skip:f64.wast:1856 -llvm:skip:f64.wast:1857 -llvm:skip:f64.wast:1858 -llvm:skip:f64.wast:1891 -llvm:skip:f64.wast:1892 -llvm:skip:f64.wast:1893 -llvm:skip:f64.wast:1894 -llvm:skip:f64.wast:1895 -llvm:skip:f64.wast:1896 -llvm:skip:f64.wast:1897 -llvm:skip:f64.wast:1898 -llvm:skip:f64.wast:1931 -llvm:skip:f64.wast:1932 -llvm:skip:f64.wast:1933 -llvm:skip:f64.wast:1934 -llvm:skip:f64.wast:1935 -llvm:skip:f64.wast:1936 -llvm:skip:f64.wast:1937 -llvm:skip:f64.wast:1938 -llvm:skip:f64.wast:1939 -llvm:skip:f64.wast:1940 -llvm:skip:f64.wast:1941 -llvm:skip:f64.wast:1942 -llvm:skip:f64.wast:1943 -llvm:skip:f64.wast:1944 -llvm:skip:f64.wast:1945 -llvm:skip:f64.wast:1946 -llvm:skip:f64.wast:1947 -llvm:skip:f64.wast:1948 -llvm:skip:f64.wast:1949 -llvm:skip:f64.wast:1950 -llvm:skip:f64.wast:1951 -llvm:skip:f64.wast:1952 -llvm:skip:f64.wast:1953 -llvm:skip:f64.wast:1954 -llvm:skip:f64.wast:1955 -llvm:skip:f64.wast:1956 -llvm:skip:f64.wast:1957 -llvm:skip:f64.wast:1958 -llvm:skip:f64.wast:1959 -llvm:skip:f64.wast:1960 -llvm:skip:f64.wast:1961 -llvm:skip:f64.wast:1962 -llvm:skip:f64.wast:1963 -llvm:skip:f64.wast:1964 -llvm:skip:f64.wast:1965 -llvm:skip:f64.wast:1966 -llvm:skip:f64.wast:1967 -llvm:skip:f64.wast:1968 -llvm:skip:f64.wast:1969 -llvm:skip:f64.wast:1970 -llvm:skip:f64.wast:1971 -llvm:skip:f64.wast:1972 -llvm:skip:f64.wast:1973 -llvm:skip:f64.wast:1974 -llvm:skip:f64.wast:1975 -llvm:skip:f64.wast:1976 -llvm:skip:f64.wast:1977 -llvm:skip:f64.wast:1978 -llvm:skip:f64.wast:1979 -llvm:skip:f64.wast:1980 -llvm:skip:f64.wast:1981 -llvm:skip:f64.wast:1982 -llvm:skip:f64.wast:1983 -llvm:skip:f64.wast:1984 -llvm:skip:f64.wast:1985 -llvm:skip:f64.wast:1986 -llvm:skip:f64.wast:1987 -llvm:skip:f64.wast:1988 -llvm:skip:f64.wast:1989 -llvm:skip:f64.wast:1990 -llvm:skip:f64.wast:1991 -llvm:skip:f64.wast:1992 -llvm:skip:f64.wast:1993 -llvm:skip:f64.wast:1994 -llvm:skip:f64.wast:1995 -llvm:skip:f64.wast:1996 -llvm:skip:f64.wast:1997 -llvm:skip:f64.wast:1998 -llvm:skip:f64.wast:1999 -llvm:skip:f64.wast:2000 -llvm:skip:f64.wast:2001 -llvm:skip:f64.wast:2002 -llvm:skip:f64.wast:2005 -llvm:skip:f64.wast:2006 -llvm:skip:f64.wast:2009 -llvm:skip:f64.wast:2010 -llvm:skip:f64.wast:2013 -llvm:skip:f64.wast:2014 -llvm:skip:f64.wast:2017 -llvm:skip:f64.wast:2018 -llvm:skip:f64.wast:2051 -llvm:skip:f64.wast:2052 -llvm:skip:f64.wast:2053 -llvm:skip:f64.wast:2054 -llvm:skip:f64.wast:2055 -llvm:skip:f64.wast:2056 -llvm:skip:f64.wast:2057 -llvm:skip:f64.wast:2058 -llvm:skip:f64.wast:2091 -llvm:skip:f64.wast:2092 -llvm:skip:f64.wast:2093 -llvm:skip:f64.wast:2094 -llvm:skip:f64.wast:2095 -llvm:skip:f64.wast:2096 -llvm:skip:f64.wast:2097 -llvm:skip:f64.wast:2098 -llvm:skip:f64.wast:2131 -llvm:skip:f64.wast:2132 -llvm:skip:f64.wast:2133 -llvm:skip:f64.wast:2134 -llvm:skip:f64.wast:2135 -llvm:skip:f64.wast:2136 -llvm:skip:f64.wast:2137 -llvm:skip:f64.wast:2138 -llvm:skip:f64.wast:2171 -llvm:skip:f64.wast:2172 -llvm:skip:f64.wast:2173 -llvm:skip:f64.wast:2174 -llvm:skip:f64.wast:2175 -llvm:skip:f64.wast:2176 -llvm:skip:f64.wast:2177 -llvm:skip:f64.wast:2178 -llvm:skip:f64.wast:2211 -llvm:skip:f64.wast:2212 -llvm:skip:f64.wast:2213 -llvm:skip:f64.wast:2214 -llvm:skip:f64.wast:2215 -llvm:skip:f64.wast:2216 -llvm:skip:f64.wast:2217 -llvm:skip:f64.wast:2218 -llvm:skip:f64.wast:2251 -llvm:skip:f64.wast:2252 -llvm:skip:f64.wast:2253 -llvm:skip:f64.wast:2254 -llvm:skip:f64.wast:2255 -llvm:skip:f64.wast:2256 -llvm:skip:f64.wast:2257 -llvm:skip:f64.wast:2258 -llvm:skip:f64.wast:2291 -llvm:skip:f64.wast:2292 -llvm:skip:f64.wast:2293 -llvm:skip:f64.wast:2294 -llvm:skip:f64.wast:2295 -llvm:skip:f64.wast:2296 -llvm:skip:f64.wast:2297 -llvm:skip:f64.wast:2298 -llvm:skip:f64.wast:2331 -llvm:skip:f64.wast:2332 -llvm:skip:f64.wast:2333 -llvm:skip:f64.wast:2334 -llvm:skip:f64.wast:2335 -llvm:skip:f64.wast:2336 -llvm:skip:f64.wast:2337 -llvm:skip:f64.wast:2338 -llvm:skip:f64.wast:2339 -llvm:skip:f64.wast:2340 -llvm:skip:f64.wast:2341 -llvm:skip:f64.wast:2342 -llvm:skip:f64.wast:2343 -llvm:skip:f64.wast:2344 -llvm:skip:f64.wast:2345 -llvm:skip:f64.wast:2346 -llvm:skip:f64.wast:2347 -llvm:skip:f64.wast:2348 -llvm:skip:f64.wast:2349 -llvm:skip:f64.wast:2350 -llvm:skip:f64.wast:2351 -llvm:skip:f64.wast:2352 -llvm:skip:f64.wast:2353 -llvm:skip:f64.wast:2354 -llvm:skip:f64.wast:2355 -llvm:skip:f64.wast:2356 -llvm:skip:f64.wast:2357 -llvm:skip:f64.wast:2358 -llvm:skip:f64.wast:2359 -llvm:skip:f64.wast:2360 -llvm:skip:f64.wast:2361 -llvm:skip:f64.wast:2362 -llvm:skip:f64.wast:2363 -llvm:skip:f64.wast:2364 -llvm:skip:f64.wast:2365 -llvm:skip:f64.wast:2366 -llvm:skip:f64.wast:2367 -llvm:skip:f64.wast:2368 -llvm:skip:f64.wast:2369 -llvm:skip:f64.wast:2370 -llvm:skip:f64.wast:2371 -llvm:skip:f64.wast:2372 -llvm:skip:f64.wast:2373 -llvm:skip:f64.wast:2374 -llvm:skip:f64.wast:2375 -llvm:skip:f64.wast:2376 -llvm:skip:f64.wast:2377 -llvm:skip:f64.wast:2378 -llvm:skip:f64.wast:2379 -llvm:skip:f64.wast:2380 -llvm:skip:f64.wast:2381 -llvm:skip:f64.wast:2382 -llvm:skip:f64.wast:2383 -llvm:skip:f64.wast:2384 -llvm:skip:f64.wast:2385 -llvm:skip:f64.wast:2386 -llvm:skip:f64.wast:2387 -llvm:skip:f64.wast:2388 -llvm:skip:f64.wast:2389 -llvm:skip:f64.wast:2390 -llvm:skip:f64.wast:2391 -llvm:skip:f64.wast:2392 -llvm:skip:f64.wast:2393 -llvm:skip:f64.wast:2394 -llvm:skip:f64.wast:2395 -llvm:skip:f64.wast:2396 -llvm:skip:f64.wast:2397 -llvm:skip:f64.wast:2398 -llvm:skip:f64.wast:2399 -llvm:skip:f64.wast:2400 -llvm:skip:f64.wast:2401 -llvm:skip:f64.wast:2402 -llvm:skip:f64.wast:2405 -llvm:skip:f64.wast:2406 -llvm:skip:f64.wast:2409 -llvm:skip:f64.wast:2410 -llvm:skip:f64.wast:2413 -llvm:skip:f64.wast:2414 -llvm:skip:f64.wast:2417 -llvm:skip:f64.wast:2418 - # LLVM llvm:skip:br_table.wast:1255 llvm:skip:imports.wast:391 # Running forever From da0cfb8fc2b135a621d1b84763858e941bf50173 Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 11:36:38 -0700 Subject: [PATCH 2/3] Add changelog entry. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11365bb9c2..49d90aaae4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ Blocks of changes will separated by version increments. ## **[Unreleased]** +- [#863](https://github.com/wasmerio/wasmer/pull/863) Fix min and max for cases involving NaN and negative zero when using the LLVM backend. + ## 0.8.0 - 2019-10-02 Special thanks to @jdanford for their contributions! From 749691ca2ad79eda60a66527aac0aab0d6ed0a0f Mon Sep 17 00:00:00 2001 From: Nick Lewycky Date: Fri, 4 Oct 2019 11:50:11 -0700 Subject: [PATCH 3/3] Add a comment explaining why we don't use the intrinsics for these. --- lib/llvm-backend/src/code.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs index a1c69c08262..13dcd2bd9b3 100644 --- a/lib/llvm-backend/src/code.rs +++ b/lib/llvm-backend/src/code.rs @@ -2692,6 +2692,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(bits); } Operator::F32Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2735,6 +2738,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2778,6 +2784,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); @@ -2830,6 +2839,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64x2Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, ""); @@ -2882,6 +2894,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2924,6 +2939,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = canonicalize_nans(builder, intrinsics, v1); let v2 = canonicalize_nans(builder, intrinsics, v2); @@ -2966,6 +2984,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F32x4Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f32x4_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f32x4_ty, ""); @@ -3018,6 +3039,9 @@ impl FunctionCodeGenerator for LLVMFunctionCodeGenerator { state.push1(res); } Operator::F64x2Max => { + // This implements the same logic as LLVM's @llvm.maximum + // intrinsic would, but x86 lowering of that intrinsics + // encounters a fatal error in LLVM 8 and LLVM 9. let (v1, v2) = state.pop2()?; let v1 = builder.build_bitcast(v1, intrinsics.f64x2_ty, ""); let v2 = builder.build_bitcast(v2, intrinsics.f64x2_ty, "");