[backport gcc-4.8/trunk r196263 ] gcc/ 2013-02-25 Richard Biener PR tree-optimization/56175 * tree-ssa-forwprop.c (hoist_conversion_for_bitop_p): New predicate, split out from ... (simplify_bitwise_binary): ... here. Also guard the conversion of (type) X op CST to (type) (X op ((type-x) CST)) with it. gcc/testsuite/ 2013-02-25 Richard Biener PR tree-optimization/56175 * gcc.dg/tree-ssa/forwprop-24.c: New testcase. --- gcc-4.7.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-24.c.~1~ 1970-01-01 01:00:00.000000000 +0100 +++ gcc-4.7.2/gcc/testsuite/gcc.dg/tree-ssa/forwprop-24.c 2013-03-02 16:05:24.578254696 +0100 @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-cddce1" } */ + +void bar (void); +unsigned short +foo (unsigned char x, unsigned short y) +{ + unsigned char t = (unsigned char)((x & 1) ^ ((unsigned char)y & 1)); + if (t == 1) + bar (); + return y; +} + +/* We should have combined this to require only one bitwise and + as in (x ^ (char) y) & 1. */ + +/* { dg-final { scan-tree-dump-times " & " 1 "cddce1" } } */ +/* { dg-final { cleanup-tree-dump "cddce1" } } */ --- gcc-4.7.2/gcc/tree-ssa-forwprop.c.~1~ 2012-07-19 23:40:23.000000000 +0200 +++ gcc-4.7.2/gcc/tree-ssa-forwprop.c 2013-03-02 16:05:24.588254565 +0100 @@ -1742,6 +1742,29 @@ simplify_bitwise_binary_1 (enum tree_cod return NULL_TREE; } +/* 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; +} + /* Simplify bitwise binary operations. Return true if a transformation applied, otherwise return false. */ @@ -1781,9 +1804,11 @@ simplify_bitwise_binary (gimple_stmt_ite } } - /* Try to fold (type) X op CST -> (type) (X op ((type-x) CST)). */ + /* 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))) { @@ -1810,15 +1835,7 @@ simplify_bitwise_binary (gimple_stmt_ite if (CONVERT_EXPR_CODE_P (def1_code) && CONVERT_EXPR_CODE_P (def2_code) && types_compatible_p (TREE_TYPE (def1_arg1), TREE_TYPE (def2_arg1)) - /* Make sure that the conversion widens the operands, or has same - precision, or that it changes the operation to a bitfield - precision. */ - && ((TYPE_PRECISION (TREE_TYPE (def1_arg1)) - <= TYPE_PRECISION (TREE_TYPE (arg1))) - || (GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (arg1))) - != MODE_INT) - || (TYPE_PRECISION (TREE_TYPE (arg1)) - != GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (arg1)))))) + && hoist_conversion_for_bitop_p (TREE_TYPE (arg1), TREE_TYPE (def1_arg1))) { gimple newop; tree tem = create_tmp_reg (TREE_TYPE (def1_arg1),