diff mbox series

Don't simplify NAN/INF or out-of-range constant for FIX/UNSIGNED_FIX.

Message ID 20240522015743.275499-1-hongtao.liu@intel.com
State New
Headers show
Series Don't simplify NAN/INF or out-of-range constant for FIX/UNSIGNED_FIX. | expand

Commit Message

liuhongt May 22, 2024, 1:57 a.m. UTC
According to IEEE standard, for conversions from floating point to
integer. When a NaN or infinite operand cannot be represented in the
destination format and this cannot otherwise be indicated, the invalid
operation exception shall be signaled. When a numeric operand would
convert to an integer outside the range of the destination format, the
invalid operation exception shall be signaled if this situation cannot
otherwise be indicated.

The patch prevent simplication of the conversion from floating point
to integer for NAN/INF/out-of-range constant when flag_trapping_math.

Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}
Ok for trunk?

gcc/ChangeLog:

	PR rtl-optimization/100927
	PR rtl-optimization/115161
	PR rtl-optimization/115115
	* simplify-rtx.cc (simplify_const_unary_operation): Prevent
	simplication of FIX/UNSIGNED_FIX for NAN/INF/out-of-range
	constant when flag_trapping_math.

gcc/testsuite/ChangeLog:

	* gcc.target/i386/pr100927.c: New test.
---
 gcc/simplify-rtx.cc                      | 23 ++++++++++++++++----
 gcc/testsuite/gcc.target/i386/pr100927.c | 27 ++++++++++++++++++++++++
 2 files changed, 46 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr100927.c

Comments

Richard Biener May 22, 2024, 7:46 a.m. UTC | #1
On Wed, May 22, 2024 at 3:58 AM liuhongt <hongtao.liu@intel.com> wrote:
>
> According to IEEE standard, for conversions from floating point to
> integer. When a NaN or infinite operand cannot be represented in the
> destination format and this cannot otherwise be indicated, the invalid
> operation exception shall be signaled. When a numeric operand would
> convert to an integer outside the range of the destination format, the
> invalid operation exception shall be signaled if this situation cannot
> otherwise be indicated.
>
> The patch prevent simplication of the conversion from floating point
> to integer for NAN/INF/out-of-range constant when flag_trapping_math.
>
> Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}
> Ok for trunk?

OK if there are no further comments today.

Thanks,
Richard.

> gcc/ChangeLog:
>
>         PR rtl-optimization/100927
>         PR rtl-optimization/115161
>         PR rtl-optimization/115115
>         * simplify-rtx.cc (simplify_const_unary_operation): Prevent
>         simplication of FIX/UNSIGNED_FIX for NAN/INF/out-of-range
>         constant when flag_trapping_math.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/i386/pr100927.c: New test.
> ---
>  gcc/simplify-rtx.cc                      | 23 ++++++++++++++++----
>  gcc/testsuite/gcc.target/i386/pr100927.c | 27 ++++++++++++++++++++++++
>  2 files changed, 46 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/i386/pr100927.c
>
> diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
> index 53f54d1d392..b7a770dad60 100644
> --- a/gcc/simplify-rtx.cc
> +++ b/gcc/simplify-rtx.cc
> @@ -2256,14 +2256,25 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
>        switch (code)
>         {
>         case FIX:
> +         /* According to IEEE standard, for conversions from floating point to
> +            integer. When a NaN or infinite operand cannot be represented in
> +            the destination format and this cannot otherwise be indicated, the
> +            invalid operation exception shall be signaled. When a numeric
> +            operand would convert to an integer outside the range of the
> +            destination format, the invalid operation exception shall be
> +            signaled if this situation cannot otherwise be indicated.  */
>           if (REAL_VALUE_ISNAN (*x))
> -           return const0_rtx;
> +           return flag_trapping_math ? NULL_RTX : const0_rtx;
> +
> +         if (REAL_VALUE_ISINF (*x) && flag_trapping_math)
> +           return NULL_RTX;
>
>           /* Test against the signed upper bound.  */
>           wmax = wi::max_value (width, SIGNED);
>           real_from_integer (&t, VOIDmode, wmax, SIGNED);
>           if (real_less (&t, x))
> -           return immed_wide_int_const (wmax, mode);
> +           return (flag_trapping_math
> +                   ? NULL_RTX : immed_wide_int_const (wmax, mode));
>
>           /* Test against the signed lower bound.  */
>           wmin = wi::min_value (width, SIGNED);
> @@ -2276,13 +2287,17 @@ simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
>
>         case UNSIGNED_FIX:
>           if (REAL_VALUE_ISNAN (*x) || REAL_VALUE_NEGATIVE (*x))
> -           return const0_rtx;
> +           return flag_trapping_math ? NULL_RTX : const0_rtx;
> +
> +         if (REAL_VALUE_ISINF (*x) && flag_trapping_math)
> +           return NULL_RTX;
>
>           /* Test against the unsigned upper bound.  */
>           wmax = wi::max_value (width, UNSIGNED);
>           real_from_integer (&t, VOIDmode, wmax, UNSIGNED);
>           if (real_less (&t, x))
> -           return immed_wide_int_const (wmax, mode);
> +           return (flag_trapping_math
> +                   ? NULL_RTX : immed_wide_int_const (wmax, mode));
>
>           return immed_wide_int_const (real_to_integer (x, &fail, width),
>                                        mode);
> diff --git a/gcc/testsuite/gcc.target/i386/pr100927.c b/gcc/testsuite/gcc.target/i386/pr100927.c
> new file mode 100644
> index 00000000000..b137396c30f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/pr100927.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile } */
> +/* { dg-options "-msse2 -O2 -ftrapping-math" } */
> +/* { dg-final { scan-assembler-times "cvttps2dq" 3 } }  */
> +
> +#include <emmintrin.h>
> +
> +__m128i foo_ofr() {
> +  const __m128i iv = _mm_set_epi32(0x4f000000, 0x4f000000, 0x4f000000, 0x4f000000);
> +  const __m128  fv = _mm_castsi128_ps(iv);
> +  const __m128i riv = _mm_cvttps_epi32(fv);
> +  return riv;
> +}
> +
> +__m128i foo_nan() {
> +  const __m128i iv = _mm_set_epi32(0xff800001, 0xff800001, 0xff800001, 0xff800001);
> +  const __m128  fv = _mm_castsi128_ps(iv);
> +  const __m128i riv = _mm_cvttps_epi32(fv);
> +  return riv;
> +}
> +
> +__m128i foo_inf() {
> +  const __m128i iv = _mm_set_epi32(0xff800000, 0xff800000, 0xff800000, 0xff800000);
> +  const __m128  fv = _mm_castsi128_ps(iv);
> +  const __m128i riv = _mm_cvttps_epi32(fv);
> +  return riv;
> +}
> +
> --
> 2.31.1
>
Jakub Jelinek May 22, 2024, 7:59 a.m. UTC | #2
On Wed, May 22, 2024 at 09:46:41AM +0200, Richard Biener wrote:
> On Wed, May 22, 2024 at 3:58 AM liuhongt <hongtao.liu@intel.com> wrote:
> >
> > According to IEEE standard, for conversions from floating point to
> > integer. When a NaN or infinite operand cannot be represented in the
> > destination format and this cannot otherwise be indicated, the invalid
> > operation exception shall be signaled. When a numeric operand would
> > convert to an integer outside the range of the destination format, the
> > invalid operation exception shall be signaled if this situation cannot
> > otherwise be indicated.
> >
> > The patch prevent simplication of the conversion from floating point
> > to integer for NAN/INF/out-of-range constant when flag_trapping_math.
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}
> > Ok for trunk?
> 
> OK if there are no further comments today.

As I wrote in the PR, I don't think this is the right fix for the PR,
the simplify-rtx.cc change is the right thing to do, the C standard
in F.4 says that the out of range conversions to integers should raise
exceptions, but still says that the resulting value in those cases is
unspecified.
So, for the C part we should verify that with -ftrapping-math we don't
constant fold it and cover it both by pure C and perhaps backend specific
testcases which just search asm for the conversion instructions
or even runtime test which tests that the exceptions are triggered,
verify that we don't fold it either during GIMPLE opts or RTL opts
(dunno whether they can be folded in e.g. C constant initializers or not).

And then on the backend side, it should stop using FIX/UNSIGNED_FIX RTLs
in patterns which are used for the intrinsics (and keep using them in
patterns used for C scalar/vector conversions), because even with
-fno-trapping-math the intrinsics should have the documented behavior,
particular result value, while in C they are clearly unspecified and
FIX/UNSIGNED_FIX folding even with the patch chooses some particular values
which don't match those (sure, they are like that because of Java, but am
not sure it is the right time to change what we do in those cases say
by providing a target hook to pick a different value).

The provided testcase tests the values though, so I think is inappropriate
for this patch.

	Jakub
Hongtao Liu May 23, 2024, 5:11 a.m. UTC | #3
On Wed, May 22, 2024 at 3:59 PM Jakub Jelinek <jakub@redhat.com> wrote:
>
> On Wed, May 22, 2024 at 09:46:41AM +0200, Richard Biener wrote:
> > On Wed, May 22, 2024 at 3:58 AM liuhongt <hongtao.liu@intel.com> wrote:
> > >
> > > According to IEEE standard, for conversions from floating point to
> > > integer. When a NaN or infinite operand cannot be represented in the
> > > destination format and this cannot otherwise be indicated, the invalid
> > > operation exception shall be signaled. When a numeric operand would
> > > convert to an integer outside the range of the destination format, the
> > > invalid operation exception shall be signaled if this situation cannot
> > > otherwise be indicated.
> > >
> > > The patch prevent simplication of the conversion from floating point
> > > to integer for NAN/INF/out-of-range constant when flag_trapping_math.
> > >
> > > Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}
> > > Ok for trunk?
> >
> > OK if there are no further comments today.
>
> As I wrote in the PR, I don't think this is the right fix for the PR,
> the simplify-rtx.cc change is the right thing to do, the C standard
> in F.4 says that the out of range conversions to integers should raise
> exceptions, but still says that the resulting value in those cases is
> unspecified.
> So, for the C part we should verify that with -ftrapping-math we don't
> constant fold it and cover it both by pure C and perhaps backend specific
> testcases which just search asm for the conversion instructions
> or even runtime test which tests that the exceptions are triggered,
> verify that we don't fold it either during GIMPLE opts or RTL opts
> (dunno whether they can be folded in e.g. C constant initializers or not).
>
There're lots of warnings for Wconversion that rely on gimple fold,
lots of new failures after the patch below.
Should we also add -fno-trapping-math to those testcases?

-  t = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (arg1));
+  /* According to IEEE standard, for conversions from floating point to
+     integer. When a NaN or infinite operand cannot be represented in the
+     destination format and this cannot otherwise be indicated, the invalid
+     operation exception shall be signaled. When a numeric operand would
+     convert to an integer outside the range of the destination format, the
+     invalid operation exception shall be signaled if this situation cannot
+     otherwise be indicated.  */
+  if (!flag_trapping_math || !overflow)
+    t = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (arg1));
+  else
+    t = NULL_TREE;
+
   return t;
 }


g++: c-c++-common/Wconversion-1.c  -std=gnu++14  (test for warnings, line 13)

g++: c-c++-common/Wconversion-1.c  -std=gnu++17  (test for warnings, line 13)

g++: c-c++-common/Wconversion-1.c  -std=gnu++20  (test for warnings, line 13)

g++: c-c++-common/Wconversion-1.c  -std=gnu++98  (test for warnings, line 13)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 26)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 30)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 34)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 39)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 43)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 47)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 51)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 55)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14  (test for
warnings, line 59)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++14 execution test

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 26)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 30)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 34)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 39)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 43)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 47)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 51)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 55)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17  (test for
warnings, line 59)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++17 execution test

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 26)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 30)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 34)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 39)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 43)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 47)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 51)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 55)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20  (test for
warnings, line 59)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++20 execution test

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 26)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 30)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 34)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 39)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 43)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 47)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 51)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 55)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98  (test for
warnings, line 59)

g++: c-c++-common/dfp/convert-int-saturate.c  -std=c++98 execution test

g++: g++.dg/ubsan/pr63956.C    (test for errors, line 159)

g++: g++.dg/ubsan/pr63956.C   (test for excess errors)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 100)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 101)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 102)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 110)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 111)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 33)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 34)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 86)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 87)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 88)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 89)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 90)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 91)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 92)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 93)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 95)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 96)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 97)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 98)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++14  (test for
warnings, line 99)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 100)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 101)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 102)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 110)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 111)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 33)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 34)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 86)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 87)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 88)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 89)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 90)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 91)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 92)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 93)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 95)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 96)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 97)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 98)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++17  (test for
warnings, line 99)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 100)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 101)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 102)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 110)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 111)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 33)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 34)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 86)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 87)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 88)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 89)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 90)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 91)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 92)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 93)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 95)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 96)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 97)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 98)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++20  (test for
warnings, line 99)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 100)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 101)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 102)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 110)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 111)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 33)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 34)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 86)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 87)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 88)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 89)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 90)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 91)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 92)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 93)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 95)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 96)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 97)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 98)

g++: g++.dg/warn/Wconversion-real-integer.C  -std=gnu++98  (test for
warnings, line 99)

gcc: c-c++-common/Wconversion-1.c  -Wc++-compat   (test for warnings, line 13)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 26)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 30)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 34)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 39)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 43)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 47)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 51)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 55)

gcc: c-c++-common/dfp/convert-int-saturate.c  (test for warnings, line 59)

gcc: c-c++-common/dfp/convert-int-saturate.c execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O0  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O1  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O2  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O2 -flto
-fno-use-linker-plugin -flto-partition=none  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -O3 -g  execution test

gcc: gcc.c-torture/execute/20031003-1.c   -Os  execution test

gcc: gcc.dg/Wconversion-complex-c99.c  (test for warnings, line 118)

gcc: gcc.dg/Wconversion-complex-c99.c  (test for warnings, line 119)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 100)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 101)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 102)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 103)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 111)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 112)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 34)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 35)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 87)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 88)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 89)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 90)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 91)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 92)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 93)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 94)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 96)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 97)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 98)

gcc: gcc.dg/Wconversion-real-integer.c  (test for warnings, line 99)

gcc: gcc.dg/c90-const-expr-11.c  (test for warnings, line 23)

gcc: gcc.dg/c90-const-expr-11.c constant at line 24 (test for errors, line 23)

gcc: gcc.dg/overflow-warn-8.c  (test for warnings, line 10)
>
>         Jakub
>
diff mbox series

Patch

diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 53f54d1d392..b7a770dad60 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -2256,14 +2256,25 @@  simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
       switch (code)
 	{
 	case FIX:
+	  /* According to IEEE standard, for conversions from floating point to
+	     integer. When a NaN or infinite operand cannot be represented in
+	     the destination format and this cannot otherwise be indicated, the
+	     invalid operation exception shall be signaled. When a numeric
+	     operand would convert to an integer outside the range of the
+	     destination format, the invalid operation exception shall be
+	     signaled if this situation cannot otherwise be indicated.  */
 	  if (REAL_VALUE_ISNAN (*x))
-	    return const0_rtx;
+	    return flag_trapping_math ? NULL_RTX : const0_rtx;
+
+	  if (REAL_VALUE_ISINF (*x) && flag_trapping_math)
+	    return NULL_RTX;
 
 	  /* Test against the signed upper bound.  */
 	  wmax = wi::max_value (width, SIGNED);
 	  real_from_integer (&t, VOIDmode, wmax, SIGNED);
 	  if (real_less (&t, x))
-	    return immed_wide_int_const (wmax, mode);
+	    return (flag_trapping_math
+		    ? NULL_RTX : immed_wide_int_const (wmax, mode));
 
 	  /* Test against the signed lower bound.  */
 	  wmin = wi::min_value (width, SIGNED);
@@ -2276,13 +2287,17 @@  simplify_const_unary_operation (enum rtx_code code, machine_mode mode,
 
 	case UNSIGNED_FIX:
 	  if (REAL_VALUE_ISNAN (*x) || REAL_VALUE_NEGATIVE (*x))
-	    return const0_rtx;
+	    return flag_trapping_math ? NULL_RTX : const0_rtx;
+
+	  if (REAL_VALUE_ISINF (*x) && flag_trapping_math)
+	    return NULL_RTX;
 
 	  /* Test against the unsigned upper bound.  */
 	  wmax = wi::max_value (width, UNSIGNED);
 	  real_from_integer (&t, VOIDmode, wmax, UNSIGNED);
 	  if (real_less (&t, x))
-	    return immed_wide_int_const (wmax, mode);
+	    return (flag_trapping_math
+		    ? NULL_RTX : immed_wide_int_const (wmax, mode));
 
 	  return immed_wide_int_const (real_to_integer (x, &fail, width),
 				       mode);
diff --git a/gcc/testsuite/gcc.target/i386/pr100927.c b/gcc/testsuite/gcc.target/i386/pr100927.c
new file mode 100644
index 00000000000..b137396c30f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr100927.c
@@ -0,0 +1,27 @@ 
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O2 -ftrapping-math" } */
+/* { dg-final { scan-assembler-times "cvttps2dq" 3 } }  */
+
+#include <emmintrin.h>
+
+__m128i foo_ofr() {
+  const __m128i iv = _mm_set_epi32(0x4f000000, 0x4f000000, 0x4f000000, 0x4f000000);
+  const __m128  fv = _mm_castsi128_ps(iv);
+  const __m128i riv = _mm_cvttps_epi32(fv);
+  return riv;
+}
+
+__m128i foo_nan() {
+  const __m128i iv = _mm_set_epi32(0xff800001, 0xff800001, 0xff800001, 0xff800001);
+  const __m128  fv = _mm_castsi128_ps(iv);
+  const __m128i riv = _mm_cvttps_epi32(fv);
+  return riv;
+}
+
+__m128i foo_inf() {
+  const __m128i iv = _mm_set_epi32(0xff800000, 0xff800000, 0xff800000, 0xff800000);
+  const __m128  fv = _mm_castsi128_ps(iv);
+  const __m128i riv = _mm_cvttps_epi32(fv);
+  return riv;
+}
+