This is the actual patch for fixing the binary expression cases in PR49806 - adding unary expressions is easy but will slightly convolute the code.
Only lightly tested sofar, bootstrap and regtest pending for x86_64-unknown-linux-gnu. Any comments on general profitability issues? Thanks, Richard. 2011-07-29 Richard Guenther <rguent...@suse.de> PR tree-optimization/49806 * tree-vrp.c (range_fits_type_p): Move earlier. (simplify_converted_operation_using_ranges): New function. (simplify_stmt_using_ranges): Call it. * gcc.dg/tree-ssa/vrp47.c: Adjust. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c.orig 2011-07-29 14:31:59.000000000 +0200 --- gcc/tree-vrp.c 2011-07-29 14:32:00.000000000 +0200 *************** simplify_switch_using_ranges (gimple stm *** 7314,7319 **** --- 7314,7532 ---- return false; } + /* Return whether the value range *VR fits in an integer type specified + by PRECISION and UNSIGNED_P. */ + + static bool + range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p) + { + tree src_type; + unsigned src_precision; + double_int tem; + + /* We can only handle integral and pointer types. */ + src_type = TREE_TYPE (vr->min); + if (!INTEGRAL_TYPE_P (src_type) + && !POINTER_TYPE_P (src_type)) + return false; + + /* An extension is always fine, so is an identity transform. */ + src_precision = TYPE_PRECISION (TREE_TYPE (vr->min)); + if (src_precision < precision + || (src_precision == precision + && TYPE_UNSIGNED (src_type) == unsigned_p)) + return true; + + /* Now we can only handle ranges with constant bounds. */ + if (vr->type != VR_RANGE + || TREE_CODE (vr->min) != INTEGER_CST + || TREE_CODE (vr->max) != INTEGER_CST) + return false; + + /* For precision-preserving sign-changes the MSB of the double-int + has to be clear. */ + if (src_precision == precision + && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0) + return false; + + /* Then we can perform the conversion on both ends and compare + the result for equality. */ + tem = double_int_ext (tree_to_double_int (vr->min), precision, unsigned_p); + if (!double_int_equal_p (tree_to_double_int (vr->min), tem)) + return false; + tem = double_int_ext (tree_to_double_int (vr->max), precision, unsigned_p); + if (!double_int_equal_p (tree_to_double_int (vr->max), tem)) + return false; + + return true; + } + + /* Convert an operation to the type of its converted result. The conversion + statement is STMT. Return true if we performed the replacement. */ + + static bool + simplify_converted_operation_using_ranges (gimple stmt) + { + tree lhs, op_result, rhs1, rhs1_def_rhs, rhs2, rhs2_def_rhs, tem, var, iptype; + enum tree_code op_code; + gimple op, rhs1_def, rhs2_def, newop; + gimple_stmt_iterator gsi; + value_range_t rhs1_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; + value_range_t rhs2_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; + value_range_t res_vr = { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }; + unsigned orig_precision, precision; + bool orig_unsigned_p, unsigned_p; + + lhs = gimple_assign_lhs (stmt); + op_result = gimple_assign_rhs1 (stmt); + if (TREE_CODE (op_result) != SSA_NAME + || !has_single_use (op_result)) + return false; + op = SSA_NAME_DEF_STMT (op_result); + if (!is_gimple_assign (op)) + return false; + op_code = gimple_assign_rhs_code (op); + if (TREE_CODE_CLASS (op_code) != tcc_binary) + return false; + rhs1 = gimple_assign_rhs1 (op); + rhs2 = gimple_assign_rhs2 (op); + if (TREE_CODE (rhs1) != SSA_NAME + || (TREE_CODE (rhs2) != SSA_NAME + && TREE_CODE (rhs2) != INTEGER_CST)) + return false; + rhs1_def = SSA_NAME_DEF_STMT (rhs1); + if (!has_single_use (rhs1) + || !is_gimple_assign (rhs1_def) + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (rhs1_def))) + return false; + rhs1_def_rhs = gimple_assign_rhs1 (rhs1_def); + if (TREE_CODE (rhs2) == SSA_NAME) + { + rhs2_def = SSA_NAME_DEF_STMT (rhs2); + if (!has_single_use (rhs2) + || !is_gimple_assign (rhs2_def) + || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (rhs2_def))) + return false; + rhs2_def_rhs = gimple_assign_rhs1 (rhs2_def); + } + else + rhs2_def_rhs = rhs2; + + /* Now we have matched the statement pattern + + rhs1 = (T1)x; + rhs2 = (T1)y; + op_result = rhs1 OP rhs2; + lhs = (T2)op_result; + + We want to compute rhs1 OP rhs2 in type T2 to get rid of the + final conversion, either eliminating the conversions to T1 + as well, or adjusting them accordingly. + For this to be valid we need to simulate rhs1 OP rhs2 in + infinite precision and verify the result fits both in T1 and T2. */ + orig_precision = TYPE_PRECISION (TREE_TYPE (op_result)); + orig_unsigned_p = TYPE_UNSIGNED (TREE_TYPE (op_result)); + precision = TYPE_PRECISION (TREE_TYPE (lhs)); + unsigned_p = TYPE_UNSIGNED (TREE_TYPE (lhs)); + + /* Restrict this transformation to seemingly profitable cases which + include a non-mode-precision operation type or a final truncation + and a new operation precision that matches its mode-precision. */ + if (!(((orig_precision + != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (op_result)))) + || precision < orig_precision) + && precision == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (lhs))))) + return false; + + /* Of course x and y have to have value-ranges that fit in both T1 + and T2 as well. */ + rhs1_vr = *get_value_range (rhs1_def_rhs); + if (rhs1_vr.type != VR_RANGE + || TREE_CODE (rhs1_vr.min) != INTEGER_CST + || TREE_CODE (rhs1_vr.max) != INTEGER_CST) + return false; + if (TREE_CODE (rhs2) == SSA_NAME) + { + rhs2_vr = *get_value_range (rhs2_def_rhs); + if (rhs2_vr.type != VR_RANGE + || TREE_CODE (rhs2_vr.min) != INTEGER_CST + || TREE_CODE (rhs2_vr.max) != INTEGER_CST) + return false; + } + else + set_value_range_to_value (&rhs2_vr, rhs2, NULL); + if (!range_fits_type_p (&rhs1_vr, orig_precision, orig_unsigned_p) + || !range_fits_type_p (&rhs2_vr, orig_precision, orig_unsigned_p) + || !range_fits_type_p (&rhs1_vr, precision, unsigned_p) + || !range_fits_type_p (&rhs2_vr, precision, unsigned_p)) + return false; + + /* Simulate it in infinite precision, if possible and check if the + result fits. */ + if (orig_precision > HOST_BITS_PER_WIDE_INT + || precision > HOST_BITS_PER_WIDE_INT) + return false; + iptype = build_nonstandard_integer_type (2 * HOST_BITS_PER_WIDE_INT, 0); + rhs1_vr.min = fold_convert (iptype, rhs1_vr.min); + rhs1_vr.max = fold_convert (iptype, rhs1_vr.max); + rhs2_vr.min = fold_convert (iptype, rhs2_vr.min); + rhs2_vr.max = fold_convert (iptype, rhs2_vr.max); + extract_range_from_binary_expr_1 (&res_vr, + op_code, iptype, &rhs1_vr, &rhs2_vr); + if (res_vr.type != VR_RANGE + || !range_fits_type_p (&res_vr, orig_precision, orig_unsigned_p) + || !range_fits_type_p (&res_vr, precision, unsigned_p)) + return false; + + var = create_tmp_reg (TREE_TYPE (lhs), NULL); + + /* Re-write the operand conversions. */ + if (!useless_type_conversion_p (TREE_TYPE (lhs), + TREE_TYPE (rhs1_def_rhs))) + { + gsi = gsi_for_stmt (rhs1_def); + newop = gimple_build_assign_with_ops (NOP_EXPR, var, rhs1_def_rhs, + NULL_TREE); + rhs1 = make_ssa_name (var, newop); + gimple_assign_set_lhs (newop, rhs1); + gsi_insert_before (&gsi, newop, GSI_SAME_STMT); + } + else + rhs1 = rhs1_def_rhs; + if (TREE_CODE (rhs2) == SSA_NAME) + { + if (!useless_type_conversion_p (TREE_TYPE (lhs), + TREE_TYPE (rhs2_def_rhs))) + { + gsi = gsi_for_stmt (rhs2_def); + newop = gimple_build_assign_with_ops (NOP_EXPR, var, rhs2_def_rhs, + NULL_TREE); + rhs2 = make_ssa_name (var, newop); + gimple_assign_set_lhs (newop, rhs2); + gsi_insert_before (&gsi, newop, GSI_SAME_STMT); + } + else + rhs2 = rhs2_def_rhs; + } + else + rhs2 = fold_convert (TREE_TYPE (lhs), rhs2); + + /* Re-write the operation in the target type. */ + gsi = gsi_for_stmt (op); + var = create_tmp_reg (TREE_TYPE (lhs), NULL); + newop = gimple_build_assign_with_ops (op_code, var, rhs1, rhs2); + tem = make_ssa_name (var, newop); + gimple_assign_set_lhs (newop, tem); + gsi_insert_before (&gsi, newop, GSI_SAME_STMT); + + /* Adjust the final conversion. */ + gimple_assign_set_rhs1 (stmt, tem); + gimple_assign_set_rhs_code (stmt, SSA_NAME); + update_stmt (stmt); + + return true; + } + /* Simplify an integral conversion from an SSA name in STMT. */ static bool *************** simplify_conversion_using_ranges (gimple *** 7374,7426 **** return true; } - /* Return whether the value range *VR fits in an integer type specified - by PRECISION and UNSIGNED_P. */ - - static bool - range_fits_type_p (value_range_t *vr, unsigned precision, bool unsigned_p) - { - tree src_type; - unsigned src_precision; - double_int tem; - - /* We can only handle integral and pointer types. */ - src_type = TREE_TYPE (vr->min); - if (!INTEGRAL_TYPE_P (src_type) - && !POINTER_TYPE_P (src_type)) - return false; - - /* An extension is always fine, so is an identity transform. */ - src_precision = TYPE_PRECISION (TREE_TYPE (vr->min)); - if (src_precision < precision - || (src_precision == precision - && TYPE_UNSIGNED (src_type) == unsigned_p)) - return true; - - /* Now we can only handle ranges with constant bounds. */ - if (vr->type != VR_RANGE - || TREE_CODE (vr->min) != INTEGER_CST - || TREE_CODE (vr->max) != INTEGER_CST) - return false; - - /* For precision-preserving sign-changes the MSB of the double-int - has to be clear. */ - if (src_precision == precision - && (TREE_INT_CST_HIGH (vr->min) | TREE_INT_CST_HIGH (vr->max)) < 0) - return false; - - /* Then we can perform the conversion on both ends and compare - the result for equality. */ - tem = double_int_ext (tree_to_double_int (vr->min), precision, unsigned_p); - if (!double_int_equal_p (tree_to_double_int (vr->min), tem)) - return false; - tem = double_int_ext (tree_to_double_int (vr->max), precision, unsigned_p); - if (!double_int_equal_p (tree_to_double_int (vr->max), tem)) - return false; - - return true; - } - /* Simplify a conversion from integral SSA name to float in STMT. */ static bool --- 7587,7592 ---- *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7540,7546 **** CASE_CONVERT: if (TREE_CODE (rhs1) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) ! return simplify_conversion_using_ranges (stmt); break; case FLOAT_EXPR: --- 7706,7713 ---- CASE_CONVERT: if (TREE_CODE (rhs1) == SSA_NAME && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) ! return (simplify_conversion_using_ranges (stmt) ! || simplify_converted_operation_using_ranges (stmt)); break; case FLOAT_EXPR: Index: gcc/testsuite/gcc.dg/tree-ssa/vrp47.c =================================================================== *** gcc/testsuite/gcc.dg/tree-ssa/vrp47.c.orig 2011-07-29 14:34:56.000000000 +0200 --- gcc/testsuite/gcc.dg/tree-ssa/vrp47.c 2011-07-29 14:35:09.000000000 +0200 *************** *** 4,11 **** jumps when evaluating an && condition. VRP is not able to optimize this. */ /* { dg-do compile { target { ! "mips*-*-* s390*-*-* avr-*-* mn10300-*-*" } } } */ ! /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom" } */ ! /* { dg-options "-O2 -fdump-tree-vrp -fdump-tree-dom -march=i586" { target { i?86-*-* && ilp32 } } } */ int h(int x, int y) { --- 4,11 ---- jumps when evaluating an && condition. VRP is not able to optimize this. */ /* { dg-do compile { target { ! "mips*-*-* s390*-*-* avr-*-* mn10300-*-*" } } } */ ! /* { dg-options "-O2 -fdump-tree-vrp1" } */ ! /* { dg-options "-O2 -fdump-tree-vrp1 -march=i586" { target { i?86-*-* && ilp32 } } } */ int h(int x, int y) { *************** int f(int x) *** 36,48 **** 0 or 1. */ /* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */ ! /* This one needs more copy propagation that only happens in dom1. */ ! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "dom1" } } */ ! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" { xfail *-*-* } } } */ ! ! /* These two are fully simplified by VRP. */ ! /* { dg-final { scan-tree-dump-times "x\[^ \]* \[|\] y" 1 "vrp1" } } */ /* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */ ! /* { dg-final { cleanup-tree-dump "vrp\[0-9\]" } } */ ! /* { dg-final { cleanup-tree-dump "dom\[0-9\]" } } */ --- 36,44 ---- 0 or 1. */ /* { dg-final { scan-tree-dump-times "\[xy\]\[^ \]* !=" 0 "vrp1" } } */ ! /* These three are fully simplified by VRP. */ ! /* { dg-final { scan-tree-dump-times "x\[^ \]* & y" 1 "vrp1" } } */ ! /* { dg-final { scan-tree-dump-times "x\[^ \]* \\| y" 1 "vrp1" } } */ /* { dg-final { scan-tree-dump-times "x\[^ \]* \\^ 1" 1 "vrp1" } } */ ! /* { dg-final { cleanup-tree-dump "vrp1" } } */