diff mbox series

Fix floating point handling in dom (PR tree-optimization/84235)

Message ID 20180206204037.GE5867@tucnak
State New
Headers show
Series Fix floating point handling in dom (PR tree-optimization/84235) | expand

Commit Message

Jakub Jelinek Feb. 6, 2018, 8:40 p.m. UTC
Hi!

As the following testcase shows, dom2 miscompiles floating point x - x
into 0.0 even when x could be infinity and x - x then a NaN.
The corresponding match.pd optimization is:
/* Simplify x - x.
   This is unsafe for certain floats even in non-IEEE formats.
   In IEEE, it is unsafe because it does wrong for NaNs.
   Also note that operand_equal_p is always false if an operand
   is volatile.  */
(simplify
 (minus @0 @0)
 (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
  { build_zero_cst (type); }))
The patch makes it match what match.pd does.
We also have:
 /* X / X is one.  */
 (simplify
  (div @0 @0)
  /* But not for 0 / 0 so that we can get the proper warnings and errors.
     And not for _Fract types where we can't build 1.  */
  (if (!integer_zerop (@0) && !ALL_FRACT_MODE_P (TYPE_MODE (type)))
   { build_one_cst (type); }))
We can ignore the 0 / 0 case, we have both operands SSA_NAMEs and match.pd
only avoids optimizing away literal 0 / 0, but the rest is valid, some fract
types don't have a way to express 1.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2018-02-06  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/84235
	* tree-ssa-scopedtables.c
	(avail_exprs_stack::simplify_binary_operation): Fir MINUS_EXPR, punt
	if the subtraction is performed in floating point type where NaNs are
	honored.  For *DIV_EXPR, punt for ALL_FRACT_MODE_Ps where we can't
	build 1.  Formatting fix.

	* gcc.c-torture/execute/ieee/pr84235.c: New test.


	Jakub

Comments

Richard Biener Feb. 7, 2018, 7:06 a.m. UTC | #1
On February 6, 2018 9:40:37 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>As the following testcase shows, dom2 miscompiles floating point x - x
>into 0.0 even when x could be infinity and x - x then a NaN.
>The corresponding match.pd optimization is:
>/* Simplify x - x.
>   This is unsafe for certain floats even in non-IEEE formats.
>   In IEEE, it is unsafe because it does wrong for NaNs.
>   Also note that operand_equal_p is always false if an operand
>   is volatile.  */
>(simplify
> (minus @0 @0)
> (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
>  { build_zero_cst (type); }))
>The patch makes it match what match.pd does.
>We also have:
> /* X / X is one.  */
> (simplify
>  (div @0 @0)
>/* But not for 0 / 0 so that we can get the proper warnings and errors.
>     And not for _Fract types where we can't build 1.  */
>  (if (!integer_zerop (@0) && !ALL_FRACT_MODE_P (TYPE_MODE (type)))
>   { build_one_cst (type); }))
>We can ignore the 0 / 0 case, we have both operands SSA_NAMEs and
>match.pd
>only avoids optimizing away literal 0 / 0, but the rest is valid, some
>fract
>types don't have a way to express 1.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK. 

I wonder why we have to re-implement all this in DOM. there's enough of match and simplify interfaces to make it use that? 

Richard. 


>2018-02-06  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/84235
>	* tree-ssa-scopedtables.c
>	(avail_exprs_stack::simplify_binary_operation): Fir MINUS_EXPR, punt
>	if the subtraction is performed in floating point type where NaNs are
>	honored.  For *DIV_EXPR, punt for ALL_FRACT_MODE_Ps where we can't
>	build 1.  Formatting fix.
>
>	* gcc.c-torture/execute/ieee/pr84235.c: New test.
>
>--- gcc/tree-ssa-scopedtables.c.jj	2018-01-03 10:19:54.528533857 +0100
>+++ gcc/tree-ssa-scopedtables.c	2018-02-06 14:58:08.944673984 +0100
>@@ -182,8 +182,15 @@ avail_exprs_stack::simplify_binary_opera
> 		      case BIT_AND_EXPR:
> 			return gimple_assign_rhs1 (stmt);
> 
>-		      case BIT_XOR_EXPR:
> 		      case MINUS_EXPR:
>+			/* This is unsafe for certain floats even in non-IEEE
>+			   formats.  In IEEE, it is unsafe because it does
>+			   wrong for NaNs.  */
>+			if (FLOAT_TYPE_P (result_type)
>+			    && HONOR_NANS (result_type))
>+			  break;
>+			/* FALLTHRU */
>+		      case BIT_XOR_EXPR:
> 		      case TRUNC_MOD_EXPR:
> 		      case CEIL_MOD_EXPR:
> 		      case FLOOR_MOD_EXPR:
>@@ -195,6 +202,9 @@ avail_exprs_stack::simplify_binary_opera
> 		      case FLOOR_DIV_EXPR:
> 		      case ROUND_DIV_EXPR:
> 		      case EXACT_DIV_EXPR:
>+			/* Avoid _Fract types where we can't build 1.  */
>+			if (ALL_FRACT_MODE_P (TYPE_MODE (result_type)))
>+			  break;
> 			return build_one_cst (result_type);
> 
> 		      default:
>@@ -204,8 +214,8 @@ avail_exprs_stack::simplify_binary_opera
> 		break;
> 	      }
> 
>-	      default:
>-		break;
>+	    default:
>+	      break;
> 	    }
> 	}
>     }
>--- gcc/testsuite/gcc.c-torture/execute/ieee/pr84235.c.jj	2018-02-06
>15:04:26.528454766 +0100
>+++ gcc/testsuite/gcc.c-torture/execute/ieee/pr84235.c	2018-02-06
>15:05:06.836341334 +0100
>@@ -0,0 +1,11 @@
>+/* PR tree-optimization/84235 */
>+
>+int
>+main ()
>+{
>+  double d = 1.0 / 0.0;
>+  _Bool b = d == d && (d - d) != (d - d);
>+  if (!b)
>+    __builtin_abort ();
>+  return 0;
>+}
>
>	Jakub
Jakub Jelinek Feb. 7, 2018, 8:35 a.m. UTC | #2
On Wed, Feb 07, 2018 at 08:06:53AM +0100, Richard Biener wrote:
> >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> OK. 

Committed, thanks.

> I wonder why we have to re-implement all this in DOM.  there's enough of
> match and simplify interfaces to make it use that?

It would certainly be nicer to be able to just use match.pd here.
I guess the intent is only do it if it folds into a constant.  While we
could use a valueize hook that would return the same SSA_NAME for both
values, wonder if gimplify-match.c has some API to create stmts in a
sequence only instead of replacing the stmt(s) in the IL that we could use,
test if it is a constant and use it, otherwise throw away.

	Jakub
Richard Biener Feb. 7, 2018, 10:21 a.m. UTC | #3
On Wed, 7 Feb 2018, Jakub Jelinek wrote:

> On Wed, Feb 07, 2018 at 08:06:53AM +0100, Richard Biener wrote:
> > >Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> > 
> > OK. 
> 
> Committed, thanks.
> 
> > I wonder why we have to re-implement all this in DOM.  there's enough of
> > match and simplify interfaces to make it use that?
> 
> It would certainly be nicer to be able to just use match.pd here.
> I guess the intent is only do it if it folds into a constant.  While we
> could use a valueize hook that would return the same SSA_NAME for both
> values, wonder if gimplify-match.c has some API to create stmts in a
> sequence only instead of replacing the stmt(s) in the IL that we could use,
> test if it is a constant and use it, otherwise throw away.

Yes it does.  SCCVN for example uses it - not 100% "nice" but you
can look at vn_nary_build_or_lookup_1 for example.  The interface
is using gimple_resimplify[123], passing a NULL gimple_seq (never
allow any extra stmts as simplification) and expanded ops/code.
The simplification result is in the same expanded form and you
can use gimple_simplified_result_is_gimple_val to check if it
is a singleton and then is_gimple_min_invariant if it is constant.
But maybe we can also allow SSA names as result, like from
a - b + b or so.

There's of course the gimple_fold_stmt_to_constant[_1] API that
you can also use on existing gimple stmts which will return
a is_gimple_val as well (and will valueize things in the _1 variant
with the appropriate callbacks).  Not sure if everything DOM
wants to simplify is readily available in the IL though.  If not,
the above interface is the correct thing to use.

Well - or simply use fold_{unary,binary} ...

Richard.
Jeff Law Feb. 8, 2018, 4:27 a.m. UTC | #4
On 02/07/2018 12:06 AM, Richard Biener wrote:
> On February 6, 2018 9:40:37 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>> Hi!
>>
>> As the following testcase shows, dom2 miscompiles floating point x - x
>> into 0.0 even when x could be infinity and x - x then a NaN.
>> The corresponding match.pd optimization is:
>> /* Simplify x - x.
>>   This is unsafe for certain floats even in non-IEEE formats.
>>   In IEEE, it is unsafe because it does wrong for NaNs.
>>   Also note that operand_equal_p is always false if an operand
>>   is volatile.  */
>> (simplify
>> (minus @0 @0)
>> (if (!FLOAT_TYPE_P (type) || !HONOR_NANS (type))
>>  { build_zero_cst (type); }))
>> The patch makes it match what match.pd does.
>> We also have:
>> /* X / X is one.  */
>> (simplify
>>  (div @0 @0)
>> /* But not for 0 / 0 so that we can get the proper warnings and errors.
>>     And not for _Fract types where we can't build 1.  */
>>  (if (!integer_zerop (@0) && !ALL_FRACT_MODE_P (TYPE_MODE (type)))
>>   { build_one_cst (type); }))
>> We can ignore the 0 / 0 case, we have both operands SSA_NAMEs and
>> match.pd
>> only avoids optimizing away literal 0 / 0, but the rest is valid, some
>> fract
>> types don't have a way to express 1.
>>
>> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> OK. 
> 
> I wonder why we have to re-implement all this in DOM. there's enough of match and simplify interfaces to make it use that? 
What's going on with this code is we have some kind of binary
expression.  We do not know the value of either operand.

However, we have recorded that the two operands are equal to each other
via a conditional equivalence.  ie, we have 1 = (A == B) in the
expression hash table.

For many binary operations knowing the operands are equal allows us to
eliminate the binary operation.

This was part of avoiding regressing when we stopped recording
conditional equivalences in the cprop tables.

What I'm concerned about here is how did we get into this code for a
floating point object  That should have been filtered out earlier!


Jeff
diff mbox series

Patch

--- gcc/tree-ssa-scopedtables.c.jj	2018-01-03 10:19:54.528533857 +0100
+++ gcc/tree-ssa-scopedtables.c	2018-02-06 14:58:08.944673984 +0100
@@ -182,8 +182,15 @@  avail_exprs_stack::simplify_binary_opera
 		      case BIT_AND_EXPR:
 			return gimple_assign_rhs1 (stmt);
 
-		      case BIT_XOR_EXPR:
 		      case MINUS_EXPR:
+			/* This is unsafe for certain floats even in non-IEEE
+			   formats.  In IEEE, it is unsafe because it does
+			   wrong for NaNs.  */
+			if (FLOAT_TYPE_P (result_type)
+			    && HONOR_NANS (result_type))
+			  break;
+			/* FALLTHRU */
+		      case BIT_XOR_EXPR:
 		      case TRUNC_MOD_EXPR:
 		      case CEIL_MOD_EXPR:
 		      case FLOOR_MOD_EXPR:
@@ -195,6 +202,9 @@  avail_exprs_stack::simplify_binary_opera
 		      case FLOOR_DIV_EXPR:
 		      case ROUND_DIV_EXPR:
 		      case EXACT_DIV_EXPR:
+			/* Avoid _Fract types where we can't build 1.  */
+			if (ALL_FRACT_MODE_P (TYPE_MODE (result_type)))
+			  break;
 			return build_one_cst (result_type);
 
 		      default:
@@ -204,8 +214,8 @@  avail_exprs_stack::simplify_binary_opera
 		break;
 	      }
 
-	      default:
-		break;
+	    default:
+	      break;
 	    }
 	}
     }
--- gcc/testsuite/gcc.c-torture/execute/ieee/pr84235.c.jj	2018-02-06 15:04:26.528454766 +0100
+++ gcc/testsuite/gcc.c-torture/execute/ieee/pr84235.c	2018-02-06 15:05:06.836341334 +0100
@@ -0,0 +1,11 @@ 
+/* PR tree-optimization/84235 */
+
+int
+main ()
+{
+  double d = 1.0 / 0.0;
+  _Bool b = d == d && (d - d) != (d - d);
+  if (!b)
+    __builtin_abort ();
+  return 0;
+}