Hi, this is the second part of the patch for this problem. It adds some basic simplifications for ==/!= comparisons for eliminating redudant operands.
It adds the following patterns: -X ==/!= Z - X -> Z ==/!= 0. ~X ==/!= Z ^ X -> Z ==/!= ~0 X ==/!= X - Y -> Y == 0 X ==/!= X + Y -> Y == 0 X ==/!= X ^ Y -> Y == 0 (X - Y) ==/!= (Z - Y) -> X ==/!= Z (Y - X) ==/!= (Y - Z) -> X ==/!= Z (X + Y) ==/!= (X + Z) -> Y ==/!= Z (X + Y) ==/!= (Z + X) -> Y ==/!= Z (X ^ Y) ==/!= (Z ^ X) -> Y ==/!= Z ChangeLog 2012-03-15 Kai Tietz <kti...@redhat.com> PR tree-optimization/45397 * tree-ssa-forwprop.c (compare_equal_optimized_1): Add simplification patterns for ==/!= comparison. 2012-03-15 Kai Tietz <kti...@redhat.com> * gcc.dg/tree-ssa/pr45397-2.c: New test. Regression tested for all languages (including Ada and Obj-C) on x86_64-unknown-linux-gnu. Ok for apply? Regards, Kai Index: gcc-trunk/gcc/tree-ssa-forwprop.c =================================================================== --- gcc-trunk.orig/gcc/tree-ssa-forwprop.c +++ gcc-trunk/gcc/tree-ssa-forwprop.c @@ -381,6 +381,99 @@ compare_equal_optimize_1 (gimple stmt, e || !INTEGRAL_TYPE_P (type_outer)) return NULL_TREE; + /* Simplify -X ==/!= Z - X -> Z ==/!= 0. */ + if (TREE_CODE (op0) == NEGATE_EXPR + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 0)) + && TREE_CODE (op1) == MINUS_EXPR + && TREE_OPERAND (op0, 0) == TREE_OPERAND (op1, 1)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op1, 0), + build_zero_cst (TREE_TYPE (op1))); + + /* Simplify X - Z ==/!= -X -> Z ==/!= 0. */ + if (TREE_CODE (op1) == NEGATE_EXPR + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op1, 0)) + && TREE_CODE (op0) == MINUS_EXPR + && TREE_OPERAND (op1, 0) == TREE_OPERAND (op0, 1)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 0), + build_zero_cst (TREE_TYPE (op0))); + + /* Simplify ~X ==/!= X ^ Y to Y ==/!= ~0. */ + if (TREE_CODE (op0) == BIT_NOT_EXPR + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 0)) + && TREE_CODE (op1) == BIT_XOR_EXPR) + { + if (TREE_OPERAND (op0, 0) == TREE_OPERAND (op1, 1)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op1, 0), + fold_build1 (BIT_NOT_EXPR, + TREE_TYPE (op1), + build_zero_cst (TREE_TYPE (op1)))); + if (TREE_OPERAND (op0, 0) == TREE_OPERAND (op1, 0)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op1, 1), + fold_build1 (BIT_NOT_EXPR, + TREE_TYPE (op1), + build_zero_cst (TREE_TYPE (op1)))); + } + + /* Simplify X ^ Y ==/!= ~X to Y ==/!= ~0. */ + if (TREE_CODE (op1) == BIT_NOT_EXPR + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op1, 0)) + && TREE_CODE (op0) == BIT_XOR_EXPR) + { + if (TREE_OPERAND (op1, 0) == TREE_OPERAND (op0, 1)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 0), + fold_build1 (BIT_NOT_EXPR, + TREE_TYPE (op0), + build_zero_cst (TREE_TYPE (op0)))); + if (TREE_OPERAND (op1, 0) == TREE_OPERAND (op0, 0)) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 1), + fold_build1 (BIT_NOT_EXPR, + TREE_TYPE (op0), + build_zero_cst (TREE_TYPE (op0)))); + } + + /* For code being +, -, or ^-expression simplify (X code Y) ==/!= (Z code Y) + to (X ==/!= Z), and (X code Y) ==/!= (X code Z) to (Y ==/!= Z). */ + if (TREE_CODE (op0) == TREE_CODE (op1) + && (TREE_CODE (op0) == PLUS_EXPR + || TREE_CODE (op0) == MINUS_EXPR + || TREE_CODE (op0) == BIT_XOR_EXPR)) + { + /* Simplify (X code Y) ==/!= (X code Z) to Y ==/!= Z. */ + if (TREE_OPERAND (op0, 0) == TREE_OPERAND (op1, 0) + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 0))) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 1), + TREE_OPERAND (op1, 1)); + /* Simplify (X code Y) ==/!= (Z code X) to Y ==/!= Z, if code isn't + minus operation. */ + if (TREE_CODE (op0) != MINUS_EXPR + && TREE_OPERAND (op0, 0) == TREE_OPERAND (op1, 1) + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 0))) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 1), + TREE_OPERAND (op1, 0)); + /* Simplify (Y code X) ==/!= (X code Z) to Y ==/!= Z, if code isn't + minus operation. */ + if (TREE_CODE (op0) != MINUS_EXPR + && TREE_OPERAND (op0, 1) == TREE_OPERAND (op1, 0) + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 1))) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 0), + TREE_OPERAND (op1, 1)); + /* Simplify (Y code X) ==/!= (Z code X) to Y ==/!= Z. */ + if (TREE_OPERAND (op0, 1) == TREE_OPERAND (op1, 1) + && !TREE_SIDE_EFFECTS (TREE_OPERAND (op0, 1))) + return fold_build2_loc (gimple_location (stmt), code, type, + TREE_OPERAND (op0, 0), + TREE_OPERAND (op1, 0)); + } + /* If OP0 isn't a conversion, then check if OP1 might be one. If so swap arguments, otherwise return NULL_TREE. */ if (!CONVERT_EXPR_P (op0)) Index: gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/pr45397-2.c =================================================================== --- /dev/null +++ gcc-trunk/gcc/testsuite/gcc.dg/tree-ssa/pr45397-2.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ + +int +foo (const unsigned char *a, int b, int c) +{ + int x = (unsigned char) (a[b] + c); + int y = a[b] + c; + int z = (unsigned char) y; + return x == z; +} + +/* { dg-final { scan-tree-dump-times "return 1" 1 "optimized" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ +