From patchwork Wed Jun 1 19:27:06 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bill Schmidt X-Patchwork-Id: 98247 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]) by ozlabs.org (Postfix) with SMTP id 40100B6F9C for ; Thu, 2 Jun 2011 05:27:57 +1000 (EST) Received: (qmail 25673 invoked by alias); 1 Jun 2011 19:27:55 -0000 Received: (qmail 25662 invoked by uid 22791); 1 Jun 2011 19:27:54 -0000 X-SWARE-Spam-Status: No, hits=-1.2 required=5.0 tests=AWL, BAYES_00, MAY_BE_FORGED, TW_FN, TW_TM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from e31.co.us.ibm.com (HELO e31.co.us.ibm.com) (32.97.110.149) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 01 Jun 2011 19:27:37 +0000 Received: from d03relay03.boulder.ibm.com (d03relay03.boulder.ibm.com [9.17.195.228]) by e31.co.us.ibm.com (8.14.4/8.13.1) with ESMTP id p51JAvJG031715 for ; Wed, 1 Jun 2011 13:10:57 -0600 Received: from d03av05.boulder.ibm.com (d03av05.boulder.ibm.com [9.17.195.85]) by d03relay03.boulder.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p51JRB2Q105982 for ; Wed, 1 Jun 2011 13:27:12 -0600 Received: from d03av05.boulder.ibm.com (loopback [127.0.0.1]) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p51JR84L026926 for ; Wed, 1 Jun 2011 13:27:08 -0600 Received: from [9.10.86.209] (tepot-pc.rchland.ibm.com [9.10.86.209] (may be forged)) by d03av05.boulder.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id p51JR7aA026838; Wed, 1 Jun 2011 13:27:07 -0600 Subject: [PATCH] gimple_val_nonnegative_real_p (PR46728 patch 7 of 7) From: "William J. Schmidt" To: gcc-patches@gcc.gnu.org Date: Wed, 01 Jun 2011 14:27:06 -0500 Message-Id: <1306956426.5243.18.camel@L3G5336.ibm.com> Mime-Version: 1.0 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 This patch cleans up the FIXME logic in gimple_expand_builtin_pow by introducing gimple_val_nonnegative_real_p for the same purpose that tree_expr_nonnegative_p served in the expand logic. This completes the work for PR46728. Bootstrapped/regtested on powerpc64-linux. 2011-06-01 Bill Schmidt PR tree-optimization/46728 * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Change FIXME to use gimple_val_nonnegative_real_p. * gimple-fold.c (gimple_val_nonnegative_real_p): New function. * gimple.h (gimple_val_nonnegative_real_p): New declaration. Index: gcc/tree-ssa-math-opts.c =================================================================== --- gcc/tree-ssa-math-opts.c (revision 174535) +++ gcc/tree-ssa-math-opts.c (working copy) @@ -1172,13 +1172,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g if (flag_unsafe_math_optimizations && cbrtfn - /* FIXME: The following line was originally - && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)), - but since arg0 is a gimple value, the first predicate - will always return false. It needs to be replaced with a - call to a similar gimple_val_nonnegative_p function to be - added in gimple-fold.c. */ - && !HONOR_NANS (mode) + && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode)) && REAL_VALUES_EQUAL (c, dconst1_3)) return build_and_insert_call (gsi, loc, &target, cbrtfn, arg0); @@ -1190,13 +1184,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g if (flag_unsafe_math_optimizations && sqrtfn && cbrtfn - /* FIXME: The following line was originally - && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)), - but since arg0 is a gimple value, the first predicate - will always return false. It needs to be replaced with a - call to a similar gimple_val_nonnegative_p function to be - added in gimple-fold.c. */ - && !HONOR_NANS (mode) + && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode)) && optimize_function_for_speed_p (cfun) && hw_sqrt_exists && REAL_VALUES_EQUAL (c, dconst1_6)) @@ -1270,13 +1258,7 @@ gimple_expand_builtin_pow (gimple_stmt_iterator *g if (flag_unsafe_math_optimizations && cbrtfn - /* FIXME: The following line was originally - && (tree_expr_nonnegative_p (arg0) || !HONOR_NANS (mode)), - but since arg0 is a gimple value, the first predicate - will always return false. It needs to be replaced with a - call to a similar gimple_val_nonnegative_p function to be - added in gimple-fold.c. */ - && !HONOR_NANS (mode) + && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode)) && real_identical (&c2, &c) && optimize_function_for_speed_p (cfun) && powi_cost (n / 3) <= POWI_MAX_MULTS) Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 174535) +++ gcc/gimple-fold.c (working copy) @@ -3433,3 +3433,224 @@ fold_const_aggregate_ref (tree t) { return fold_const_aggregate_ref_1 (t, NULL); } + +/* Return true iff VAL is a gimple expression that is known to be + non-negative. Restricted to floating-point inputs. When changing + this function, review fold-const.c:tree_expr_nonnegative_p to see + whether similar changes are required. */ + +bool +gimple_val_nonnegative_real_p (tree val) +{ + gimple def_stmt; + + /* Use existing logic for non-gimple trees. */ + if (tree_expr_nonnegative_p (val)) + return true; + + if (TREE_CODE (val) != SSA_NAME) + return false; + + def_stmt = SSA_NAME_DEF_STMT (val); + + if (is_gimple_assign (def_stmt)) + { + tree op0, op1; + + /* If this is just a copy between SSA names, check the RHS. */ + if (gimple_assign_ssa_name_copy_p (def_stmt)) + { + op0 = gimple_assign_rhs1 (def_stmt); + return gimple_val_nonnegative_real_p (op0); + } + + switch (gimple_assign_rhs_code (def_stmt)) + { + case ABS_EXPR: + /* Always true for floating-point operands. */ + return true; + + case NOP_EXPR: + case CONVERT_EXPR: + /* True if the first operand is a nonnegative real. */ + op0 = gimple_assign_rhs1 (def_stmt); + return (TREE_CODE (TREE_TYPE (op0)) == REAL_TYPE + && gimple_val_nonnegative_real_p (op0)); + + case PLUS_EXPR: + case MIN_EXPR: + case RDIV_EXPR: + /* True if both operands are nonnegative. */ + op0 = gimple_assign_rhs1 (def_stmt); + op1 = gimple_assign_rhs2 (def_stmt); + return (gimple_val_nonnegative_real_p (op0) + && gimple_val_nonnegative_real_p (op1)); + + case MAX_EXPR: + /* True if either operand is nonnegative. */ + op0 = gimple_assign_rhs1 (def_stmt); + op1 = gimple_assign_rhs2 (def_stmt); + return (gimple_val_nonnegative_real_p (op0) + || gimple_val_nonnegative_real_p (op1)); + + case MULT_EXPR: + /* True if the two operands are identical (since we are + restricted to floating-point inputs), or if both operands + are nonnegative. */ + op0 = gimple_assign_rhs1 (def_stmt); + op1 = gimple_assign_rhs2 (def_stmt); + + if (operand_equal_p (op0, op1, 0)) + return true; + + if (TREE_CODE (op0) == SSA_NAME + && TREE_CODE (op1) == SSA_NAME + && SSA_NAME_VAR (op0) == SSA_NAME_VAR (op1) + && SSA_NAME_VERSION (op0) == SSA_NAME_VERSION (op1)) + return true; + + /* FIXME: Could we miss cases where op0 and op1 are different + SSA_NAMES whose defining values are equivalent, or one is + an SSA_NAME and the other is an equivalent non-SSA_NAME? + These cases likely don't constitute a great loss in any + event. */ + + return (gimple_val_nonnegative_real_p (op0) + && gimple_val_nonnegative_real_p (op1)); + + default: + return false; + } + } + else if (is_gimple_call (def_stmt)) + { + tree fndecl = gimple_call_fndecl (def_stmt); + if (fndecl + && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL) + { + tree arg0, arg1; + + switch (DECL_FUNCTION_CODE (fndecl)) + { + CASE_FLT_FN (BUILT_IN_ACOS): + CASE_FLT_FN (BUILT_IN_ACOSH): + CASE_FLT_FN (BUILT_IN_CABS): + CASE_FLT_FN (BUILT_IN_COSH): + CASE_FLT_FN (BUILT_IN_ERFC): + CASE_FLT_FN (BUILT_IN_EXP): + CASE_FLT_FN (BUILT_IN_EXP10): + CASE_FLT_FN (BUILT_IN_EXP2): + CASE_FLT_FN (BUILT_IN_FABS): + CASE_FLT_FN (BUILT_IN_FDIM): + CASE_FLT_FN (BUILT_IN_HYPOT): + CASE_FLT_FN (BUILT_IN_POW10): + return true; + + CASE_FLT_FN (BUILT_IN_SQRT): + /* sqrt(-0.0) is -0.0, and sqrt is not defined over other + nonnegative inputs. */ + if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val)))) + return true; + + arg0 = gimple_call_arg (def_stmt, 0); + return gimple_val_nonnegative_real_p (arg0); + + CASE_FLT_FN (BUILT_IN_ASINH): + CASE_FLT_FN (BUILT_IN_ATAN): + CASE_FLT_FN (BUILT_IN_ATANH): + CASE_FLT_FN (BUILT_IN_CBRT): + CASE_FLT_FN (BUILT_IN_CEIL): + CASE_FLT_FN (BUILT_IN_ERF): + CASE_FLT_FN (BUILT_IN_EXPM1): + CASE_FLT_FN (BUILT_IN_FLOOR): + CASE_FLT_FN (BUILT_IN_FMOD): + CASE_FLT_FN (BUILT_IN_FREXP): + CASE_FLT_FN (BUILT_IN_LCEIL): + CASE_FLT_FN (BUILT_IN_LDEXP): + CASE_FLT_FN (BUILT_IN_LFLOOR): + CASE_FLT_FN (BUILT_IN_LLCEIL): + CASE_FLT_FN (BUILT_IN_LLFLOOR): + CASE_FLT_FN (BUILT_IN_LLRINT): + CASE_FLT_FN (BUILT_IN_LLROUND): + CASE_FLT_FN (BUILT_IN_LRINT): + CASE_FLT_FN (BUILT_IN_LROUND): + CASE_FLT_FN (BUILT_IN_MODF): + CASE_FLT_FN (BUILT_IN_NEARBYINT): + CASE_FLT_FN (BUILT_IN_RINT): + CASE_FLT_FN (BUILT_IN_ROUND): + CASE_FLT_FN (BUILT_IN_SCALB): + CASE_FLT_FN (BUILT_IN_SCALBLN): + CASE_FLT_FN (BUILT_IN_SCALBN): + CASE_FLT_FN (BUILT_IN_SIGNBIT): + CASE_FLT_FN (BUILT_IN_SIGNIFICAND): + CASE_FLT_FN (BUILT_IN_SINH): + CASE_FLT_FN (BUILT_IN_TANH): + CASE_FLT_FN (BUILT_IN_TRUNC): + /* True if the first argument is nonnegative. */ + arg0 = gimple_call_arg (def_stmt, 0); + return gimple_val_nonnegative_real_p (arg0); + + CASE_FLT_FN (BUILT_IN_FMAX): + /* True if either argument is nonnegative. */ + arg0 = gimple_call_arg (def_stmt, 0); + arg1 = gimple_call_arg (def_stmt, 1); + return (gimple_val_nonnegative_real_p (arg0) + || gimple_val_nonnegative_real_p (arg1)); + + CASE_FLT_FN (BUILT_IN_FMIN): + /* True if both arguments are nonnegative. */ + arg0 = gimple_call_arg (def_stmt, 0); + arg1 = gimple_call_arg (def_stmt, 1); + return (gimple_val_nonnegative_real_p (arg0) + && gimple_val_nonnegative_real_p (arg1)); + + CASE_FLT_FN (BUILT_IN_COPYSIGN): + /* True if the second argument is nonnegative. */ + arg1 = gimple_call_arg (def_stmt, 1); + return gimple_val_nonnegative_real_p (arg1); + + CASE_FLT_FN (BUILT_IN_POWI): + /* True if the first argument is nonnegative or the + second argument is an even integer. */ + arg0 = gimple_call_arg (def_stmt, 0); + arg1 = gimple_call_arg (def_stmt, 1); + + if (TREE_CODE (arg1) == INTEGER_CST + && (TREE_INT_CST_LOW (arg1) & 1) == 0) + return true; + + return gimple_val_nonnegative_real_p (arg0); + + CASE_FLT_FN (BUILT_IN_POW): + /* True if the first argument is nonnegative or the + second argument is an even integer-valued real. */ + arg0 = gimple_call_arg (def_stmt, 0); + arg1 = gimple_call_arg (def_stmt, 1); + + if (TREE_CODE (arg1) == REAL_CST) + { + REAL_VALUE_TYPE c; + HOST_WIDE_INT n; + + c = TREE_REAL_CST (arg1); + n = real_to_integer (&c); + + if ((n & 1) == 0) + { + REAL_VALUE_TYPE cint; + real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0); + if (real_identical (&c, &cint)) + return true; + } + } + + return gimple_val_nonnegative_real_p (arg0); + + default: + return false; + } + } + } + + return false; +} Index: gcc/gimple.h =================================================================== --- gcc/gimple.h (revision 174535) +++ gcc/gimple.h (working copy) @@ -4988,4 +4988,5 @@ extern tree maybe_fold_and_comparisons (enum tree_ extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree, enum tree_code, tree, tree); +bool gimple_val_nonnegative_real_p (tree); #endif /* GCC_GIMPLE_H */