range-op-float, v2: Fix up frange_arithmetic [PR107967]

Message ID Y5C2HQOXFT+RTCId@tucnak
State Unresolved
Headers
Series range-op-float, v2: Fix up frange_arithmetic [PR107967] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Dec. 7, 2022, 3:49 p.m. UTC
  On Wed, Dec 07, 2022 at 04:26:14PM +0100, Aldy Hernandez wrote:
> This chunk...
> 
> ...is quite similar to this one.  Could you abstract this?

It differs in various small details, plus comment content.
Anyway, here it is reworked such that those various small details
are based on whether inf is negative or positive in a single piece
of code.
Is this ok if it passes bootstrap/regtest?

2022-12-07  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/107967
	* range-op-float.cc (frange_arithmetic): Fix a thinko - if
	inf is negative, use nextafter if !real_less (&result, &value)
	rather than if real_less (&result, &value).  If result is +-INF
	while value is finite and -fno-rounding-math, don't do rounding
	if !inexact or if result is significantly above max representable
	value or below min representable value.

	* gcc.dg/pr107967-1.c: New test.
	* gcc.dg/pr107967-2.c: New test.
	* gcc.dg/pr107967-3.c: New test.



	Jakub
  

Comments

Aldy Hernandez Dec. 7, 2022, 5:40 p.m. UTC | #1
OK, thanks.
Aldy

On 12/7/22 16:49, Jakub Jelinek wrote:
> On Wed, Dec 07, 2022 at 04:26:14PM +0100, Aldy Hernandez wrote:
>> This chunk...
>>
>> ...is quite similar to this one.  Could you abstract this?
> 
> It differs in various small details, plus comment content.
> Anyway, here it is reworked such that those various small details
> are based on whether inf is negative or positive in a single piece
> of code.
> Is this ok if it passes bootstrap/regtest?
> 
> 2022-12-07  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/107967
> 	* range-op-float.cc (frange_arithmetic): Fix a thinko - if
> 	inf is negative, use nextafter if !real_less (&result, &value)
> 	rather than if real_less (&result, &value).  If result is +-INF
> 	while value is finite and -fno-rounding-math, don't do rounding
> 	if !inexact or if result is significantly above max representable
> 	value or below min representable value.
> 
> 	* gcc.dg/pr107967-1.c: New test.
> 	* gcc.dg/pr107967-2.c: New test.
> 	* gcc.dg/pr107967-3.c: New test.
> 
> --- gcc/range-op-float.cc.jj	2022-12-07 16:37:05.285143250 +0100
> +++ gcc/range-op-float.cc	2022-12-07 16:41:58.500928517 +0100
> @@ -287,9 +287,42 @@ frange_arithmetic (enum tree_code code,
>   
>     // Be extra careful if there may be discrepancies between the
>     // compile and runtime results.
> -  if ((mode_composite || (real_isneg (&inf) ? real_less (&result, &value)
> -			  : !real_less (&value, &result)))
> -      && (inexact || !real_identical (&result, &value)))
> +  bool round = false;
> +  if (mode_composite)
> +    round = true;
> +  else
> +    {
> +      bool low = real_isneg (&inf);
> +      round = (low ? !real_less (&result, &value)
> +		   : !real_less (&value, &result));
> +      if (real_isinf (&result, !low)
> +	  && !real_isinf (&value)
> +	  && !flag_rounding_math)
> +	{
> +	  // Use just [+INF, +INF] rather than [MAX, +INF]
> +	  // even if value is larger than MAX and rounds to
> +	  // nearest to +INF.  Similarly just [-INF, -INF]
> +	  // rather than [-INF, +MAX] even if value is smaller
> +	  // than -MAX and rounds to nearest to -INF.
> +	  // Unless INEXACT is true, in that case we need some
> +	  // extra buffer.
> +	  if (!inexact)
> +	    round = false;
> +	  else
> +	    {
> +	      REAL_VALUE_TYPE tmp = result, tmp2;
> +	      frange_nextafter (mode, tmp, inf);
> +	      // TMP is at this point the maximum representable
> +	      // number.
> +	      real_arithmetic (&tmp2, MINUS_EXPR, &value, &tmp);
> +	      if (real_isneg (&tmp2) != low
> +		  && (REAL_EXP (&tmp2) - REAL_EXP (&tmp)
> +		      >= 2 - REAL_MODE_FORMAT (mode)->p))
> +		round = false;
> +	    }
> +	}
> +    }
> +  if (round && (inexact || !real_identical (&result, &value)))
>       {
>         if (mode_composite)
>   	{
> --- gcc/testsuite/gcc.dg/pr107967-1.c.jj	2022-12-07 16:38:07.519248686 +0100
> +++ gcc/testsuite/gcc.dg/pr107967-1.c	2022-12-07 16:38:07.519248686 +0100
> @@ -0,0 +1,35 @@
> +/* PR tree-optimization/107967 */
> +/* { dg-do compile { target float64 } } */
> +/* { dg-options "-O2 -frounding-math -fno-trapping-math -fdump-tree-optimized" } */
> +/* { dg-add-options float64 } */
> +/* { dg-final { scan-tree-dump-not "return\[ \t]\*-?Inf;" "optimized" } } */
> +
> +_Float64
> +foo (void)
> +{
> +  const _Float64 huge = 1.0e+300f64;
> +  return huge * huge;
> +}
> +
> +_Float64
> +bar (void)
> +{
> +  const _Float64 huge = 1.0e+300f64;
> +  return huge * -huge;
> +}
> +
> +_Float64
> +baz (void)
> +{
> +  const _Float64 a = 0x1.fffffffffffffp+1023f64;
> +  const _Float64 b = 0x1.fffffffffffffp+970f64;
> +  return a + b;
> +}
> +
> +_Float64
> +qux (void)
> +{
> +  const _Float64 a = 0x1.fffffffffffffp+1023f64;
> +  const _Float64 b = 0x1.fffffffffffffp+969f64;
> +  return a + b;
> +}
> --- gcc/testsuite/gcc.dg/pr107967-2.c.jj	2022-12-07 16:38:07.519248686 +0100
> +++ gcc/testsuite/gcc.dg/pr107967-2.c	2022-12-07 16:38:07.519248686 +0100
> @@ -0,0 +1,35 @@
> +/* PR tree-optimization/107967 */
> +/* { dg-do compile { target float64 } } */
> +/* { dg-options "-O2 -fno-rounding-math -fno-trapping-math -fdump-tree-optimized" } */
> +/* { dg-add-options float64 } */
> +/* { dg-final { scan-tree-dump-times "return\[ \t]\*-?Inf;" 3 "optimized" } } */
> +
> +_Float64
> +foo (void)
> +{
> +  const _Float64 huge = 1.0e+300f64;
> +  return huge * huge;
> +}
> +
> +_Float64
> +bar (void)
> +{
> +  const _Float64 huge = 1.0e+300f64;
> +  return huge * -huge;
> +}
> +
> +_Float64
> +baz (void)
> +{
> +  const _Float64 a = 0x1.fffffffffffffp+1023f64;
> +  const _Float64 b = 0x1.fffffffffffffp+970f64;
> +  return a + b;
> +}
> +
> +_Float64
> +qux (void)
> +{
> +  const _Float64 a = 0x1.fffffffffffffp+1023f64;
> +  const _Float64 b = 0x1.fffffffffffffp+969f64;
> +  return a + b;
> +}
> --- gcc/testsuite/gcc.dg/pr107967-3.c.jj	2022-12-07 16:38:07.519248686 +0100
> +++ gcc/testsuite/gcc.dg/pr107967-3.c	2022-12-07 16:38:07.519248686 +0100
> @@ -0,0 +1,53 @@
> +/* PR tree-optimization/107967 */
> +/* { dg-do compile { target float64 } } */
> +/* { dg-options "-O2 -fno-rounding-math -fno-trapping-math -fdump-tree-optimized" } */
> +/* { dg-add-options float64 } */
> +/* { dg-final { scan-tree-dump-times "return\[ \t]\*-?Inf;" 3 "optimized" } } */
> +
> +_Float64
> +foo (_Float64 x)
> +{
> +  if (x >= 1.0e+300f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  return x * x;
> +}
> +
> +_Float64
> +bar (_Float64 x)
> +{
> +  if (x >= 1.0e+300f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  return x * -x;
> +}
> +
> +_Float64
> +baz (_Float64 a, _Float64 b)
> +{
> +  if (a >= 0x1.fffffffffffffp+1023f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  if (b >= 0x1.p+972f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  return a + b;
> +}
> +
> +_Float64
> +qux (_Float64 a, _Float64 b)
> +{
> +  if (a >= 0x1.fffffffffffffp+1023f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  if (b >= 0x1.fffffffffffffp+969f64)
> +    ;
> +  else
> +    __builtin_unreachable ();
> +  return a + b;
> +}
> 
> 
> 	Jakub
>
  

Patch

--- gcc/range-op-float.cc.jj	2022-12-07 16:37:05.285143250 +0100
+++ gcc/range-op-float.cc	2022-12-07 16:41:58.500928517 +0100
@@ -287,9 +287,42 @@  frange_arithmetic (enum tree_code code,
 
   // Be extra careful if there may be discrepancies between the
   // compile and runtime results.
-  if ((mode_composite || (real_isneg (&inf) ? real_less (&result, &value)
-			  : !real_less (&value, &result)))
-      && (inexact || !real_identical (&result, &value)))
+  bool round = false;
+  if (mode_composite)
+    round = true;
+  else
+    {
+      bool low = real_isneg (&inf);
+      round = (low ? !real_less (&result, &value)
+		   : !real_less (&value, &result));
+      if (real_isinf (&result, !low)
+	  && !real_isinf (&value)
+	  && !flag_rounding_math)
+	{
+	  // Use just [+INF, +INF] rather than [MAX, +INF]
+	  // even if value is larger than MAX and rounds to
+	  // nearest to +INF.  Similarly just [-INF, -INF]
+	  // rather than [-INF, +MAX] even if value is smaller
+	  // than -MAX and rounds to nearest to -INF.
+	  // Unless INEXACT is true, in that case we need some
+	  // extra buffer.
+	  if (!inexact)
+	    round = false;
+	  else
+	    {
+	      REAL_VALUE_TYPE tmp = result, tmp2;
+	      frange_nextafter (mode, tmp, inf);
+	      // TMP is at this point the maximum representable
+	      // number.
+	      real_arithmetic (&tmp2, MINUS_EXPR, &value, &tmp);
+	      if (real_isneg (&tmp2) != low
+		  && (REAL_EXP (&tmp2) - REAL_EXP (&tmp)
+		      >= 2 - REAL_MODE_FORMAT (mode)->p))
+		round = false;
+	    }
+	}
+    }
+  if (round && (inexact || !real_identical (&result, &value)))
     {
       if (mode_composite)
 	{
--- gcc/testsuite/gcc.dg/pr107967-1.c.jj	2022-12-07 16:38:07.519248686 +0100
+++ gcc/testsuite/gcc.dg/pr107967-1.c	2022-12-07 16:38:07.519248686 +0100
@@ -0,0 +1,35 @@ 
+/* PR tree-optimization/107967 */
+/* { dg-do compile { target float64 } } */
+/* { dg-options "-O2 -frounding-math -fno-trapping-math -fdump-tree-optimized" } */
+/* { dg-add-options float64 } */
+/* { dg-final { scan-tree-dump-not "return\[ \t]\*-?Inf;" "optimized" } } */
+
+_Float64
+foo (void)
+{
+  const _Float64 huge = 1.0e+300f64;
+  return huge * huge;
+}
+
+_Float64
+bar (void)
+{
+  const _Float64 huge = 1.0e+300f64;
+  return huge * -huge;
+}
+
+_Float64
+baz (void)
+{
+  const _Float64 a = 0x1.fffffffffffffp+1023f64;
+  const _Float64 b = 0x1.fffffffffffffp+970f64;
+  return a + b;
+}
+
+_Float64
+qux (void)
+{
+  const _Float64 a = 0x1.fffffffffffffp+1023f64;
+  const _Float64 b = 0x1.fffffffffffffp+969f64;
+  return a + b;
+}
--- gcc/testsuite/gcc.dg/pr107967-2.c.jj	2022-12-07 16:38:07.519248686 +0100
+++ gcc/testsuite/gcc.dg/pr107967-2.c	2022-12-07 16:38:07.519248686 +0100
@@ -0,0 +1,35 @@ 
+/* PR tree-optimization/107967 */
+/* { dg-do compile { target float64 } } */
+/* { dg-options "-O2 -fno-rounding-math -fno-trapping-math -fdump-tree-optimized" } */
+/* { dg-add-options float64 } */
+/* { dg-final { scan-tree-dump-times "return\[ \t]\*-?Inf;" 3 "optimized" } } */
+
+_Float64
+foo (void)
+{
+  const _Float64 huge = 1.0e+300f64;
+  return huge * huge;
+}
+
+_Float64
+bar (void)
+{
+  const _Float64 huge = 1.0e+300f64;
+  return huge * -huge;
+}
+
+_Float64
+baz (void)
+{
+  const _Float64 a = 0x1.fffffffffffffp+1023f64;
+  const _Float64 b = 0x1.fffffffffffffp+970f64;
+  return a + b;
+}
+
+_Float64
+qux (void)
+{
+  const _Float64 a = 0x1.fffffffffffffp+1023f64;
+  const _Float64 b = 0x1.fffffffffffffp+969f64;
+  return a + b;
+}
--- gcc/testsuite/gcc.dg/pr107967-3.c.jj	2022-12-07 16:38:07.519248686 +0100
+++ gcc/testsuite/gcc.dg/pr107967-3.c	2022-12-07 16:38:07.519248686 +0100
@@ -0,0 +1,53 @@ 
+/* PR tree-optimization/107967 */
+/* { dg-do compile { target float64 } } */
+/* { dg-options "-O2 -fno-rounding-math -fno-trapping-math -fdump-tree-optimized" } */
+/* { dg-add-options float64 } */
+/* { dg-final { scan-tree-dump-times "return\[ \t]\*-?Inf;" 3 "optimized" } } */
+
+_Float64
+foo (_Float64 x)
+{
+  if (x >= 1.0e+300f64)
+    ;
+  else
+    __builtin_unreachable ();
+  return x * x;
+}
+
+_Float64
+bar (_Float64 x)
+{
+  if (x >= 1.0e+300f64)
+    ;
+  else
+    __builtin_unreachable ();
+  return x * -x;
+}
+
+_Float64
+baz (_Float64 a, _Float64 b)
+{
+  if (a >= 0x1.fffffffffffffp+1023f64)
+    ;
+  else
+    __builtin_unreachable ();
+  if (b >= 0x1.p+972f64)
+    ;
+  else
+    __builtin_unreachable ();
+  return a + b;
+}
+
+_Float64
+qux (_Float64 a, _Float64 b)
+{
+  if (a >= 0x1.fffffffffffffp+1023f64)
+    ;
+  else
+    __builtin_unreachable ();
+  if (b >= 0x1.fffffffffffffp+969f64)
+    ;
+  else
+    __builtin_unreachable ();
+  return a + b;
+}