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 <ja...@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