From c255521a13d72ded4c18102398c7f9017028bea5 Mon Sep 17 00:00:00 2001 From: bernds Date: Sat, 24 Apr 2010 18:53:47 +0000 Subject: [PATCH] gcc/ PR tree-optimization/41442 * fold-const.c (merge_truthop_with_opposite_arm): New function. (fold_binary_loc): Call it. gcc/testsuite/ PR tree-optimization/41442 * gcc.target/i386/pr41442.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@158689 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 6 ++++ gcc/fold-const.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++ gcc/testsuite/ChangeLog | 5 +++ 3 files changed, 97 insertions(+) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2ec92ea6583..9e1a30a101b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2010-04-24 Bernd Schmidt + + PR tree-optimization/41442 + * fold-const.c (merge_truthop_with_opposite_arm): New function. + (fold_binary_loc): Call it. + 2010-04-23 Manuel López-Ibáñez * toplev.c (general_init): Set default for diff --git a/gcc/fold-const.c b/gcc/fold-const.c index cdae661733c..ffd9d30ef2e 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -4997,6 +4997,76 @@ unextend (tree c, int p, int unsignedp, tree mask) const_binop (BIT_XOR_EXPR, c, temp, 0)); } +/* For an expression that has the form + (A && B) || ~B + or + (A || B) && ~B, + we can drop one of the inner expressions and simplify to + A || ~B + or + A && ~B + LOC is the location of the resulting expression. OP is the inner + logical operation; the left-hand side in the examples above, while CMPOP + is the right-hand side. RHS_ONLY is used to prevent us from accidentally + removing a condition that guards another, as in + (A != NULL && A->...) || A == NULL + which we must not transform. If RHS_ONLY is true, only eliminate the + right-most operand of the inner logical operation. */ + +static tree +merge_truthop_with_opposite_arm (location_t loc, tree op, tree cmpop, + bool rhs_only) +{ + tree type = TREE_TYPE (cmpop); + enum tree_code code = TREE_CODE (cmpop); + enum tree_code truthop_code = TREE_CODE (op); + tree lhs = TREE_OPERAND (op, 0); + tree rhs = TREE_OPERAND (op, 1); + tree orig_lhs = lhs, orig_rhs = rhs; + enum tree_code rhs_code = TREE_CODE (rhs); + enum tree_code lhs_code = TREE_CODE (lhs); + enum tree_code inv_code; + + if (TREE_SIDE_EFFECTS (op) || TREE_SIDE_EFFECTS (cmpop)) + return NULL_TREE; + + if (TREE_CODE_CLASS (code) != tcc_comparison) + return NULL_TREE; + + if (rhs_code == truthop_code) + { + tree newrhs = merge_truthop_with_opposite_arm (loc, rhs, cmpop, rhs_only); + if (newrhs != NULL_TREE) + { + rhs = newrhs; + rhs_code = TREE_CODE (rhs); + } + } + if (lhs_code == truthop_code && !rhs_only) + { + tree newlhs = merge_truthop_with_opposite_arm (loc, lhs, cmpop, false); + if (newlhs != NULL_TREE) + { + lhs = newlhs; + lhs_code = TREE_CODE (lhs); + } + } + + inv_code = invert_tree_comparison (code, HONOR_NANS (TYPE_MODE (type))); + if (inv_code == rhs_code + && operand_equal_p (TREE_OPERAND (rhs, 0), TREE_OPERAND (cmpop, 0), 0) + && operand_equal_p (TREE_OPERAND (rhs, 1), TREE_OPERAND (cmpop, 1), 0)) + return lhs; + if (!rhs_only && inv_code == lhs_code + && operand_equal_p (TREE_OPERAND (lhs, 0), TREE_OPERAND (cmpop, 0), 0) + && operand_equal_p (TREE_OPERAND (lhs, 1), TREE_OPERAND (cmpop, 1), 0)) + return rhs; + if (rhs != orig_rhs || lhs != orig_lhs) + return fold_build2_loc (loc, truthop_code, TREE_TYPE (cmpop), + lhs, rhs); + return NULL_TREE; +} + /* Find ways of folding logical expressions of LHS and RHS: Try to merge two comparisons to the same innermost item. Look for range tests like "ch >= '0' && ch <= '9'". @@ -11833,6 +11903,22 @@ fold_binary_loc (location_t loc, if (0 != (tem = fold_range_test (loc, code, type, op0, op1))) return tem; + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg0) == TRUTH_ORIF_EXPR) + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg0) == TRUTH_ANDIF_EXPR)) + { + tem = merge_truthop_with_opposite_arm (loc, arg0, arg1, true); + if (tem) + return fold_build2_loc (loc, code, type, tem, arg1); + } + + if ((code == TRUTH_ANDIF_EXPR && TREE_CODE (arg1) == TRUTH_ORIF_EXPR) + || (code == TRUTH_ORIF_EXPR && TREE_CODE (arg1) == TRUTH_ANDIF_EXPR)) + { + tem = merge_truthop_with_opposite_arm (loc, arg1, arg0, false); + if (tem) + return fold_build2_loc (loc, code, type, arg0, tem); + } + /* Check for the possibility of merging component references. If our lhs is another similar operation, try to merge its rhs with our rhs. Then try to merge our lhs and rhs. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 26ae3d0bee0..0133717fc20 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-04-24 Bernd Schmidt + + PR tree-optimization/41442 + * gcc.target/i386/pr41442.c: New test. + 2010-04-24 Hans-Peter Nilsson PR fortran/43832 -- 2.11.0