From patchwork Sun Aug 30 07:57:24 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Glisse X-Patchwork-Id: 512188 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 00C431401AF for ; Sun, 30 Aug 2015 17:57:38 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=Kpt3z53s; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=x6IkLymKCDs/CNzbC6hCtgZA/rgnJh5iYZP2NvDY5DIRNYXECHzqN 53r/2gS4nA3oEvCBn90tJyeV3PZGXgF63On+5IY3r698ndnI6SmjMjFMtLT0O172 KDngVlHSU3XiMTHGpOOWefZKEbRGP2FPqHbMH6BgHt/3ObLkh2KNCQ= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=a0VDjLvfnSJCtLRUQnuzXrRM0Wo=; b=Kpt3z53sRvlFy60SD79j CKF8XqmkklGp2fWW5DHg76USJL4UljKM1nZs0GnfJD7L6omzXtVmZHwqB2UR4vaj 9t+ENLurKmUApSGaEzmXAxUJiPfb1AFBNHq3zJOoBmivsLHbC9WAhcnuPLTtBOHL KGpMo4ytvTm/GAjfjJRQFyE= Received: (qmail 83252 invoked by alias); 30 Aug 2015 07:57:32 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 83243 invoked by uid 89); 30 Aug 2015 07:57:31 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=AWL, BAYES_00, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: mail2-relais-roc.national.inria.fr Received: from mail2-relais-roc.national.inria.fr (HELO mail2-relais-roc.national.inria.fr) (192.134.164.83) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Sun, 30 Aug 2015 07:57:29 +0000 Received: from ip-214.net-81-220-91.toulouse.rev.numericable.fr (HELO laptop-mg.local) ([81.220.91.214]) by mail2-relais-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 30 Aug 2015 09:57:25 +0200 Date: Sun, 30 Aug 2015 09:57:24 +0200 (CEST) From: Marc Glisse To: gcc-patches@gcc.gnu.org Subject: Move some comparison simplifications to match.pd Message-ID: User-Agent: Alpine 2.02 (DEB 1266 2009-07-14) MIME-Version: 1.0 Hello, just trying to shrink fold-const.c a bit more. initializer_zerop is close to what I was looking for with zerop, but I wasn't sure if it would be safe (it accepts some CONSTRUCTOR and STRING_CST). At some point I tried using sign_bit_p, but using the return of that function in the simplification confused the machinery too much. I added an "overload" of element_precision like the one in element_mode, for convenience. Bootstrap+testsuite on ppc64le-redhat-linux. 2015-08-31 Marc Glisse gcc/ * tree.h (zerop): New function. * tree.c (zerop): Likewise. (element_precision): Handle expressions. * match.pd (define_predicates): Add zerop. (x <= +Inf): Fix comment. (abs (x) == 0, A & C == C, A & C != 0): Converted from ... * fold-const.c (fold_binary_loc): ... here. Remove. gcc/testsuite/ * gcc.dg/tree-ssa/cmp-1.c: New file. Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 227316) +++ gcc/fold-const.c (working copy) @@ -10761,25 +10761,20 @@ fold_binary_loc (location_t loc, 1)), arg1, 0) && wi::extract_uhwi (TREE_OPERAND (arg0, 0), 0, 1) == 1) { return omit_two_operands_loc (loc, type, code == NE_EXPR ? boolean_true_node : boolean_false_node, TREE_OPERAND (arg0, 1), arg1); } - /* Convert ABS_EXPR == 0 or ABS_EXPR != 0 to x == 0 or x != 0. */ - if (TREE_CODE (arg0) == ABS_EXPR - && (integer_zerop (arg1) || real_zerop (arg1))) - return fold_build2_loc (loc, code, type, TREE_OPERAND (arg0, 0), arg1); - /* If this is an EQ or NE comparison with zero and ARG0 is (1 << foo) & bar, convert it to (bar >> foo) & 1. Both require two operations, but the latter can be done in one less insn on machines that have only two-operand insns or on which a constant cannot be the first operand. */ if (TREE_CODE (arg0) == BIT_AND_EXPR && integer_zerop (arg1)) { tree arg00 = TREE_OPERAND (arg0, 0); tree arg01 = TREE_OPERAND (arg0, 1); @@ -10868,35 +10863,20 @@ fold_binary_loc (location_t loc, ((X >> C1) & C2) != 0 is rewritten as (X,false), and ((X >> C1) & C2) == 0 is rewritten as (X,true). */ else return omit_one_operand_loc (loc, type, code == EQ_EXPR ? integer_one_node : integer_zero_node, arg000); } } - /* If we have (A & C) == C where C is a power of 2, convert this into - (A & C) != 0. Similarly for NE_EXPR. */ - if (TREE_CODE (arg0) == BIT_AND_EXPR - && integer_pow2p (TREE_OPERAND (arg0, 1)) - && operand_equal_p (TREE_OPERAND (arg0, 1), arg1, 0)) - return fold_build2_loc (loc, code == EQ_EXPR ? NE_EXPR : EQ_EXPR, type, - arg0, fold_convert_loc (loc, TREE_TYPE (arg0), - integer_zero_node)); - - /* If we have (A & C) != 0 or (A & C) == 0 and C is the sign - bit, then fold the expression into A < 0 or A >= 0. */ - tem = fold_single_bit_test_into_sign_test (loc, code, arg0, arg1, type); - if (tem) - return tem; - /* If we have (A & C) == D where D & ~C != 0, convert this into 0. Similarly for NE_EXPR. */ if (TREE_CODE (arg0) == BIT_AND_EXPR && TREE_CODE (arg1) == INTEGER_CST && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST) { tree notc = fold_build1_loc (loc, BIT_NOT_EXPR, TREE_TYPE (TREE_OPERAND (arg0, 1)), TREE_OPERAND (arg0, 1)); tree dandnotc Index: gcc/match.pd =================================================================== --- gcc/match.pd (revision 227316) +++ gcc/match.pd (working copy) @@ -21,20 +21,21 @@ for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ /* Generic tree predicates we inherit. */ (define_predicates integer_onep integer_zerop integer_all_onesp integer_minus_onep integer_each_onep integer_truep integer_nonzerop real_zerop real_onep real_minus_onep + zerop CONSTANT_CLASS_P tree_expr_nonnegative_p integer_pow2p HONOR_NANS) /* Operator lists. */ (define_operator_list tcc_comparison lt le eq ne ge gt unordered ordered unlt unle ungt unge uneq ltgt) (define_operator_list inverted_tcc_comparison ge gt ne eq lt le ordered unordered ge gt le lt ltgt uneq) @@ -1570,21 +1571,21 @@ along with GCC; see the file COPYING3. } (switch /* x > +Inf is always false, if with ignore sNANs. */ (if (code == GT_EXPR && ! HONOR_SNANS (@0)) { constant_boolean_node (false, type); }) (if (code == LE_EXPR) /* x <= +Inf is always true, if we don't case about NaNs. */ (if (! HONOR_NANS (@0)) { constant_boolean_node (true, type); } - /* x <= +Inf is the same as x == x, i.e. isfinite(x). */ + /* x <= +Inf is the same as x == x, i.e. !isnan(x). */ (eq @0 @0))) /* x == +Inf and x >= +Inf are always equal to x > DBL_MAX. */ (if (code == EQ_EXPR || code == GE_EXPR) (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } (if (neg) (lt @0 { build_real (TREE_TYPE (@0), max); }) (gt @0 { build_real (TREE_TYPE (@0), max); })))) /* x < +Inf is always equal to x <= DBL_MAX. */ (if (code == LT_EXPR) (with { real_maxval (&max, neg, TYPE_MODE (TREE_TYPE (@0))); } @@ -1727,20 +1728,26 @@ along with GCC; see the file COPYING3. (scmp @0 @1))) (simplify (cmp (negate @0) CONSTANT_CLASS_P@1) (if (FLOAT_TYPE_P (TREE_TYPE (@0)) || (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)))) (with { tree tem = fold_unary (NEGATE_EXPR, TREE_TYPE (@0), @1); } (if (tem && !TREE_OVERFLOW (tem)) (scmp @0 { tem; })))))) +/* Convert ABS_EXPR == 0 or ABS_EXPR != 0 to x == 0 or x != 0. */ +(for op (eq ne) + (simplify + (op (abs @0) zerop@1) + (op @0 @1))) + /* From fold_sign_changed_comparison and fold_widened_comparison. */ (for cmp (simple_comparison) (simplify (cmp (convert@0 @00) (convert?@1 @10)) (if (TREE_CODE (TREE_TYPE (@0)) == INTEGER_TYPE /* Disable this optimization if we're casting a function pointer type on targets that require function pointer canonicalization. */ && !(targetm.have_canonicalize_funcptr_for_compare () && TREE_CODE (TREE_TYPE (@00)) == POINTER_TYPE && TREE_CODE (TREE_TYPE (TREE_TYPE (@00))) == FUNCTION_TYPE) @@ -1833,20 +1840,42 @@ along with GCC; see the file COPYING3. (simplify (cmp (convert?@3 (bit_xor @0 INTEGER_CST@1)) INTEGER_CST@2) (if (tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))) (cmp @0 (bit_xor @1 (convert @2))))) (simplify (cmp (convert? addr@0) integer_zerop) (if (tree_single_nonzero_warnv_p (@0, NULL)) { constant_boolean_node (cmp == NE_EXPR, type); }))) +/* If we have (A & C) == C where C is a power of 2, convert this into + (A & C) != 0. Similarly for NE_EXPR. */ +(for cmp (eq ne) + icmp (ne eq) + (simplify + (cmp (bit_and@2 @0 integer_pow2p@1) @1) + (icmp @2 { build_zero_cst (TREE_TYPE (@0)); }))) + +/* If we have (A & C) != 0 where C is the sign bit of A, convert + this into A < 0. Similarly for (A & C) == 0 into A >= 0. */ +(for cmp (eq ne) + ncmp (ge lt) + (simplify + (cmp (bit_and (convert?@2 @0) integer_pow2p@1) integer_zerop) + (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) + && (TYPE_PRECISION (TREE_TYPE (@0)) + == GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (@0)))) + && element_precision (@2) >= element_precision (@0) + && wi::only_sign_bit_p (@1, element_precision (@0))) + (with { tree stype = signed_type_for (TREE_TYPE (@0)); } + (ncmp (convert:stype @0) { build_zero_cst (stype); }))))) + /* When the addresses are not directly of decls compare base and offset. This implements some remaining parts of fold_comparison address comparisons but still no complete part of it. Still it is good enough to make fold_stmt not regress when not dispatching to fold_binary. */ (for cmp (simple_comparison) (simplify (cmp (convert1?@2 addr@0) (convert2? addr@1)) (with { HOST_WIDE_INT off0, off1; Index: gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/cmp-1.c (working copy) @@ -0,0 +1,19 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-gimple -fdump-tree-optimized" } */ + +int f(int a){ + int b = -__INT_MAX__-1; + a &= b; + return a == b; +} +int g(int x){ + x = x < 0 ? -x : x; + return x == 0; +} + +/* This should work even if int is not 32 bits, it is just not meaningful in + that case. */ +/* { dg-final { scan-tree-dump-not "-2147483648" "optimized"} } */ +/* { dg-final { scan-tree-dump " < 0" "optimized"} } */ +/* { dg-final { scan-tree-dump "ABS_EXPR" "gimple"} } */ +/* { dg-final { scan-tree-dump-not "ABS_EXPR" "optimized"} } */ Index: gcc/tree.c =================================================================== --- gcc/tree.c (revision 227316) +++ gcc/tree.c (working copy) @@ -2208,20 +2208,31 @@ grow_tree_vec_stat (tree v, int len MEM_ record_node_allocation_statistics (TREE_VEC, length - oldlength); v = (tree) ggc_realloc (v, length PASS_MEM_STAT); TREE_VEC_LENGTH (v) = len; return v; } +/* Return 1 if EXPR is the constant zero, whether it is integral, float or + fixed, and scalar, complex or vector. */ + +int +zerop (const_tree expr) +{ + return (integer_zerop (expr) + || real_zerop (expr) + || fixed_zerop (expr)); +} + /* Return 1 if EXPR is the integer constant zero or a complex constant of zero. */ int integer_zerop (const_tree expr) { STRIP_NOPS (expr); switch (TREE_CODE (expr)) { @@ -7505,20 +7516,22 @@ valid_constant_size_p (const_tree size) return false; return true; } /* Return the precision of the type, or for a complex or vector type the precision of the type of its elements. */ unsigned int element_precision (const_tree type) { + if (!TYPE_P (type)) + type = TREE_TYPE (type); enum tree_code code = TREE_CODE (type); if (code == COMPLEX_TYPE || code == VECTOR_TYPE) type = TREE_TYPE (type); return TYPE_PRECISION (type); } /* Return true if CODE represents an associative tree code. Otherwise return false. */ bool Index: gcc/tree.h =================================================================== --- gcc/tree.h (revision 227316) +++ gcc/tree.h (working copy) @@ -4102,20 +4102,24 @@ extern bool initializer_zerop (const_tre /* Given a vector VEC, return its first element if all elements are the same. Otherwise return NULL_TREE. */ extern tree uniform_vector_p (const_tree); /* Given a CONSTRUCTOR CTOR, return the element values as a vector. */ extern vec *ctor_to_vec (tree); +/* zerop (tree x) is nonzero if X is a constant of value 0. */ + +extern int zerop (const_tree); + /* integer_zerop (tree x) is nonzero if X is an integer constant of value 0. */ extern int integer_zerop (const_tree); /* integer_onep (tree x) is nonzero if X is an integer constant of value 1. */ extern int integer_onep (const_tree); /* integer_onep (tree x) is nonzero if X is an integer constant of value 1, or a vector or complex where each part is 1. */