This adds a pattern matching x != ~x on GIMPLE and allows CCP to properly optimize the added testcase. gimple_simplify gets confused by the existing ~x == 1 -> x == 0 pattern which gimple_fold_stmt_to_constant_1 cannot reduce to a single value.
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2015-08-04 Richard Biener <rguent...@suse.de> * gimple-fold.c (gimple_fold_stmt_to_constant_1): Canonicalize bool compares on RHS. * match.pd: Add X ==/!= !X is false/true pattern. * gcc.dg/tree-ssa/ssa-ccp-38.c: New testcase. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 226559) +++ gcc/gimple-fold.c (working copy) @@ -5012,10 +5012,8 @@ gimple_fold_stmt_to_constant_1 (gimple s further propagation. */ if (subcode == POINTER_PLUS_EXPR) { - /* Handle binary operators that can appear in GIMPLE form. */ tree op0 = (*valueize) (gimple_assign_rhs1 (stmt)); tree op1 = (*valueize) (gimple_assign_rhs2 (stmt)); - if (TREE_CODE (op0) == ADDR_EXPR && TREE_CODE (op1) == INTEGER_CST) { @@ -5027,6 +5025,38 @@ gimple_fold_stmt_to_constant_1 (gimple s unshare_expr (op0), off)); } } + /* Canonicalize bool != 0 and bool == 0 appearing after + valueization. While gimple_simplify handles this + it can get confused by the ~X == 1 -> X == 0 transform + which we cant reduce to a SSA name or a constant + (and we have no way to tell gimple_simplify to not + consider those transforms in the first place). */ + else if (subcode == EQ_EXPR + || subcode == NE_EXPR) + { + tree lhs = gimple_assign_lhs (stmt); + tree op0 = gimple_assign_rhs1 (stmt); + if (useless_type_conversion_p (TREE_TYPE (lhs), + TREE_TYPE (op0))) + { + tree op1 = (*valueize) (gimple_assign_rhs2 (stmt)); + op0 = (*valueize) (op0); + if (subcode == NE_EXPR) + { + if (integer_zerop (op1)) + return op0; + else if (integer_zerop (op0)) + return op1; + } + else + { + if (integer_onep (op1)) + return op0; + else if (integer_onep (op0)) + return op1; + } + } + } return NULL_TREE; case GIMPLE_TERNARY_RHS: Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 226559) +++ gcc/match.pd (working copy) @@ -618,6 +618,11 @@ (define_operator_list CBRT BUILT_IN_CBRT (simplify (op:c truth_valued_p@0 (logical_inverted_value @0)) { constant_boolean_node (true, type); })) +/* X ==/!= !X is false/true. */ +(for op (eq ne) + (simplify + (op:c truth_valued_p@0 (logical_inverted_value @0)) + { constant_boolean_node (op == NE_EXPR ? true : false, type); })) /* If arg1 and arg2 are booleans (or any single bit type) then try to simplify: Index: gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-38.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-38.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/ssa-ccp-38.c (working copy) @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-ccp1" } */ + +int foo (_Bool x) +{ + _Bool t = 1; + _Bool xx = !x; + _Bool y = xx == t; + _Bool z = y == x; + return z ? 1 : 0; +} + +/* { dg-final { scan-tree-dump "return 0;" "ccp1" } } */