This implements what forward_propagate_comparison does (and fold for a part). This leaves the first loop backwards over stmts in a BB in forwprop doing only address forward propagation (just in case we want to separate that from the "folding" transforms).
It also makes the two conflicting transforms !compare -> inverted-compare and X | !Y -> Y <= X (and friends) trigger in a more random fashion which means we now generate better code for gcc.dg/tree-ssa/forwprop-28.c (on x86) but the transform this testcase is testing for triggers less often. I have simply adjusted the testcase. Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2014-11-13 Richard Biener <rguent...@suse.de> * match.pd: Add tcc_comparison, inverted_tcc_comparison and inverted_tcc_comparison_with_nans operator lists. Use tcc_comparison in the truth_valued_p predicate definition. Restrict logical_inverted_value with bit_xor to integral types. Build a boolean true for simplifying x |^ !x because of vector types. Implement patterns from forward_propagate_comparison * tree-ssa-forwprop.c (forward_propagate_comparison): Remove. (get_prop_dest_stmt): Likewise. (pass_forwprop::execute): Do not call it. * fold-const.c (fold_unary_loc): Remove the pattern here. * gcc.dg/tree-ssa/forwprop-28.c: Adjust. Index: trunk/gcc/match.pd =================================================================== *** trunk.orig/gcc/match.pd 2014-11-13 12:38:20.337833493 +0100 --- trunk/gcc/match.pd 2014-11-13 12:44:40.370816862 +0100 *************** along with GCC; see the file COPYING3. *** 31,36 **** --- 31,44 ---- CONSTANT_CLASS_P tree_expr_nonnegative_p) + /* Operator lists. */ + (define_operator_list tcc_comparison + lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt) + (define_operator_list inverted_tcc_comparison + ge gt ne eq lt le ordered unordered ge gt le lt ltgt uneq) + (define_operator_list inverted_tcc_comparison_with_nans + unge ungt ne eq unlt unle ordered unordered ge gt le lt ltgt uneq) + /* Simplifications of operations with one constant operand and simplifications to constants or single values. */ *************** along with GCC; see the file COPYING3. *** 172,178 **** (match truth_valued_p @0 (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))) ! (for op (lt le eq ne ge gt truth_and truth_andif truth_or truth_orif truth_xor) (match truth_valued_p (op @0 @1))) (match truth_valued_p --- 180,186 ---- (match truth_valued_p @0 (if (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))) ! (for op (tcc_comparison truth_and truth_andif truth_or truth_orif truth_xor) (match truth_valued_p (op @0 @1))) (match truth_valued_p *************** along with GCC; see the file COPYING3. *** 187,193 **** (ne truth_valued_p@0 integer_onep) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))))) (match (logical_inverted_value @0) ! (bit_xor truth_valued_p@0 integer_onep)) /* X & !X -> 0. */ (simplify --- 195,202 ---- (ne truth_valued_p@0 integer_onep) (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))))) (match (logical_inverted_value @0) ! (bit_xor truth_valued_p@0 integer_onep) ! (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))))) /* X & !X -> 0. */ (simplify *************** along with GCC; see the file COPYING3. *** 197,203 **** (for op (bit_ior bit_xor) (simplify (op:c truth_valued_p@0 (logical_inverted_value @0)) ! { build_one_cst (type); })) (for bitop (bit_and bit_ior) rbitop (bit_ior bit_and) --- 206,212 ---- (for op (bit_ior bit_xor) (simplify (op:c truth_valued_p@0 (logical_inverted_value @0)) ! { constant_boolean_node (true, type); })) (for bitop (bit_and bit_ior) rbitop (bit_ior bit_and) *************** along with GCC; see the file COPYING3. *** 638,640 **** --- 647,688 ---- (simplify (cond (logical_inverted_value truth_valued_p@0) @1 @2) (cond @0 @2 @1)) + + + /* Simplifications of comparisons. */ + + /* We can simplify a logical negation of a comparison to the + inverted comparison. As we cannot compute an expression + operator using invert_tree_comparison we have to simulate + that with expression code iteration. */ + (for cmp (tcc_comparison) + icmp (inverted_tcc_comparison) + ncmp (inverted_tcc_comparison_with_nans) + /* Ideally we'd like to combine the following two patterns + and handle some more cases by using + (logical_inverted_value (cmp @0 @1)) + here but for that genmatch would need to "inline" that. + For now implement what forward_propagate_comparison did. */ + (simplify + (bit_not (cmp @0 @1)) + (if (VECTOR_TYPE_P (type) + || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1)) + /* Comparison inversion may be impossible for trapping math, + invert_tree_comparison will tell us. But we can't use + a computed operator in the replacement tree thus we have + to play the trick below. */ + (with { enum tree_code ic = invert_tree_comparison + (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); } + (if (ic == icmp) + (icmp @0 @1)) + (if (ic == ncmp) + (ncmp @0 @1))))) + (simplify + (bit_xor (cmp @0 @1) integer_onep) + (if (INTEGRAL_TYPE_P (type)) + (with { enum tree_code ic = invert_tree_comparison + (cmp, HONOR_NANS (TYPE_MODE (TREE_TYPE (@0)))); } + (if (ic == icmp) + (icmp @0 @1)) + (if (ic == ncmp) + (ncmp @0 @1)))))) Index: trunk/gcc/tree-ssa-forwprop.c =================================================================== *** trunk.orig/gcc/tree-ssa-forwprop.c 2014-11-13 12:38:20.337833493 +0100 --- trunk/gcc/tree-ssa-forwprop.c 2014-11-13 12:44:40.371816862 +0100 *************** fwprop_invalidate_lattice (tree name) *** 233,270 **** } - /* Get the next statement we can propagate NAME's value into skipping - trivial copies. Returns the statement that is suitable as a - propagation destination or NULL_TREE if there is no such one. - This only returns destinations in a single-use chain. FINAL_NAME_P - if non-NULL is written to the ssa name that represents the use. */ - - static gimple - get_prop_dest_stmt (tree name, tree *final_name_p) - { - use_operand_p use; - gimple use_stmt; - - do { - /* If name has multiple uses, bail out. */ - if (!single_imm_use (name, &use, &use_stmt)) - return NULL; - - /* If this is not a trivial copy, we found it. */ - if (!gimple_assign_ssa_name_copy_p (use_stmt) - || gimple_assign_rhs1 (use_stmt) != name) - break; - - /* Continue searching uses of the copy destination. */ - name = gimple_assign_lhs (use_stmt); - } while (1); - - if (final_name_p) - *final_name_p = name; - - return use_stmt; - } - /* Get the statement we can propagate from into NAME skipping trivial copies. Returns the statement which defines the propagation source or NULL_TREE if there is no such one. --- 233,238 ---- *************** forward_propagate_addr_expr (tree name, *** 1060,1149 **** } - /* Forward propagate the comparison defined in *DEFGSI like - cond_1 = x CMP y to uses of the form - a_1 = (T')cond_1 - a_1 = !cond_1 - a_1 = cond_1 != 0 - Returns true if stmt is now unused. Advance DEFGSI to the next - statement. */ - - static bool - forward_propagate_comparison (gimple_stmt_iterator *defgsi) - { - gimple stmt = gsi_stmt (*defgsi); - tree name = gimple_assign_lhs (stmt); - gimple use_stmt; - tree tmp = NULL_TREE; - gimple_stmt_iterator gsi; - enum tree_code code; - tree lhs; - - /* Don't propagate ssa names that occur in abnormal phis. */ - if ((TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs1 (stmt))) - || (TREE_CODE (gimple_assign_rhs2 (stmt)) == SSA_NAME - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_assign_rhs2 (stmt)))) - goto bailout; - - /* Do not un-cse comparisons. But propagate through copies. */ - use_stmt = get_prop_dest_stmt (name, &name); - if (!use_stmt - || !is_gimple_assign (use_stmt)) - goto bailout; - - code = gimple_assign_rhs_code (use_stmt); - lhs = gimple_assign_lhs (use_stmt); - if (!INTEGRAL_TYPE_P (TREE_TYPE (lhs))) - goto bailout; - - /* We can propagate the condition into a statement that - computes the logical negation of the comparison result. */ - if ((code == BIT_NOT_EXPR - && TYPE_PRECISION (TREE_TYPE (lhs)) == 1) - || (code == BIT_XOR_EXPR - && integer_onep (gimple_assign_rhs2 (use_stmt)))) - { - tree type = TREE_TYPE (gimple_assign_rhs1 (stmt)); - bool nans = HONOR_NANS (TYPE_MODE (type)); - enum tree_code inv_code; - inv_code = invert_tree_comparison (gimple_assign_rhs_code (stmt), nans); - if (inv_code == ERROR_MARK) - goto bailout; - - tmp = build2 (inv_code, TREE_TYPE (lhs), gimple_assign_rhs1 (stmt), - gimple_assign_rhs2 (stmt)); - } - else - goto bailout; - - gsi = gsi_for_stmt (use_stmt); - gimple_assign_set_rhs_from_tree (&gsi, unshare_expr (tmp)); - use_stmt = gsi_stmt (gsi); - update_stmt (use_stmt); - - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, " Replaced '"); - print_gimple_expr (dump_file, stmt, 0, dump_flags); - fprintf (dump_file, "' with '"); - print_gimple_expr (dump_file, use_stmt, 0, dump_flags); - fprintf (dump_file, "'\n"); - } - - /* When we remove stmt now the iterator defgsi goes off it's current - sequence, hence advance it now. */ - gsi_next (defgsi); - - /* Remove defining statements. */ - return remove_prop_source_from_use (name); - - bailout: - gsi_next (defgsi); - return false; - } - - /* Helper function for simplify_gimple_switch. Remove case labels that have values outside the range of the new type. */ --- 1028,1033 ---- *************** pass_forwprop::execute (function *fun) *** 2316,2326 **** else gsi_next (&gsi); } - else if (TREE_CODE_CLASS (code) == tcc_comparison) - { - if (forward_propagate_comparison (&gsi)) - cfg_changed = true; - } else gsi_next (&gsi); } --- 2200,2205 ---- Index: trunk/gcc/fold-const.c =================================================================== *** trunk.orig/gcc/fold-const.c 2014-11-13 12:38:20.337833493 +0100 --- trunk/gcc/fold-const.c 2014-11-13 12:44:40.376816862 +0100 *************** fold_unary_loc (location_t loc, enum tre *** 7938,7955 **** if (i == count) return build_vector (type, elements); } - else if (COMPARISON_CLASS_P (arg0) - && (VECTOR_TYPE_P (type) - || (INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) == 1))) - { - tree op_type = TREE_TYPE (TREE_OPERAND (arg0, 0)); - enum tree_code subcode = invert_tree_comparison (TREE_CODE (arg0), - HONOR_NANS (TYPE_MODE (op_type))); - if (subcode != ERROR_MARK) - return build2_loc (loc, subcode, type, TREE_OPERAND (arg0, 0), - TREE_OPERAND (arg0, 1)); - } - return NULL_TREE; --- 7938,7943 ---- Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c =================================================================== *** trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c 2014-11-13 12:38:20.337833493 +0100 --- trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c 2014-11-13 12:51:11.918799728 +0100 *************** test_8 (int code) *** 79,84 **** oof (); } ! /* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 8 "forwprop1"} } */ /* { dg-final { cleanup-tree-dump "forwprop1" } } */ --- 79,89 ---- oof (); } ! /* ??? This used to check for 8 times transforming the combined conditional ! to a ordered compare. But the transform does not trigger if we transform ! the negated code == 22 compare to code != 22 first. It turns out if ! we do that we even generate better code on x86 at least. */ ! ! /* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 4 "forwprop1"} } */ /* { dg-final { cleanup-tree-dump "forwprop1" } } */