This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][11/n] Merge from match-and-simplify, bit patterns from forwprop
- From: pinskia at gmail dot com
- To: Richard Biener <rguenther at suse dot de>
- Cc: "gcc-patches at gcc dot gnu dot org" <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 6 Nov 2014 01:10:51 -0800
- Subject: Re: [PATCH][11/n] Merge from match-and-simplify, bit patterns from forwprop
- Authentication-results: sourceware.org; auth=none
- References: <alpine dot LSU dot 2 dot 11 dot 1411060952430 dot 27850 at zhemvz dot fhfr dot qr>
> On Nov 6, 2014, at 12:55 AM, Richard Biener <rguenther@suse.de> wrote:
>
>
> This merges patterns implementing the bitwise patterns from
> tree-ssa-forwprop.c. I've removed duplicate functionality from
> fold-const.c as I found them, some may be still lurking in the
> depths.
>
> This also fixes a bug in genmatch which made user-defined predicates
> matching anything, thus
>
> (match foo
> @0
> (if ...
>
> not work (that is: ignored).
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk.
Only one small comment.
>
> Richard.
>
> 2014-11-06 Richard Biener <rguenther@suse.de>
>
> * match.pd: Implement bitwise binary and unary simplifications
> from tree-ssa-forwprop.c.
> * fold-const.c (fold_unary_loc): Remove them here.
> (fold_binary_loc): Likewise.
> * tree-ssa-forwprop.c (simplify_not_neg_expr): Remove.
> (truth_valued_ssa_name): Likewise.
> (lookup_logical_inverted_value): Likewise.
> (simplify_bitwise_binary_1): Likewise.
> (hoist_conversion_for_bitop_p): Likewise.
> (simplify_bitwise_binary_boolean): Likewise.
> (simplify_bitwise_binary): Likewise.
> (pass_forwprop::execute): Remove calls to simplify_not_neg_expr
> and simplify_bitwise_binary.
> * genmatch.c (dt_node::append_true_op): Use safe_as_a for parent.
> (decision_tree::insert): Also insert non-expressions.
>
> * gcc.dg/tree-ssa/forwprop-28.c: Adjust scanning for the
> desired transform.
>
> Index: trunk/gcc/fold-const.c
> ===================================================================
> --- trunk.orig/gcc/fold-const.c 2014-11-05 13:31:01.131942296 +0100
> +++ trunk/gcc/fold-const.c 2014-11-05 13:35:29.362930558 +0100
> @@ -8008,8 +8008,6 @@ fold_unary_loc (location_t loc, enum tre
> case BIT_NOT_EXPR:
> if (TREE_CODE (arg0) == INTEGER_CST)
> return fold_not_const (arg0, type);
> - else if (TREE_CODE (arg0) == BIT_NOT_EXPR)
> - return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
> /* Convert ~ (-A) to A - 1. */
> else if (INTEGRAL_TYPE_P (type) && TREE_CODE (arg0) == NEGATE_EXPR)
> return fold_build2_loc (loc, MINUS_EXPR, type,
> @@ -11152,26 +11150,6 @@ fold_binary_loc (location_t loc,
> arg1);
> }
>
> - /* (X & Y) | Y is (X, Y). */
> - if (TREE_CODE (arg0) == BIT_AND_EXPR
> - && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
> - return omit_one_operand_loc (loc, type, arg1, TREE_OPERAND (arg0, 0));
> - /* (X & Y) | X is (Y, X). */
> - if (TREE_CODE (arg0) == BIT_AND_EXPR
> - && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
> - && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
> - return omit_one_operand_loc (loc, type, arg1, TREE_OPERAND (arg0, 1));
> - /* X | (X & Y) is (Y, X). */
> - if (TREE_CODE (arg1) == BIT_AND_EXPR
> - && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)
> - && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1)))
> - return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1, 1));
> - /* X | (Y & X) is (Y, X). */
> - if (TREE_CODE (arg1) == BIT_AND_EXPR
> - && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
> - && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
> - return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1, 0));
> -
> /* (X & ~Y) | (~X & Y) is X ^ Y */
> if (TREE_CODE (arg0) == BIT_AND_EXPR
> && TREE_CODE (arg1) == BIT_AND_EXPR)
> @@ -11391,42 +11369,6 @@ fold_binary_loc (location_t loc,
> && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
> return omit_one_operand_loc (loc, type, integer_zero_node, arg0);
>
> - /* Canonicalize (X | C1) & C2 as (X & C2) | (C1 & C2). */
> - if (TREE_CODE (arg0) == BIT_IOR_EXPR
> - && TREE_CODE (arg1) == INTEGER_CST
> - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
> - {
> - tree tmp1 = fold_convert_loc (loc, type, arg1);
> - tree tmp2 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
> - tree tmp3 = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 1));
> - tmp2 = fold_build2_loc (loc, BIT_AND_EXPR, type, tmp2, tmp1);
> - tmp3 = fold_build2_loc (loc, BIT_AND_EXPR, type, tmp3, tmp1);
> - return
> - fold_convert_loc (loc, type,
> - fold_build2_loc (loc, BIT_IOR_EXPR,
> - type, tmp2, tmp3));
> - }
> -
> - /* (X | Y) & Y is (X, Y). */
> - if (TREE_CODE (arg0) == BIT_IOR_EXPR
> - && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0))
> - return omit_one_operand_loc (loc, type, arg1, TREE_OPERAND (arg0, 0));
> - /* (X | Y) & X is (Y, X). */
> - if (TREE_CODE (arg0) == BIT_IOR_EXPR
> - && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
> - && reorder_operands_p (TREE_OPERAND (arg0, 1), arg1))
> - return omit_one_operand_loc (loc, type, arg1, TREE_OPERAND (arg0, 1));
> - /* X & (X | Y) is (Y, X). */
> - if (TREE_CODE (arg1) == BIT_IOR_EXPR
> - && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0)
> - && reorder_operands_p (arg0, TREE_OPERAND (arg1, 1)))
> - return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1, 1));
> - /* X & (Y | X) is (Y, X). */
> - if (TREE_CODE (arg1) == BIT_IOR_EXPR
> - && operand_equal_p (arg0, TREE_OPERAND (arg1, 1), 0)
> - && reorder_operands_p (arg0, TREE_OPERAND (arg1, 0)))
> - return omit_one_operand_loc (loc, type, arg0, TREE_OPERAND (arg1, 0));
> -
> /* Fold (X ^ 1) & 1 as (X & 1) == 0. */
> if (TREE_CODE (arg0) == BIT_XOR_EXPR
> && INTEGRAL_TYPE_P (type)
> Index: trunk/gcc/match.pd
> ===================================================================
> --- trunk.orig/gcc/match.pd 2014-11-05 13:31:01.131942296 +0100
> +++ trunk/gcc/match.pd 2014-11-05 13:37:57.099924093 +0100
> @@ -113,6 +113,134 @@ along with GCC; see the file COPYING3.
> @0)
>
>
> +/* Try to fold (type) X op CST -> (type) (X op ((type-x) CST))
> + when profitable.
> + For bitwise binary operations apply operand conversions to the
> + binary operation result instead of to the operands. This allows
> + to combine successive conversions and bitwise binary operations.
> + We combine the above two cases by using a conditional convert. */
> +(for bitop (bit_and bit_ior bit_xor)
> + (simplify
> + (bitop (convert @0) (convert? @1))
> + (if (((TREE_CODE (@1) == INTEGER_CST
> + && INTEGRAL_TYPE_P (TREE_TYPE (@0))
> + && int_fits_type_p (@1, TREE_TYPE (@0))
> + /* ??? This transform conflicts with fold-const.c doing
> + Convert (T)(x & c) into (T)x & (T)c, if c is an integer
> + constants (if x has signed type, the sign bit cannot be set
> + in c). This folds extension into the BIT_AND_EXPR.
> + Restrict it to GIMPLE to avoid endless recursions. */
> + && (bitop != BIT_AND_EXPR || GIMPLE))
> + || types_compatible_p (TREE_TYPE (@0), TREE_TYPE (@1)))
> + && (/* That's a good idea if the conversion widens the operand, thus
> + after hoisting the conversion the operation will be narrower. */
> + TYPE_PRECISION (TREE_TYPE (@0)) < TYPE_PRECISION (type)
> + /* It's also a good idea if the conversion is to a non-integer
> + mode. */
> + || GET_MODE_CLASS (TYPE_MODE (type)) != MODE_INT
> + /* Or if the precision of TO is not the same as the precision
> + of its mode. */
> + || TYPE_PRECISION (type) != GET_MODE_PRECISION (TYPE_MODE (type))))
> + (convert (bitop @0 (convert @1))))))
> +
> +/* Simplify (A & B) OP0 (C & B) to (A OP0 C) & B. */
> +(for bitop (bit_and bit_ior bit_xor)
> + (simplify
> + (bitop (bit_and:c @0 @1) (bit_and @2 @1))
> + (bit_and (bitop @0 @2) @1)))
> +
> +/* (x | CST1) & CST2 -> (x & CST2) | (CST1 & CST2) */
> +(simplify
> + (bit_and (bit_ior @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
> + (bit_ior (bit_and @0 @2) (bit_and @1 @2)))
> +
> +/* Combine successive equal operations with constants. */
> +(for bitop (bit_and bit_ior bit_xor)
> + (simplify
> + (bitop (bitop @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2)
> + (bitop @0 (bitop @1 @2))))
> +
> +/* Try simple folding for X op !X, and X op X with the help
> + of the truth_valued_p and logical_inverted_value predicates. */
> +(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
> + (truth_not @0))
> +
> +(match (logical_inverted_value @0)
> + (bit_not truth_valued_p@0))
> +(match (logical_inverted_value @0)
> + (eq @0 integer_zerop)
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)))))
> +(match (logical_inverted_value @0)
> + (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
> + (bit_and:c @0 (logical_inverted_value @0))
> + { build_zero_cst (type); })
> +/* X | !X and X ^ !X -> 1, , if X is truth-valued. */
> +(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)
> + /* (x | y) & x -> x */
> + /* (x & y) | x -> x */
> + (simplify
> + (bitop:c (rbitop:c @0 @1) @0)
> + @0)
> + /* (~x | y) & x -> x & y */
> + /* (~x & y) | x -> x | y */
> + (simplify
> + (bitop:c (rbitop:c (bit_not @0) @1) @0)
> + (bitop @0 @1)))
> +
> +/* If arg1 and arg2 are booleans (or any single bit type)
> + then try to simplify:
> +
> + (~X & Y) -> X < Y
> + (X & ~Y) -> Y < X
> + (~X | Y) -> X <= Y
> + (X | ~Y) -> Y <= X
> +
> + But only do this if our result feeds into a comparison as
> + this transformation is not always a win, particularly on
> + targets with and-not instructions.
> + -> simplify_bitwise_binary_boolean */
> +(simplify
> + (ne (bit_and:c (bit_not @0) @1) integer_zerop)
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
> + && TYPE_PRECISION (TREE_TYPE (@1)) == 1)
> + (lt @0 @1)))
> +(simplify
> + (ne (bit_ior:c (bit_not @0) @1) integer_zerop)
> + (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
> + && TYPE_PRECISION (TREE_TYPE (@1)) == 1)
> + (le @0 @1)))
> +
> +/* From tree-ssa-forwprop.c:simplify_not_neg_expr. */
> +
> +/* ~~x -> x */
> +(simplify
> + (bit_not (bit_not @0))
> + @0)
> +
> +/* The corresponding (negate (negate @0)) -> @0 is in match-plusminus.pd. */
This above comment is no longer true as far as I can tell.
> +(simplify
> + (negate (negate @0))
> + @0)
Thanks,
Andrew
> +
> +
> /* Simplifications of conversions. */
>
> /* Basic strip-useless-type-conversions / strip_nops. */
> Index: trunk/gcc/tree-ssa-forwprop.c
> ===================================================================
> --- trunk.orig/gcc/tree-ssa-forwprop.c 2014-11-05 13:31:01.131942296 +0100
> +++ trunk/gcc/tree-ssa-forwprop.c 2014-11-05 13:35:29.365930558 +0100
> @@ -1253,49 +1253,6 @@ simplify_conversion_from_bitmask (gimple
> }
>
>
> -/* If we have lhs = ~x (STMT), look and see if earlier we had x = ~y.
> - If so, we can change STMT into lhs = y which can later be copy
> - propagated. Similarly for negation.
> -
> - This could trivially be formulated as a forward propagation
> - to immediate uses. However, we already had an implementation
> - from DOM which used backward propagation via the use-def links.
> -
> - It turns out that backward propagation is actually faster as
> - there's less work to do for each NOT/NEG expression we find.
> - Backwards propagation needs to look at the statement in a single
> - backlink. Forward propagation needs to look at potentially more
> - than one forward link.
> -
> - Returns true when the statement was changed. */
> -
> -static bool
> -simplify_not_neg_expr (gimple_stmt_iterator *gsi_p)
> -{
> - gimple stmt = gsi_stmt (*gsi_p);
> - tree rhs = gimple_assign_rhs1 (stmt);
> - gimple rhs_def_stmt = SSA_NAME_DEF_STMT (rhs);
> -
> - /* See if the RHS_DEF_STMT has the same form as our statement. */
> - if (is_gimple_assign (rhs_def_stmt)
> - && gimple_assign_rhs_code (rhs_def_stmt) == gimple_assign_rhs_code (stmt))
> - {
> - tree rhs_def_operand = gimple_assign_rhs1 (rhs_def_stmt);
> -
> - /* Verify that RHS_DEF_OPERAND is a suitable SSA_NAME. */
> - if (TREE_CODE (rhs_def_operand) == SSA_NAME
> - && ! SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs_def_operand))
> - {
> - gimple_assign_set_rhs_from_tree (gsi_p, rhs_def_operand);
> - stmt = gsi_stmt (*gsi_p);
> - update_stmt (stmt);
> - return true;
> - }
> - }
> -
> - return false;
> -}
> -
> /* Helper function for simplify_gimple_switch. Remove case labels that
> have values outside the range of the new type. */
>
> @@ -1714,126 +1671,6 @@ simplify_builtin_call (gimple_stmt_itera
> return false;
> }
>
> -/* Checks if expression has type of one-bit precision, or is a known
> - truth-valued expression. */
> -static bool
> -truth_valued_ssa_name (tree name)
> -{
> - gimple def;
> - tree type = TREE_TYPE (name);
> -
> - if (!INTEGRAL_TYPE_P (type))
> - return false;
> - /* Don't check here for BOOLEAN_TYPE as the precision isn't
> - necessarily one and so ~X is not equal to !X. */
> - if (TYPE_PRECISION (type) == 1)
> - return true;
> - def = SSA_NAME_DEF_STMT (name);
> - if (is_gimple_assign (def))
> - return truth_value_p (gimple_assign_rhs_code (def));
> - return false;
> -}
> -
> -/* Helper routine for simplify_bitwise_binary_1 function.
> - Return for the SSA name NAME the expression X if it mets condition
> - NAME = !X. Otherwise return NULL_TREE.
> - Detected patterns for NAME = !X are:
> - !X and X == 0 for X with integral type.
> - X ^ 1, X != 1,or ~X for X with integral type with precision of one. */
> -static tree
> -lookup_logical_inverted_value (tree name)
> -{
> - tree op1, op2;
> - enum tree_code code;
> - gimple def;
> -
> - /* If name has none-intergal type, or isn't a SSA_NAME, then
> - return. */
> - if (TREE_CODE (name) != SSA_NAME
> - || !INTEGRAL_TYPE_P (TREE_TYPE (name)))
> - return NULL_TREE;
> - def = SSA_NAME_DEF_STMT (name);
> - if (!is_gimple_assign (def))
> - return NULL_TREE;
> -
> - code = gimple_assign_rhs_code (def);
> - op1 = gimple_assign_rhs1 (def);
> - op2 = NULL_TREE;
> -
> - /* Get for EQ_EXPR or BIT_XOR_EXPR operation the second operand.
> - If CODE isn't an EQ_EXPR, BIT_XOR_EXPR, or BIT_NOT_EXPR, then return. */
> - if (code == EQ_EXPR || code == NE_EXPR
> - || code == BIT_XOR_EXPR)
> - op2 = gimple_assign_rhs2 (def);
> -
> - switch (code)
> - {
> - case BIT_NOT_EXPR:
> - if (truth_valued_ssa_name (name))
> - return op1;
> - break;
> - case EQ_EXPR:
> - /* Check if we have X == 0 and X has an integral type. */
> - if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
> - break;
> - if (integer_zerop (op2))
> - return op1;
> - break;
> - case NE_EXPR:
> - /* Check if we have X != 1 and X is a truth-valued. */
> - if (!INTEGRAL_TYPE_P (TREE_TYPE (op1)))
> - break;
> - if (integer_onep (op2) && truth_valued_ssa_name (op1))
> - return op1;
> - break;
> - case BIT_XOR_EXPR:
> - /* Check if we have X ^ 1 and X is truth valued. */
> - if (integer_onep (op2) && truth_valued_ssa_name (op1))
> - return op1;
> - break;
> - default:
> - break;
> - }
> -
> - return NULL_TREE;
> -}
> -
> -/* Optimize ARG1 CODE ARG2 to a constant for bitwise binary
> - operations CODE, if one operand has the logically inverted
> - value of the other. */
> -static tree
> -simplify_bitwise_binary_1 (enum tree_code code, tree type,
> - tree arg1, tree arg2)
> -{
> - tree anot;
> -
> - /* If CODE isn't a bitwise binary operation, return NULL_TREE. */
> - if (code != BIT_AND_EXPR && code != BIT_IOR_EXPR
> - && code != BIT_XOR_EXPR)
> - return NULL_TREE;
> -
> - /* First check if operands ARG1 and ARG2 are equal. If so
> - return NULL_TREE as this optimization is handled fold_stmt. */
> - if (arg1 == arg2)
> - return NULL_TREE;
> - /* See if we have in arguments logical-not patterns. */
> - if (((anot = lookup_logical_inverted_value (arg1)) == NULL_TREE
> - || anot != arg2)
> - && ((anot = lookup_logical_inverted_value (arg2)) == NULL_TREE
> - || anot != arg1))
> - return NULL_TREE;
> -
> - /* X & !X -> 0. */
> - if (code == BIT_AND_EXPR)
> - return fold_convert (type, integer_zero_node);
> - /* X | !X -> 1 and X ^ !X -> 1, if X is truth-valued. */
> - if (truth_valued_ssa_name (anot))
> - return fold_convert (type, integer_one_node);
> -
> - /* ??? Otherwise result is (X != 0 ? X : 1). not handled. */
> - return NULL_TREE;
> -}
> -
> /* Given a ssa_name in NAME see if it was defined by an assignment and
> set CODE to be the code and ARG1 to the first operand on the rhs and ARG2
> to the second operand on the rhs. */
> @@ -1879,353 +1716,6 @@ defcodefor_name (tree name, enum tree_co
> /* Ignore arg3 currently. */
> }
>
> -/* Return true if a conversion of an operand from type FROM to type TO
> - should be applied after performing the operation instead. */
> -
> -static bool
> -hoist_conversion_for_bitop_p (tree to, tree from)
> -{
> - /* That's a good idea if the conversion widens the operand, thus
> - after hoisting the conversion the operation will be narrower. */
> - if (TYPE_PRECISION (from) < TYPE_PRECISION (to))
> - return true;
> -
> - /* It's also a good idea if the conversion is to a non-integer mode. */
> - if (GET_MODE_CLASS (TYPE_MODE (to)) != MODE_INT)
> - return true;
> -
> - /* Or if the precision of TO is not the same as the precision
> - of its mode. */
> - if (TYPE_PRECISION (to) != GET_MODE_PRECISION (TYPE_MODE (to)))
> - return true;
> -
> - return false;
> -}
> -
> -/* GSI points to a statement of the form
> -
> - result = OP0 CODE OP1
> -
> - Where OP0 and OP1 are single bit SSA_NAMEs and CODE is either
> - BIT_AND_EXPR or BIT_IOR_EXPR.
> -
> - If OP0 is fed by a bitwise negation of another single bit SSA_NAME,
> - then we can simplify the two statements into a single LT_EXPR or LE_EXPR
> - when code is BIT_AND_EXPR and BIT_IOR_EXPR respectively.
> -
> - If a simplification is made, return TRUE, else return FALSE. */
> -static bool
> -simplify_bitwise_binary_boolean (gimple_stmt_iterator *gsi,
> - enum tree_code code,
> - tree op0, tree op1)
> -{
> - gimple op0_def_stmt = SSA_NAME_DEF_STMT (op0);
> -
> - if (!is_gimple_assign (op0_def_stmt)
> - || (gimple_assign_rhs_code (op0_def_stmt) != BIT_NOT_EXPR))
> - return false;
> -
> - tree x = gimple_assign_rhs1 (op0_def_stmt);
> - if (TREE_CODE (x) == SSA_NAME
> - && INTEGRAL_TYPE_P (TREE_TYPE (x))
> - && TYPE_PRECISION (TREE_TYPE (x)) == 1
> - && TYPE_UNSIGNED (TREE_TYPE (x)) == TYPE_UNSIGNED (TREE_TYPE (op1)))
> - {
> - enum tree_code newcode;
> -
> - gimple stmt = gsi_stmt (*gsi);
> - gimple_assign_set_rhs1 (stmt, x);
> - gimple_assign_set_rhs2 (stmt, op1);
> - if (code == BIT_AND_EXPR)
> - newcode = TYPE_UNSIGNED (TREE_TYPE (x)) ? LT_EXPR : GT_EXPR;
> - else
> - newcode = TYPE_UNSIGNED (TREE_TYPE (x)) ? LE_EXPR : GE_EXPR;
> - gimple_assign_set_rhs_code (stmt, newcode);
> - update_stmt (stmt);
> - return true;
> - }
> - return false;
> -
> -}
> -
> -/* Simplify bitwise binary operations.
> - Return true if a transformation applied, otherwise return false. */
> -
> -static bool
> -simplify_bitwise_binary (gimple_stmt_iterator *gsi)
> -{
> - gimple stmt = gsi_stmt (*gsi);
> - tree arg1 = gimple_assign_rhs1 (stmt);
> - tree arg2 = gimple_assign_rhs2 (stmt);
> - enum tree_code code = gimple_assign_rhs_code (stmt);
> - tree res;
> - tree def1_arg1, def1_arg2, def2_arg1, def2_arg2;
> - enum tree_code def1_code, def2_code;
> -
> - defcodefor_name (arg1, &def1_code, &def1_arg1, &def1_arg2);
> - defcodefor_name (arg2, &def2_code, &def2_arg1, &def2_arg2);
> -
> - /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST))
> - when profitable. */
> - if (TREE_CODE (arg2) == INTEGER_CST
> - && CONVERT_EXPR_CODE_P (def1_code)
> - && hoist_conversion_for_bitop_p (TREE_TYPE (arg1), TREE_TYPE (def1_arg1))
> - && INTEGRAL_TYPE_P (TREE_TYPE (def1_arg1))
> - && int_fits_type_p (arg2, TREE_TYPE (def1_arg1)))
> - {
> - gimple newop;
> - tree tem = make_ssa_name (TREE_TYPE (def1_arg1), NULL);
> - newop =
> - gimple_build_assign_with_ops (code, tem, def1_arg1,
> - fold_convert_loc (gimple_location (stmt),
> - TREE_TYPE (def1_arg1),
> - arg2));
> - gimple_set_location (newop, gimple_location (stmt));
> - gsi_insert_before (gsi, newop, GSI_SAME_STMT);
> - gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
> - tem, NULL_TREE, NULL_TREE);
> - update_stmt (gsi_stmt (*gsi));
> - return true;
> - }
> -
> - /* For bitwise binary operations apply operand conversions to the
> - binary operation result instead of to the operands. This allows
> - to combine successive conversions and bitwise binary operations. */
> - if (CONVERT_EXPR_CODE_P (def1_code)
> - && CONVERT_EXPR_CODE_P (def2_code)
> - && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1))
> - && hoist_conversion_for_bitop_p (TREE_TYPE (arg1), TREE_TYPE (def1_arg1)))
> - {
> - gimple newop;
> - tree tem = make_ssa_name (TREE_TYPE (def1_arg1), NULL);
> - newop = gimple_build_assign_with_ops (code, tem, def1_arg1, def2_arg1);
> - gimple_set_location (newop, gimple_location (stmt));
> - gsi_insert_before (gsi, newop, GSI_SAME_STMT);
> - gimple_assign_set_rhs_with_ops_1 (gsi, NOP_EXPR,
> - tem, NULL_TREE, NULL_TREE);
> - update_stmt (gsi_stmt (*gsi));
> - return true;
> - }
> -
> -
> - /* Simplify (A & B) OP0 (C & B) to (A OP0 C) & B. */
> - if (def1_code == def2_code
> - && def1_code == BIT_AND_EXPR
> - && operand_equal_for_phi_arg_p (def1_arg2,
> - def2_arg2))
> - {
> - tree b = def1_arg2;
> - tree a = def1_arg1;
> - tree c = def2_arg1;
> - tree inner = fold_build2 (code, TREE_TYPE (arg2), a, c);
> - /* If A OP0 C (this usually means C is the same as A) is 0
> - then fold it down correctly. */
> - if (integer_zerop (inner))
> - {
> - gimple_assign_set_rhs_from_tree (gsi, inner);
> - update_stmt (stmt);
> - return true;
> - }
> - /* If A OP0 C (this usually means C is the same as A) is a ssa_name
> - then fold it down correctly. */
> - else if (TREE_CODE (inner) == SSA_NAME)
> - {
> - tree outer = fold_build2 (def1_code, TREE_TYPE (inner),
> - inner, b);
> - gimple_assign_set_rhs_from_tree (gsi, outer);
> - update_stmt (stmt);
> - return true;
> - }
> - else
> - {
> - gimple newop;
> - tree tem;
> - tem = make_ssa_name (TREE_TYPE (arg2), NULL);
> - newop = gimple_build_assign_with_ops (code, tem, a, c);
> - gimple_set_location (newop, gimple_location (stmt));
> - /* Make sure to re-process the new stmt as it's walking upwards. */
> - gsi_insert_before (gsi, newop, GSI_NEW_STMT);
> - gimple_assign_set_rhs1 (stmt, tem);
> - gimple_assign_set_rhs2 (stmt, b);
> - gimple_assign_set_rhs_code (stmt, def1_code);
> - update_stmt (stmt);
> - return true;
> - }
> - }
> -
> - /* (a | CST1) & CST2 -> (a & CST2) | (CST1 & CST2). */
> - if (code == BIT_AND_EXPR
> - && def1_code == BIT_IOR_EXPR
> - && CONSTANT_CLASS_P (arg2)
> - && CONSTANT_CLASS_P (def1_arg2))
> - {
> - tree cst = fold_build2 (BIT_AND_EXPR, TREE_TYPE (arg2),
> - arg2, def1_arg2);
> - tree tem;
> - gimple newop;
> - if (integer_zerop (cst))
> - {
> - gimple_assign_set_rhs1 (stmt, def1_arg1);
> - update_stmt (stmt);
> - return true;
> - }
> - tem = make_ssa_name (TREE_TYPE (arg2), NULL);
> - newop = gimple_build_assign_with_ops (BIT_AND_EXPR,
> - tem, def1_arg1, arg2);
> - gimple_set_location (newop, gimple_location (stmt));
> - /* Make sure to re-process the new stmt as it's walking upwards. */
> - gsi_insert_before (gsi, newop, GSI_NEW_STMT);
> - gimple_assign_set_rhs1 (stmt, tem);
> - gimple_assign_set_rhs2 (stmt, cst);
> - gimple_assign_set_rhs_code (stmt, BIT_IOR_EXPR);
> - update_stmt (stmt);
> - return true;
> - }
> -
> - /* Combine successive equal operations with constants. */
> - if ((code == BIT_AND_EXPR
> - || code == BIT_IOR_EXPR
> - || code == BIT_XOR_EXPR)
> - && def1_code == code
> - && CONSTANT_CLASS_P (arg2)
> - && CONSTANT_CLASS_P (def1_arg2))
> - {
> - tree cst = fold_build2 (code, TREE_TYPE (arg2),
> - arg2, def1_arg2);
> - gimple_assign_set_rhs1 (stmt, def1_arg1);
> - gimple_assign_set_rhs2 (stmt, cst);
> - update_stmt (stmt);
> - return true;
> - }
> -
> - /* Try simple folding for X op !X, and X op X. */
> - res = simplify_bitwise_binary_1 (code, TREE_TYPE (arg1), arg1, arg2);
> - if (res != NULL_TREE)
> - {
> - gimple_assign_set_rhs_from_tree (gsi, res);
> - update_stmt (gsi_stmt (*gsi));
> - return true;
> - }
> -
> - if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
> - {
> - enum tree_code ocode = code == BIT_AND_EXPR ? BIT_IOR_EXPR : BIT_AND_EXPR;
> - if (def1_code == ocode)
> - {
> - tree x = arg2;
> - enum tree_code coden;
> - tree a1, a2;
> - /* ( X | Y) & X -> X */
> - /* ( X & Y) | X -> X */
> - if (x == def1_arg1
> - || x == def1_arg2)
> - {
> - gimple_assign_set_rhs_from_tree (gsi, x);
> - update_stmt (gsi_stmt (*gsi));
> - return true;
> - }
> -
> - defcodefor_name (def1_arg1, &coden, &a1, &a2);
> - /* (~X | Y) & X -> X & Y */
> - /* (~X & Y) | X -> X | Y */
> - if (coden == BIT_NOT_EXPR && a1 == x)
> - {
> - gimple_assign_set_rhs_with_ops (gsi, code,
> - x, def1_arg2);
> - gcc_assert (gsi_stmt (*gsi) == stmt);
> - update_stmt (stmt);
> - return true;
> - }
> - defcodefor_name (def1_arg2, &coden, &a1, &a2);
> - /* (Y | ~X) & X -> X & Y */
> - /* (Y & ~X) | X -> X | Y */
> - if (coden == BIT_NOT_EXPR && a1 == x)
> - {
> - gimple_assign_set_rhs_with_ops (gsi, code,
> - x, def1_arg1);
> - gcc_assert (gsi_stmt (*gsi) == stmt);
> - update_stmt (stmt);
> - return true;
> - }
> - }
> - if (def2_code == ocode)
> - {
> - enum tree_code coden;
> - tree a1;
> - tree x = arg1;
> - /* X & ( X | Y) -> X */
> - /* X | ( X & Y) -> X */
> - if (x == def2_arg1
> - || x == def2_arg2)
> - {
> - gimple_assign_set_rhs_from_tree (gsi, x);
> - update_stmt (gsi_stmt (*gsi));
> - return true;
> - }
> - defcodefor_name (def2_arg1, &coden, &a1, NULL);
> - /* (~X | Y) & X -> X & Y */
> - /* (~X & Y) | X -> X | Y */
> - if (coden == BIT_NOT_EXPR && a1 == x)
> - {
> - gimple_assign_set_rhs_with_ops (gsi, code,
> - x, def2_arg2);
> - gcc_assert (gsi_stmt (*gsi) == stmt);
> - update_stmt (stmt);
> - return true;
> - }
> - defcodefor_name (def2_arg2, &coden, &a1, NULL);
> - /* (Y | ~X) & X -> X & Y */
> - /* (Y & ~X) | X -> X | Y */
> - if (coden == BIT_NOT_EXPR && a1 == x)
> - {
> - gimple_assign_set_rhs_with_ops (gsi, code,
> - x, def2_arg1);
> - gcc_assert (gsi_stmt (*gsi) == stmt);
> - update_stmt (stmt);
> - return true;
> - }
> - }
> -
> - /* If arg1 and arg2 are booleans (or any single bit type)
> - then try to simplify:
> -
> - (~X & Y) -> X < Y
> - (X & ~Y) -> Y < X
> - (~X | Y) -> X <= Y
> - (X | ~Y) -> Y <= X
> -
> - But only do this if our result feeds into a comparison as
> - this transformation is not always a win, particularly on
> - targets with and-not instructions. */
> - if (TREE_CODE (arg1) == SSA_NAME
> - && TREE_CODE (arg2) == SSA_NAME
> - && INTEGRAL_TYPE_P (TREE_TYPE (arg1))
> - && TYPE_PRECISION (TREE_TYPE (arg1)) == 1
> - && TYPE_PRECISION (TREE_TYPE (arg2)) == 1
> - && (TYPE_UNSIGNED (TREE_TYPE (arg1))
> - == TYPE_UNSIGNED (TREE_TYPE (arg2))))
> - {
> - use_operand_p use_p;
> - gimple use_stmt;
> -
> - if (single_imm_use (gimple_assign_lhs (stmt), &use_p, &use_stmt))
> - {
> - if (gimple_code (use_stmt) == GIMPLE_COND
> - && gimple_cond_lhs (use_stmt) == gimple_assign_lhs (stmt)
> - && integer_zerop (gimple_cond_rhs (use_stmt))
> - && gimple_cond_code (use_stmt) == NE_EXPR)
> - {
> - if (simplify_bitwise_binary_boolean (gsi, code, arg1, arg2))
> - return true;
> - if (simplify_bitwise_binary_boolean (gsi, code, arg2, arg1))
> - return true;
> - }
> - }
> - }
> - }
> - return false;
> -}
> -
>
> /* Recognize rotation patterns. Return true if a transformation
> applied, otherwise return false.
> @@ -3760,12 +3250,8 @@ pass_forwprop::execute (function *fun)
> tree rhs1 = gimple_assign_rhs1 (stmt);
> enum tree_code code = gimple_assign_rhs_code (stmt);
>
> - if ((code == BIT_NOT_EXPR
> - || code == NEGATE_EXPR)
> - && TREE_CODE (rhs1) == SSA_NAME)
> - changed = simplify_not_neg_expr (&gsi);
> - else if (code == COND_EXPR
> - || code == VEC_COND_EXPR)
> + if (code == COND_EXPR
> + || code == VEC_COND_EXPR)
> {
> /* In this case the entire COND_EXPR is in rhs1. */
> if (forward_propagate_into_cond (&gsi)
> @@ -3788,10 +3274,6 @@ pass_forwprop::execute (function *fun)
> || code == BIT_XOR_EXPR)
> && simplify_rotate (&gsi))
> changed = true;
> - else if (code == BIT_AND_EXPR
> - || code == BIT_IOR_EXPR
> - || code == BIT_XOR_EXPR)
> - changed = simplify_bitwise_binary (&gsi);
> else if (code == MULT_EXPR)
> {
> changed = simplify_mult (&gsi);
> Index: trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c
> ===================================================================
> --- trunk.orig/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c 2014-11-05 13:30:43.209943080 +0100
> +++ trunk/gcc/testsuite/gcc.dg/tree-ssa/forwprop-28.c 2014-11-05 13:35:29.365930558 +0100
> @@ -1,7 +1,7 @@
> /* Setting LOGICAL_OP_NON_SHORT_CIRCUIT to 0 leads to two conditional jumps
> when evaluating an && condition. VRP is not able to optimize this. */
> /* { dg-do compile { target { ! { logical_op_short_circuit || { m68k*-*-* mmix*-*-* mep*-*-* bfin*-*-* v850*-*-* moxie*-*-* cris*-*-* m32c*-*-* fr30*-*-* mcore*-*-* powerpc*-*-* xtensa*-*-* hppa*-*-* } } } } } */
> -/* { dg-options "-O2 -fdump-tree-forwprop1" } */
> +/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */
>
> extern char *frob (void);
> extern _Bool testit (void);
> @@ -79,6 +79,6 @@ test_8 (int code)
> oof ();
> }
>
> -/* { dg-final { scan-tree-dump-times "Replaced" 8 "forwprop1"} } */
> +/* { dg-final { scan-tree-dump-times "simplified to if \\\(\[^ ]* <" 8 "forwprop1"} } */
> /* { dg-final { cleanup-tree-dump "forwprop1" } } */
>
> Index: trunk/gcc/genmatch.c
> ===================================================================
> --- trunk.orig/gcc/genmatch.c 2014-11-05 13:38:00.799923931 +0100
> +++ trunk/gcc/genmatch.c 2014-11-05 13:38:48.927921825 +0100
> @@ -1126,7 +1126,7 @@ dt_node::append_op (operand *op, dt_node
> dt_node *
> dt_node::append_true_op (dt_node *parent, unsigned pos)
> {
> - dt_operand *parent_ = as_a<dt_operand *> (parent);
> + dt_operand *parent_ = safe_as_a<dt_operand *> (parent);
> dt_operand *n = new dt_operand (DT_TRUE, 0, 0, parent_, pos);
> return append_node (n);
> }
> @@ -1232,9 +1232,6 @@ at_assert_elm:
> void
> decision_tree::insert (struct simplify *s, unsigned pattern_no)
> {
> - if (s->match->type != operand::OP_EXPR)
> - return;
> -
> dt_operand **indexes = XCNEWVEC (dt_operand *, s->capture_max + 1);
> dt_node *p = decision_tree::insert_operand (root, s->match, indexes);
> p->append_simplify (s, pattern_no, indexes);