diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a05b7260498b..b233e9496e47 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,33 @@ +2003-10-11 Roger Sayle + + * fold-const.c (negate_mathfn_p): New function to determine whether + a built-in mathematical function is sign preserving, f(-x) == -f(x). + Add support for BUILT_IN_ASIN, BUILT_IN_ASINF and BUILT_IN_ASINL. + (tree_swap_operands_p): Change API to take an additional argument + indicating that the swapped operands evaluate in reverse order. + Canonicalize VAR_DECLs and PARM_DECLs last if we can, i.e. neither + operand side-effects or we don't care about flag_evaluation_order. + (reorder_operands_p): New function to check whether its safe to + evaluate the given operands in reverse order. + (negate_expr_p): We can always negate integer constants unless + we honor -ftrapv and the signed type would overflow. Only allow + -(A-B) into B-A if reorder_operands_p says that its OK. Allow + negation of COMPLEX_CST if both real and imaginary parts can be + negated. Allow negation through floating point extensions and + sign-preserving built-in functions. + (negate_expr): Move the code to negate integers from "fold" to + here. Always negate integer constants unless we honor -ftrapv + and the signed type would overflow. Always negate real constants + unless we honor -ftrapping-math. Only convert -(A-B) into B-A + if allowed by reorder_operands_p. Add support for COMPLEX_CST. + Optimize negation through floating point extensions and + sign-preserving built-in functions (as defined by negate_mathfn_p). + (fold): Adjust calls to tree_swap_operands_p. + (fold ): Move the remaining negation optimizations + to negate_expr_p/negate_expr. + (fold ): Use reorder_operands_p to check whether we're + allowed to convert (-A) - B into (-B) - A. + 2003-10-11 Roger Sayle * builtins.c (expand_builtin_strcmp): Defend against the possibility diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 92b885cc0c4e..2e64314c46e4 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -60,6 +60,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT); static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *); +static bool negate_mathfn_p (enum built_in_function); static bool negate_expr_p (tree); static tree negate_expr (tree); static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int); @@ -108,7 +109,8 @@ static bool fold_real_zero_addition_p (tree, tree, int); static tree fold_mathfn_compare (enum built_in_function, enum tree_code, tree, tree, tree); static tree fold_inf_compare (enum tree_code, tree, tree, tree); -static bool tree_swap_operands_p (tree, tree); +static bool reorder_operands_p (tree, tree); +static bool tree_swap_operands_p (tree, tree, bool); /* The following constants represent a bit based encoding of GCC's comparison operators. This encoding simplifies transformations @@ -803,6 +805,35 @@ div_and_round_double (enum tree_code code, int uns, return overflow; } +/* Return true if built-in mathematical function specified by CODE + preserves the sign of it argument, i.e. -f(x) == f(-x). */ + +static bool +negate_mathfn_p (enum built_in_function code) +{ + switch (code) + { + case BUILT_IN_ASIN: + case BUILT_IN_ASINF: + case BUILT_IN_ASINL: + case BUILT_IN_ATAN: + case BUILT_IN_ATANF: + case BUILT_IN_ATANL: + case BUILT_IN_SIN: + case BUILT_IN_SINF: + case BUILT_IN_SINL: + case BUILT_IN_TAN: + case BUILT_IN_TANF: + case BUILT_IN_TANL: + return true; + + default: + break; + } + return false; +} + + /* Determine whether an expression T can be cheaply negated using the function negate_expr. */ @@ -822,8 +853,8 @@ negate_expr_p (tree t) switch (TREE_CODE (t)) { case INTEGER_CST: - if (TREE_UNSIGNED (type)) - return false; + if (TREE_UNSIGNED (type) || ! flag_trapv) + return true; /* Check that -CST will not overflow type. */ prec = TYPE_PRECISION (type); @@ -844,9 +875,15 @@ negate_expr_p (tree t) case NEGATE_EXPR: return true; + case COMPLEX_CST: + return negate_expr_p (TREE_REALPART (t)) + && negate_expr_p (TREE_IMAGPART (t)); + case MINUS_EXPR: /* We can't turn -(A-B) into B-A when we honor signed zeros. */ - return ! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations; + return (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && reorder_operands_p (TREE_OPERAND (t, 0), + TREE_OPERAND (t, 1)); case MULT_EXPR: if (TREE_UNSIGNED (TREE_TYPE (t))) @@ -860,6 +897,22 @@ negate_expr_p (tree t) || negate_expr_p (TREE_OPERAND (t, 0)); break; + case NOP_EXPR: + /* Negate -((double)float) as (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tree tem = strip_float_extensions (t); + if (tem != t) + return negate_expr_p (tem); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (builtin_mathfn_code (t))) + return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))); + break; + default: break; } @@ -884,25 +937,53 @@ negate_expr (tree t) switch (TREE_CODE (t)) { case INTEGER_CST: - if (! TREE_UNSIGNED (type) - && 0 != (tem = fold (build1 (NEGATE_EXPR, type, t))) - && ! TREE_OVERFLOW (tem)) + { + unsigned HOST_WIDE_INT low; + HOST_WIDE_INT high; + int overflow = neg_double (TREE_INT_CST_LOW (t), + TREE_INT_CST_HIGH (t), + &low, &high); + tem = build_int_2 (low, high); + TREE_TYPE (tem) = type; + TREE_OVERFLOW (tem) + = (TREE_OVERFLOW (t) + | force_fit_type (tem, overflow && !TREE_UNSIGNED (type))); + TREE_CONSTANT_OVERFLOW (tem) + = TREE_OVERFLOW (tem) | TREE_CONSTANT_OVERFLOW (t); + } + if (! TREE_OVERFLOW (tem) + || TREE_UNSIGNED (type) + || ! flag_trapv) return tem; break; case REAL_CST: tem = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (t))); /* Two's complement FP formats, such as c4x, may overflow. */ - if (! TREE_OVERFLOW (tem)) + if (! TREE_OVERFLOW (tem) || ! flag_trapping_math) return convert (type, tem); break; + case COMPLEX_CST: + { + tree rpart = negate_expr (TREE_REALPART (t)); + tree ipart = negate_expr (TREE_IMAGPART (t)); + + if ((TREE_CODE (rpart) == REAL_CST + && TREE_CODE (ipart) == REAL_CST) + || (TREE_CODE (rpart) == INTEGER_CST + && TREE_CODE (ipart) == INTEGER_CST)) + return build_complex (type, rpart, ipart); + } + break; + case NEGATE_EXPR: return convert (type, TREE_OPERAND (t, 0)); case MINUS_EXPR: /* - (A - B) -> B - A */ - if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations) + && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1))) return convert (type, fold (build (MINUS_EXPR, TREE_TYPE (t), TREE_OPERAND (t, 1), @@ -933,6 +1014,30 @@ negate_expr (tree t) } break; + case NOP_EXPR: + /* Convert -((double)float) into (double)(-float). */ + if (TREE_CODE (type) == REAL_TYPE) + { + tem = strip_float_extensions (t); + if (tem != t && negate_expr_p (tem)) + return convert (type, negate_expr (tem)); + } + break; + + case CALL_EXPR: + /* Negate -f(x) as f(-x). */ + if (negate_mathfn_p (builtin_mathfn_code (t)) + && negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)))) + { + tree fndecl, arg, arglist; + + fndecl = get_callee_fndecl (t); + arg = negate_expr (TREE_VALUE (TREE_OPERAND (t, 1))); + arglist = build_tree_list (NULL_TREE, arg); + return build_function_call_expr (fndecl, arglist); + } + break; + default: break; } @@ -4999,12 +5104,27 @@ fold_single_bit_test (enum tree_code code, tree arg0, tree arg1, return NULL_TREE; } -/* Test whether it is preferable two swap two operands, ARG0 and - ARG1, for example because ARG0 is an integer constant and ARG1 - isn't. */ +/* Check whether we are allowed to reorder operands arg0 and arg1, + such that the evaluation of arg1 occurs before arg0. */ static bool -tree_swap_operands_p (tree arg0, tree arg1) +reorder_operands_p (tree arg0, tree arg1) +{ + if (! flag_evaluation_order) + return true; + if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1)) + return true; + return ! TREE_SIDE_EFFECTS (arg0) + && ! TREE_SIDE_EFFECTS (arg1); +} + +/* Test whether it is preferable two swap two operands, ARG0 and + ARG1, for example because ARG0 is an integer constant and ARG1 + isn't. If REORDER is true, only recommend swapping if we can + evaluate the operands in reverse order. */ + +static bool +tree_swap_operands_p (tree arg0, tree arg1, bool reorder) { STRIP_SIGN_NOPS (arg0); STRIP_SIGN_NOPS (arg1); @@ -5029,6 +5149,15 @@ tree_swap_operands_p (tree arg0, tree arg1) if (TREE_CONSTANT (arg0)) return 1; + if (reorder && flag_evaluation_order + && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1))) + return 0; + + if (DECL_P (arg1)) + return 0; + if (DECL_P (arg0)) + return 1; + return 0; } @@ -5143,7 +5272,7 @@ fold (tree expr) if ((code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR || code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR || code == BIT_AND_EXPR) - && tree_swap_operands_p (arg0, arg1)) + && tree_swap_operands_p (arg0, arg1, true)) return fold (build (code, type, arg1, arg0)); /* Now WINS is set as described above, @@ -5482,71 +5611,8 @@ fold (tree expr) return t; case NEGATE_EXPR: - if (wins) - { - if (TREE_CODE (arg0) == INTEGER_CST) - { - unsigned HOST_WIDE_INT low; - HOST_WIDE_INT high; - int overflow = neg_double (TREE_INT_CST_LOW (arg0), - TREE_INT_CST_HIGH (arg0), - &low, &high); - t = build_int_2 (low, high); - TREE_TYPE (t) = type; - TREE_OVERFLOW (t) - = (TREE_OVERFLOW (arg0) - | force_fit_type (t, overflow && !TREE_UNSIGNED (type))); - TREE_CONSTANT_OVERFLOW (t) - = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0); - } - else if (TREE_CODE (arg0) == REAL_CST) - t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0))); - } - else if (TREE_CODE (arg0) == NEGATE_EXPR) - return TREE_OPERAND (arg0, 0); - /* Convert -((double)float) into (double)(-float). */ - else if (TREE_CODE (arg0) == NOP_EXPR - && TREE_CODE (type) == REAL_TYPE) - { - tree targ0 = strip_float_extensions (arg0); - if (targ0 != arg0) - return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (targ0), targ0)); - - } - - /* Convert - (a - b) to (b - a) for non-floating-point. */ - else if (TREE_CODE (arg0) == MINUS_EXPR - && (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) - return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1), - TREE_OPERAND (arg0, 0)); - - /* Convert -f(x) into f(-x) where f is sin, tan or atan. */ - switch (builtin_mathfn_code (arg0)) - { - case BUILT_IN_SIN: - case BUILT_IN_SINF: - case BUILT_IN_SINL: - case BUILT_IN_TAN: - case BUILT_IN_TANF: - case BUILT_IN_TANL: - case BUILT_IN_ATAN: - case BUILT_IN_ATANF: - case BUILT_IN_ATANL: - if (negate_expr_p (TREE_VALUE (TREE_OPERAND (arg0, 1)))) - { - tree fndecl, arg, arglist; - - fndecl = get_callee_fndecl (arg0); - arg = TREE_VALUE (TREE_OPERAND (arg0, 1)); - arg = fold (build1 (NEGATE_EXPR, type, arg)); - arglist = build_tree_list (NULL_TREE, arg); - return build_function_call_expr (fndecl, arglist); - } - break; - - default: - break; - } + if (negate_expr_p (arg0)) + return negate_expr (arg0); return t; case ABS_EXPR: @@ -5999,8 +6065,7 @@ fold (tree expr) && (FLOAT_TYPE_P (type) || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)) && negate_expr_p (arg1) - && (! TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1)) - && (! TREE_SIDE_EFFECTS (arg1) || TREE_CONSTANT (arg0))) + && reorder_operands_p (arg0, arg1)) return fold (build (MINUS_EXPR, type, negate_expr (arg1), TREE_OPERAND (arg0, 0))); @@ -6911,7 +6976,7 @@ fold (tree expr) case LE_EXPR: case GE_EXPR: /* If one arg is a real or integer constant, put it last. */ - if (tree_swap_operands_p (arg0, arg1)) + if (tree_swap_operands_p (arg0, arg1, true)) return fold (build (swap_tree_comparison (code), type, arg1, arg0)); if (FLOAT_TYPE_P (TREE_TYPE (arg0))) @@ -8025,7 +8090,8 @@ fold (tree expr) /* If the second operand is simpler than the third, swap them since that produces better jump optimization results. */ - if (tree_swap_operands_p (TREE_OPERAND (t, 1), TREE_OPERAND (t, 2))) + if (tree_swap_operands_p (TREE_OPERAND (t, 1), + TREE_OPERAND (t, 2), false)) { /* See if this can be inverted. If it can't, possibly because it was a floating-point inequality comparison, don't do