From 5b00d9211625c18148d3bacdc53c9f527557d063 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Tue, 30 Jun 2015 12:54:23 +0000 Subject: [PATCH] fold-const.c (fold_binary_loc): Move ~x & ~y -> ~(x | y) and ~x | ~y -> ~(x & y)... 2015-06-30 Richard Biener * fold-const.c (fold_binary_loc): Move ~x & ~y -> ~(x | y) and ~x | ~y -> ~(x & y), (x & CST) ^ (x & CST2) -> (x & CST) | (x & CST2), (X | Y) ^ X -> Y & ~ X, ~X ^ ~Y to X ^ Y and ~X ^ C to X ^ ~C ... * match.pd: ... to patterns here. From-SVN: r225184 --- gcc/ChangeLog | 7 +++ gcc/fold-const.c | 119 ----------------------------------------------- gcc/match.pd | 41 ++++++++++++++++ 3 files changed, 48 insertions(+), 119 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 59d3052da9d..8ac39dc1930 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2015-06-30 Richard Biener + + * fold-const.c (fold_binary_loc): Move ~x & ~y -> ~(x | y) and + ~x | ~y -> ~(x & y), (x & CST) ^ (x & CST2) -> (x & CST) | (x & CST2), + (X | Y) ^ X -> Y & ~ X, ~X ^ ~Y to X ^ Y and ~X ^ C to X ^ ~C ... + * match.pd: ... to patterns here. + 2015-06-30 Richard Biener PR tree-optimization/66704 diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 67115d2377e..7e300021220 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -10974,24 +10974,6 @@ fold_binary_loc (location_t loc, if (t1 != NULL_TREE) return t1; - /* Convert (or (not arg0) (not arg1)) to (not (and (arg0) (arg1))). - - This results in more efficient code for machines without a NAND - instruction. Combine will canonicalize to the first form - which will allow use of NAND instructions provided by the - backend if they exist. */ - if (TREE_CODE (arg0) == BIT_NOT_EXPR - && TREE_CODE (arg1) == BIT_NOT_EXPR) - { - return - fold_build1_loc (loc, BIT_NOT_EXPR, type, - build2 (BIT_AND_EXPR, type, - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0)), - fold_convert_loc (loc, type, - TREE_OPERAND (arg1, 0)))); - } - /* See if this can be simplified into a rotate first. If that is unsuccessful continue in the association code. */ goto bit_rotate; @@ -11015,90 +10997,6 @@ fold_binary_loc (location_t loc, return omit_one_operand_loc (loc, type, t1, arg0); } - /* If we are XORing two BIT_AND_EXPR's, both of which are and'ing - with a constant, and the two constants have no bits in common, - we should treat this as a BIT_IOR_EXPR since this may produce more - simplifications. */ - if (TREE_CODE (arg0) == BIT_AND_EXPR - && TREE_CODE (arg1) == BIT_AND_EXPR - && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST - && TREE_CODE (TREE_OPERAND (arg1, 1)) == INTEGER_CST - && wi::bit_and (TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg1, 1)) == 0) - { - code = BIT_IOR_EXPR; - goto bit_ior; - } - - /* (X | Y) ^ X -> Y & ~ X*/ - if (TREE_CODE (arg0) == BIT_IOR_EXPR - && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) - { - tree t2 = TREE_OPERAND (arg0, 1); - t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1), - arg1); - t1 = fold_build2_loc (loc, BIT_AND_EXPR, type, - fold_convert_loc (loc, type, t2), - fold_convert_loc (loc, type, t1)); - return t1; - } - - /* (Y | X) ^ X -> Y & ~ X*/ - if (TREE_CODE (arg0) == BIT_IOR_EXPR - && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) - { - tree t2 = TREE_OPERAND (arg0, 0); - t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg1), - arg1); - t1 = fold_build2_loc (loc, BIT_AND_EXPR, type, - fold_convert_loc (loc, type, t2), - fold_convert_loc (loc, type, t1)); - return t1; - } - - /* X ^ (X | Y) -> Y & ~ X*/ - if (TREE_CODE (arg1) == BIT_IOR_EXPR - && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0)) - { - tree t2 = TREE_OPERAND (arg1, 1); - t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg0), - arg0); - t1 = fold_build2_loc (loc, BIT_AND_EXPR, type, - fold_convert_loc (loc, type, t2), - fold_convert_loc (loc, type, t1)); - return t1; - } - - /* X ^ (Y | X) -> Y & ~ X*/ - if (TREE_CODE (arg1) == BIT_IOR_EXPR - && operand_equal_p (TREE_OPERAND (arg1, 1), arg0, 0)) - { - tree t2 = TREE_OPERAND (arg1, 0); - t1 = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (arg0), - arg0); - t1 = fold_build2_loc (loc, BIT_AND_EXPR, type, - fold_convert_loc (loc, type, t2), - fold_convert_loc (loc, type, t1)); - return t1; - } - - /* Convert ~X ^ ~Y to X ^ Y. */ - if (TREE_CODE (arg0) == BIT_NOT_EXPR - && TREE_CODE (arg1) == BIT_NOT_EXPR) - return fold_build2_loc (loc, code, type, - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0)), - fold_convert_loc (loc, type, - TREE_OPERAND (arg1, 0))); - - /* Convert ~X ^ C to X ^ ~C. */ - if (TREE_CODE (arg0) == BIT_NOT_EXPR - && TREE_CODE (arg1) == INTEGER_CST) - return fold_build2_loc (loc, code, type, - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0)), - fold_build1_loc (loc, BIT_NOT_EXPR, type, arg1)); - /* Fold (X & 1) ^ 1 as (X & 1) == 0. */ if (TREE_CODE (arg0) == BIT_AND_EXPR && INTEGRAL_TYPE_P (type) @@ -11410,23 +11308,6 @@ fold_binary_loc (location_t loc, fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0)); } - /* Convert (and (not arg0) (not arg1)) to (not (or (arg0) (arg1))). - - This results in more efficient code for machines without a NOR - instruction. Combine will canonicalize to the first form - which will allow use of NOR instructions provided by the - backend if they exist. */ - if (TREE_CODE (arg0) == BIT_NOT_EXPR - && TREE_CODE (arg1) == BIT_NOT_EXPR) - { - return fold_build1_loc (loc, BIT_NOT_EXPR, type, - build2 (BIT_IOR_EXPR, type, - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0)), - fold_convert_loc (loc, type, - TREE_OPERAND (arg1, 0)))); - } - /* If arg0 is derived from the address of an object or function, we may be able to fold this expression using the object or function's alignment. */ diff --git a/gcc/match.pd b/gcc/match.pd index d81ea53dae4..682784b094b 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -389,6 +389,47 @@ along with GCC; see the file COPYING3. If not see (bit_and:c (bit_ior:c @0 @1) (bit_xor:c @1 (bit_not @0))) (bit_and @0 @1)) +/* ~x & ~y -> ~(x | y) + ~x | ~y -> ~(x & y) */ +(for op (bit_and bit_ior) + rop (bit_ior bit_and) + (simplify + (op (convert1? (bit_not @0)) (convert2? (bit_not @1))) + (if (tree_nop_conversion_p (type, TREE_TYPE (@0)) + && tree_nop_conversion_p (type, TREE_TYPE (@1))) + (bit_not (rop (convert @0) (convert @1)))))) + +/* If we are XORing two BIT_AND_EXPR's, both of which are and'ing + with a constant, and the two constants have no bits in common, + we should treat this as a BIT_IOR_EXPR since this may produce more + simplifications. */ +(simplify + (bit_xor (convert1? (bit_and@4 @0 INTEGER_CST@1)) + (convert2? (bit_and@5 @2 INTEGER_CST@3))) + (if (tree_nop_conversion_p (type, TREE_TYPE (@0)) + && tree_nop_conversion_p (type, TREE_TYPE (@2)) + && wi::bit_and (@1, @3) == 0) + (bit_ior (convert @4) (convert @5)))) + +/* (X | Y) ^ X -> Y & ~ X*/ +(simplify + (bit_xor:c (convert? (bit_ior:c @0 @1)) (convert? @0)) + (if (tree_nop_conversion_p (type, TREE_TYPE (@0))) + (convert (bit_and @1 (bit_not @0))))) + +/* Convert ~X ^ ~Y to X ^ Y. */ +(simplify + (bit_xor (convert1? (bit_not @0)) (convert2? (bit_not @1))) + (if (tree_nop_conversion_p (type, TREE_TYPE (@0)) + && tree_nop_conversion_p (type, TREE_TYPE (@1))) + (bit_xor (convert @0) (convert @1)))) + +/* Convert ~X ^ C to X ^ ~C. */ +(simplify + (bit_xor (convert? (bit_not @0)) INTEGER_CST@1) + (bit_xor (convert @0) (bit_not @1))) + + (simplify (abs (abs@1 @0)) @1) -- 2.30.2