These two patches fix PR49715, the inability to optimize unsigned -> float compares when the unsigned operand also fits into an SImode signed integer.
The first patch makes VRP handle SSA name creation during substitute_and_fold nicely and the second implements the above transform. Does anyone know if this transformation is not beneficial on any architecture? Bootstrapped on x86_64-unknown-linux-gnu, testing in progress. Thanks, Richard. 2011-07-21 Richard Guenther <rguent...@suse.de> * tree-vrp.c (num_vr_values, values_propagated): New global vars. (get_value_range): For out-of-range SSA names or names created after propagation return a read-only varying range. (dump_all_value_ranges): Adjust. (vrp_initialize): Likewise. (vrp_finalize): Likewise. Index: trunk/gcc/tree-vrp.c =================================================================== *** trunk.orig/gcc/tree-vrp.c 2011-07-21 16:23:30.000000000 +0200 --- trunk/gcc/tree-vrp.c 2011-07-21 16:46:39.000000000 +0200 *************** static assert_locus_t *asserts_for; *** 138,144 **** --- 138,146 ---- /* Value range array. After propagation, VR_VALUE[I] holds the range of values that SSA name N_I may take. */ + static unsigned num_vr_values; static value_range_t **vr_value; + static bool values_propagated; /* For a PHI node which sets SSA name N_I, VR_COUNTS[I] holds the number of executable edges we saw the last time we visited the *************** abs_extent_range (value_range_t *vr, tre *** 658,663 **** --- 660,667 ---- static value_range_t * get_value_range (const_tree var) { + static const struct value_range_d vr_const_varying + = { VR_VARYING, NULL_TREE, NULL_TREE, NULL }; value_range_t *vr; tree sym; unsigned ver = SSA_NAME_VERSION (var); *************** get_value_range (const_tree var) *** 666,675 **** --- 670,689 ---- if (! vr_value) return NULL; + /* If we query the range for a new SSA name return an unmodifiable VARYING. + We should get here at most from the substitute-and-fold stage which + will never try to change values. */ + if (ver >= num_vr_values) + return CONST_CAST (value_range_t *, &vr_const_varying); + vr = vr_value[ver]; if (vr) return vr; + /* After propagation finished do not allocate new value-ranges. */ + if (values_propagated) + return CONST_CAST (value_range_t *, &vr_const_varying); + /* Create a default value range. */ vr_value[ver] = vr = XCNEW (value_range_t); *************** dump_all_value_ranges (FILE *file) *** 3931,3937 **** { size_t i; ! for (i = 0; i < num_ssa_names; i++) { if (vr_value[i]) { --- 3945,3951 ---- { size_t i; ! for (i = 0; i < num_vr_values; i++) { if (vr_value[i]) { *************** vrp_initialize (void) *** 5593,5599 **** { basic_block bb; ! vr_value = XCNEWVEC (value_range_t *, num_ssa_names); vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names); FOR_EACH_BB (bb) --- 5607,5615 ---- { basic_block bb; ! values_propagated = false; ! num_vr_values = num_ssa_names; ! vr_value = XCNEWVEC (value_range_t *, num_vr_values); vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names); FOR_EACH_BB (bb) *************** vrp_visit_assignment_or_call (gimple stm *** 5720,5726 **** static inline value_range_t get_vr_for_comparison (int i) { ! value_range_t vr = *(vr_value[i]); /* If name N_i does not have a valid range, use N_i as its own range. This allows us to compare against names that may --- 5736,5742 ---- static inline value_range_t get_vr_for_comparison (int i) { ! value_range_t vr = *get_value_range (ssa_name (i)); /* If name N_i does not have a valid range, use N_i as its own range. This allows us to compare against names that may *************** static void *** 7733,7739 **** vrp_finalize (void) { size_t i; ! unsigned num = num_ssa_names; if (dump_file) { --- 7749,7756 ---- vrp_finalize (void) { size_t i; ! ! values_propagated = true; if (dump_file) { *************** vrp_finalize (void) *** 7753,7759 **** identify_jump_threads (); /* Free allocated memory. */ ! for (i = 0; i < num; i++) if (vr_value[i]) { BITMAP_FREE (vr_value[i]->equiv); --- 7770,7776 ---- identify_jump_threads (); /* Free allocated memory. */ ! for (i = 0; i < num_vr_values; i++) if (vr_value[i]) { BITMAP_FREE (vr_value[i]->equiv); 2011-07-21 Richard Guenther <rguent...@suse.de> PR tree-optimization/49715 * tree-vrp.c (simplify_float_conversion_using_ranges): New function. (simplify_stmt_using_ranges): Call it. * gcc.target/i386/pr49715.c: New testcase. Index: gcc/tree-vrp.c =================================================================== *** gcc/tree-vrp.c.orig 2011-07-21 16:46:39.000000000 +0200 --- gcc/tree-vrp.c 2011-07-21 16:56:08.000000000 +0200 *************** simplify_conversion_using_ranges (gimple *** 7448,7453 **** --- 7448,7496 ---- return true; } + /* Simplify a conversion from integral SSA name to float in STMT. */ + + static bool + simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt) + { + tree rhs1 = gimple_assign_rhs1 (stmt); + value_range_t *vr = get_value_range (rhs1); + tree tem; + gimple conv; + + /* It's not interesting to widen anything smaller than SImode. */ + if (TYPE_PRECISION (TREE_TYPE (rhs1)) < GET_MODE_PRECISION (SImode) + || (!TYPE_UNSIGNED (TREE_TYPE (rhs1)) + && TYPE_PRECISION (TREE_TYPE (rhs1)) == GET_MODE_PRECISION (SImode))) + return false; + + /* We can only handle constant ranges. */ + if (vr->type != VR_RANGE + || TREE_CODE (vr->min) != INTEGER_CST + || TREE_CODE (vr->max) != INTEGER_CST) + return false; + + /* Try if the value fits in a signed SImode integer, that's the only + interesting case. */ + if (!double_int_fits_to_tree_p (intSI_type_node, + tree_to_double_int (vr->min)) + || !double_int_fits_to_tree_p (intSI_type_node, + tree_to_double_int (vr->max))) + return false; + + /* It works, insert a truncation or sign-change before the + float conversion. */ + tem = create_tmp_var (intSI_type_node, NULL); + conv = gimple_build_assign_with_ops (NOP_EXPR, tem, rhs1, NULL_TREE); + tem = make_ssa_name (tem, conv); + gimple_assign_set_lhs (conv, tem); + gsi_insert_before (gsi, conv, GSI_SAME_STMT); + gimple_assign_set_rhs1 (stmt, tem); + update_stmt (stmt); + + return true; + } + /* Simplify STMT using ranges if possible. */ static bool *************** simplify_stmt_using_ranges (gimple_stmt_ *** 7507,7512 **** --- 7550,7561 ---- return simplify_conversion_using_ranges (stmt); break; + case FLOAT_EXPR: + if (TREE_CODE (rhs1) == SSA_NAME + && INTEGRAL_TYPE_P (TREE_TYPE (rhs1))) + return simplify_float_conversion_using_ranges (gsi, stmt); + break; + default: break; } Index: gcc/testsuite/gcc.target/i386/pr49715.c =================================================================== *** /dev/null 1970-01-01 00:00:00.000000000 +0000 --- gcc/testsuite/gcc.target/i386/pr49715.c 2011-07-21 16:55:57.000000000 +0200 *************** *** 0 **** --- 1,9 ---- + /* { dg-do compile } */ + /* { dg-options "-O2 -msse -mfpmath=sse" } */ + + float func(unsigned x) + { + return (x & 0xfffff) * 0.01f; + } + + /* { dg-final { scan-assembler-times "cvtsi2ss" 1 } } */