The following patch teaches VRP to disregard the intermediate conversion in a sequence (T1)(T2)val if that sequence is value-preserving for val. There are possibly some more cases that could be handled when a sign-change is involved but the following is a first safe step.
Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Richard. 2011-07-07 Richard Guenther <rguent...@suse.de> * tree-vrp.c (simplify_conversion_using_ranges): New function. (simplify_stmt_using_ranges): Call it. * gcc.dg/tree-ssa/vrp58.c: New testcase. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c (revision 175962) --- gcc/tree-vrp.c (working copy) *************** simplify_switch_using_ranges (gimple stm *** 7342,7347 **** --- 7342,7378 ---- return false; } + /* Simplify an integral conversion from an SSA name in STMT. */ + + static bool + simplify_conversion_using_ranges (gimple stmt) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + gimple def_stmt = SSA_NAME_DEF_STMT (rhs1); + value_range_t *final, *inner; + + /* Obtain final and inner value-ranges for a conversion + sequence (final-type)(intermediate-type)inner-type. */ + final = get_value_range (gimple_assign_lhs (stmt)); + if (final->type != VR_RANGE) + return false; + if (!is_gimple_assign (def_stmt) + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt))) + return false; + rhs1 = gimple_assign_rhs1 (def_stmt); + if (TREE_CODE (rhs1) != SSA_NAME) + return false; + inner = get_value_range (rhs1); + if (inner->type != VR_RANGE) + return false; + if (!tree_int_cst_equal (final->min, inner->min) + || !tree_int_cst_equal (final->max, inner->max)) + return false; + gimple_assign_set_rhs1 (stmt, rhs1); + update_stmt (stmt); + return true; + } + /* Simplify STMT using ranges if possible. */ static bool *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7351,7356 **** --- 7382,7388 ---- if (is_gimple_assign (stmt)) { enum tree_code rhs_code = gimple_assign_rhs_code (stmt); + tree rhs1 = gimple_assign_rhs1 (stmt); switch (rhs_code) { *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7364,7370 **** or identity if the RHS is zero or one, and the LHS are known to be boolean values. Transform all TRUTH_*_EXPR into BIT_*_EXPR if both arguments are known to be boolean values. */ ! if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) return simplify_truth_ops_using_ranges (gsi, stmt); break; --- 7396,7402 ---- or identity if the RHS is zero or one, and the LHS are known to be boolean values. Transform all TRUTH_*_EXPR into BIT_*_EXPR if both arguments are known to be boolean values. */ ! if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) return simplify_truth_ops_using_ranges (gsi, stmt); break; *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7373,7387 **** than zero and the second operand is an exact power of two. */ case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR: ! if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt))) && integer_pow2p (gimple_assign_rhs2 (stmt))) return simplify_div_or_mod_using_ranges (stmt); break; /* Transform ABS (X) into X or -X as appropriate. */ case ABS_EXPR: ! if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME ! && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) return simplify_abs_using_ranges (stmt); break; --- 7405,7419 ---- than zero and the second operand is an exact power of two. */ case TRUNC_DIV_EXPR: case TRUNC_MOD_EXPR: ! if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1)) && integer_pow2p (gimple_assign_rhs2 (stmt))) return simplify_div_or_mod_using_ranges (stmt); break; /* Transform ABS (X) into X or -X as appropriate. */ case ABS_EXPR: ! if (TREE_CODE (rhs1) == SSA_NAME ! && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) return simplify_abs_using_ranges (stmt); break; *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7390,7399 **** /* Optimize away BIT_AND_EXPR and BIT_IOR_EXPR if all the bits being cleared are already cleared or all the bits being set are already set. */ ! if (INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (stmt)))) return simplify_bit_ops_using_ranges (gsi, stmt); break; default: break; } --- 7422,7437 ---- /* Optimize away BIT_AND_EXPR and BIT_IOR_EXPR if all the bits being cleared are already cleared or all the bits being set are already set. */ ! if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) return simplify_bit_ops_using_ranges (gsi, stmt); break; + CASE_CONVERT: + if (TREE_CODE (rhs1) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) + return simplify_conversion_using_ranges (stmt); + break; + default: break; } Index: gcc/testsuite/gcc.dg/tree-ssa/vrp58.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/vrp58.c (revision 0) --- gcc/testsuite/gcc.dg/tree-ssa/vrp58.c (revision 0) *************** *** 0 **** --- 1,12 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -fdump-tree-vrp1-details" } */ + + long long + foo (long long a, signed char b, signed char c) + { + int bc = b * c; + return a + (short)bc; + } + + /* { dg-final { scan-tree-dump "Folded into" "vrp1" } } */ + /* { dg-final { cleanup-tree-dump "vrp1" } } */