[PATCH] Fix VRP handling of {ADD,SUB,MUL}_OVERFLOW (PR tree-optimization/64006)

Jakub Jelinek jakub@redhat.com
Fri Nov 21 19:18:00 GMT 2014


Hi!

As discussed on IRC and in the PR, these internal calls are quite
unique for VRP in that they return _Complex integer result,
which VRP doesn't track, but then extract using REALPART_EXPR/IMAGPART_EXPR
the two results from that _Complex int and to generate good code
it is desirable to get proper ranges of those two results.
The problem is that right now this works only on the first VRP iteration,
the REALPART_EXPR/IMAGPART_EXPR statements are handled if their operand
is set by {ADD,SUB,MUL}_OVERFLOW.  If we iterate because a VR of one
of the internal call arguments changes, nothing in the propagator marks
the REALPART_EXPR/IMAGPART_EXPR statements for reconsideration.

The following patch handles this, by making the internal calls interesting
to the propagator and returning the right SSA_PROP_* for it (depending on
whether any of the value ranges of the REALPART_EXPR/IMAGPART_EXPR immediate
uses would change or not).

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

2014-11-21  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/64006
	* tree-vrp.c (stmt_interesting_for_vrp): Return true
	for {ADD,SUB,MUL}_OVERFLOW internal calls.
	(vrp_visit_assignment_or_call): For {ADD,SUB,MUL}_OVERFLOW
	internal calls, check if any REALPART_EXPR/IMAGPART_EXPR
	immediate uses would change their value ranges and return
	SSA_PROP_INTERESTING if so, or SSA_PROP_NOT_INTERESTING
	if there are some REALPART_EXPR/IMAGPART_EXPR immediate uses
	interesting for vrp.

	* gcc.c-torture/execute/pr64006.c: New test.

--- gcc/tree-vrp.c.jj	2014-11-21 10:17:05.000000000 +0100
+++ gcc/tree-vrp.c	2014-11-21 13:12:09.895013334 +0100
@@ -6949,6 +6949,20 @@ stmt_interesting_for_vrp (gimple stmt)
 	  && (is_gimple_call (stmt)
 	      || !gimple_vuse (stmt)))
 	return true;
+      else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
+	switch (gimple_call_internal_fn (stmt))
+	  {
+	  case IFN_ADD_OVERFLOW:
+	  case IFN_SUB_OVERFLOW:
+	  case IFN_MUL_OVERFLOW:
+	    /* These internal calls return _Complex integer type,
+	       but are interesting to VRP nevertheless.  */
+	    if (lhs && TREE_CODE (lhs) == SSA_NAME)
+	      return true;
+	    break;
+	  default:
+	    break;
+	  }
     }
   else if (gimple_code (stmt) == GIMPLE_COND
 	   || gimple_code (stmt) == GIMPLE_SWITCH)
@@ -7101,6 +7115,74 @@ vrp_visit_assignment_or_call (gimple stm
 
       return SSA_PROP_NOT_INTERESTING;
     }
+  else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
+    switch (gimple_call_internal_fn (stmt))
+      {
+      case IFN_ADD_OVERFLOW:
+      case IFN_SUB_OVERFLOW:
+      case IFN_MUL_OVERFLOW:
+	/* These internal calls return _Complex integer type,
+	   which VRP does not track, but the immediate uses
+	   thereof might be interesting.  */
+	if (lhs && TREE_CODE (lhs) == SSA_NAME)
+	  {
+	    imm_use_iterator iter;
+	    use_operand_p use_p;
+	    enum ssa_prop_result res = SSA_PROP_VARYING;
+
+	    set_value_range_to_varying (get_value_range (lhs));
+
+	    FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
+	      {
+		gimple use_stmt = USE_STMT (use_p);
+		if (!is_gimple_assign (use_stmt))
+		  continue;
+		enum tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
+		if (rhs_code != REALPART_EXPR && rhs_code != IMAGPART_EXPR)
+		  continue;
+		tree rhs1 = gimple_assign_rhs1 (use_stmt);
+		tree use_lhs = gimple_assign_lhs (use_stmt);
+		if (TREE_CODE (rhs1) != rhs_code
+		    || TREE_OPERAND (rhs1, 0) != lhs
+		    || TREE_CODE (use_lhs) != SSA_NAME
+		    || !stmt_interesting_for_vrp (use_stmt)
+		    || (!INTEGRAL_TYPE_P (TREE_TYPE (use_lhs))
+			|| !TYPE_MIN_VALUE (TREE_TYPE (use_lhs))
+			|| !TYPE_MAX_VALUE (TREE_TYPE (use_lhs))))
+		  continue;
+
+		/* If there is a change in the value range for any of the
+		   REALPART_EXPR/IMAGPART_EXPR immediate uses, return
+		   SSA_PROP_INTERESTING.  If there are any REALPART_EXPR
+		   or IMAGPART_EXPR immediate uses, but none of them have
+		   a change in their value ranges, return
+		   SSA_PROP_NOT_INTERESTING.  If there are no
+		   {REAL,IMAG}PART_EXPR uses at all,
+		   return SSA_PROP_VARYING.  */
+		value_range_t new_vr = VR_INITIALIZER;
+		extract_range_basic (&new_vr, use_stmt);
+		value_range_t *old_vr = get_value_range (use_lhs);
+		if (old_vr->type != new_vr.type
+		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
+		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
+		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		  res = SSA_PROP_INTERESTING;
+		else
+		  res = SSA_PROP_NOT_INTERESTING;
+		BITMAP_FREE (new_vr.equiv);
+		if (res == SSA_PROP_INTERESTING)
+		  {
+		    *output_p = lhs;
+		    return res;
+		  }
+	      }
+
+	    return res;
+	  }
+	break;
+      default:
+	break;
+      }
 
   /* Every other statement produces no useful ranges.  */
   FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
--- gcc/testsuite/gcc.c-torture/execute/pr64006.c.jj	2014-11-21 13:22:08.185160990 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr64006.c	2014-11-21 13:29:28.259119733 +0100
@@ -0,0 +1,26 @@
+/* PR tree-optimization/64006 */
+
+int v;
+
+long __attribute__ ((noinline, noclone))
+test (long *x, int y)
+{
+  int i;
+  long s = 1;
+  for (i = 0; i < y; i++)
+    if (__builtin_mul_overflow (s, x[i], &s))
+      v++;
+  return s;
+}
+
+int
+main ()
+{
+  long d[7] = { 975, 975, 975, 975, 975, 975, 975 };
+  long r = test (d, 7);
+  if (sizeof (long) * __CHAR_BIT__ == 64 && v != 1)
+    __builtin_abort ();
+  else if (sizeof (long) * __CHAR_BIT__ == 32 && v != 4)
+    __builtin_abort ();
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list