diff options
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/expmed.c | 25 | ||||
-rw-r--r-- | gcc/fold-const.c | 79 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/20030804-1.c | 75 |
5 files changed, 175 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 60a391c..daf0bec 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2003-08-04 Roger Sayle <roger@eyesopen.com> + * fold-const.c (fold <PLUS_EXPR>): Transform x+x into x*2.0. + Optimize x*c+x and x+x*c into x*(c+1) and x*c1+x*c2 into x*(c1+c2) + for floating point expressions with -ffast-math. + (fold <MULT_EXPR>): Don't transform x*2.0 into x+x. + * expmed.c (expand_mult): Wrap long line. Expand x*2.0 as x+x. + +2003-08-04 Roger Sayle <roger@eyesopen.com> + * c-common.c (flag_noniso_default_format_attributes): Delete. (built_in_attribute): Don't define/undefine DEF_FN_ATTR. (c_attrs_initialized): Delete. diff --git a/gcc/expmed.c b/gcc/expmed.c index 68163e9..89ecd0c 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -2300,7 +2300,8 @@ synth_mult (struct algorithm *alg_out, unsigned HOST_WIDE_INT t, you should swap the two operands if OP0 would be constant. */ rtx -expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, int unsignedp) +expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, + int unsignedp) { rtx const_op1 = op1; @@ -2514,6 +2515,28 @@ expand_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target, int unsignedp } } + if (GET_CODE (op0) == CONST_DOUBLE) + { + rtx temp = op0; + op0 = op1; + op1 = temp; + } + + /* Expand x*2.0 as x+x. */ + if (GET_CODE (op1) == CONST_DOUBLE + && GET_MODE_CLASS (mode) == MODE_FLOAT) + { + REAL_VALUE_TYPE d; + REAL_VALUE_FROM_CONST_DOUBLE (d, op1); + + if (REAL_VALUES_EQUAL (d, dconst2)) + { + op0 = force_reg (GET_MODE (op0), op0); + return expand_binop (mode, add_optab, op0, op0, + target, unsignedp, OPTAB_LIB_WIDEN); + } + } + /* This used to use umul_optab if unsigned, but for non-widening multiply there is no difference between signed and unsigned. */ op0 = expand_binop (mode, diff --git a/gcc/fold-const.c b/gcc/fold-const.c index c4faf07..4dd606f 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -5659,14 +5659,72 @@ fold (tree expr) same)); } } + else + { + /* See if ARG1 is zero and X + ARG1 reduces to X. */ + if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0)) + return non_lvalue (convert (type, arg0)); - /* See if ARG1 is zero and X + ARG1 reduces to X. */ - else if (fold_real_zero_addition_p (TREE_TYPE (arg0), arg1, 0)) - return non_lvalue (convert (type, arg0)); + /* Likewise if the operands are reversed. */ + if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0)) + return non_lvalue (convert (type, arg1)); - /* Likewise if the operands are reversed. */ - else if (fold_real_zero_addition_p (TREE_TYPE (arg1), arg0, 0)) - return non_lvalue (convert (type, arg1)); + /* Convert x+x into x*2.0. */ + if (operand_equal_p (arg0, arg1, 0)) + return fold (build (MULT_EXPR, type, arg0, + build_real (type, dconst2))); + + /* Convert x*c+x into x*(c+1). */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1)) + && operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)) + { + REAL_VALUE_TYPE c; + + c = TREE_REAL_CST (TREE_OPERAND (arg0, 1)); + real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); + return fold (build (MULT_EXPR, type, arg1, + build_real (type, c))); + } + + /* Convert x+x*c into x*(c+1). */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg1) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1)) + && operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0)) + { + REAL_VALUE_TYPE c; + + c = TREE_REAL_CST (TREE_OPERAND (arg1, 1)); + real_arithmetic (&c, PLUS_EXPR, &c, &dconst1); + return fold (build (MULT_EXPR, type, arg0, + build_real (type, c))); + } + + /* Convert x*c1+x*c2 into x*(c1+c2). */ + if (flag_unsafe_math_optimizations + && TREE_CODE (arg0) == MULT_EXPR + && TREE_CODE (arg1) == MULT_EXPR + && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1)) + && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST + && ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1)) + && operand_equal_p (TREE_OPERAND (arg0, 0), + TREE_OPERAND (arg1, 0), 0)) + { + REAL_VALUE_TYPE c1, c2; + + c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1)); + c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1)); + real_arithmetic (&c1, PLUS_EXPR, &c1, &c2); + return fold (build (MULT_EXPR, type, + TREE_OPERAND (arg0, 0), + build_real (type, c1))); + } + } bit_rotate: /* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A @@ -5954,15 +6012,6 @@ fold (tree expr) && real_minus_onep (arg1)) return fold (build1 (NEGATE_EXPR, type, arg0)); - /* x*2 is x+x */ - if (! wins && real_twop (arg1) - && (*lang_hooks.decls.global_bindings_p) () == 0 - && ! CONTAINS_PLACEHOLDER_P (arg0)) - { - tree arg = save_expr (arg0); - return fold (build (PLUS_EXPR, type, arg, arg)); - } - if (flag_unsafe_math_optimizations) { enum built_in_function fcode0 = builtin_mathfn_code (arg0); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 862280a..ba19bc8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2003-08-04 Roger Sayle <roger@eyesopen.com> + + * gcc.dg/20030804-1.c: New test case. + 2003-08-04 Alexandre Oliva <aoliva@redhat.com> * gcc.dg/cpp/separate-1.c: New test. diff --git a/gcc/testsuite/gcc.dg/20030804-1.c b/gcc/testsuite/gcc.dg/20030804-1.c new file mode 100644 index 0000000..cbc6647 --- /dev/null +++ b/gcc/testsuite/gcc.dg/20030804-1.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2003 Free Software Foundation. + + Check that constant folding of mathematical expressions doesn't + break anything. + + Written by Roger Sayle, 3rd August 2003. */ + +/* { dg-do link } */ +/* { dg-options "-O2 -ffast-math" } */ + +extern void link_error(void); + +void test(double x) +{ + if (x+x != 2.0*x) + link_error (); + if (x+x != x*2.0) + link_error (); + + if (x+x+x != 3.0*x) + link_error (); + if (x+x+x != x*3.0) + link_error (); + + if ((x+x)+x != 3.0*x) + link_error (); + if ((x+x)+x != x*3.0) + link_error (); + + if (x+(x+x) != 3.0*x) + link_error (); + if (x+(x+x) != x*3.0) + link_error (); + + if (x+4.0*x != 5.0*x) + link_error (); + if (x+4.0*x != x*5.0) + link_error (); + if (x+x*4.0 != 5.0*x) + link_error (); + if (x+x*4.0 != x*5.0) + link_error (); + if (4.0*x+x != 5.0*x) + link_error (); + if (4.0*x+x != x*5.0) + link_error (); + if (x*4.0+x != 5.0*x) + link_error (); + if (x*4.0+x != x*5.0) + link_error (); + + if (3.0*x + 5.0*x != 8.0*x) + link_error (); + if (3.0*x + 5.0*x != x*8.0) + link_error (); + if (x*3.0 + 5.0*x != 8.0*x) + link_error (); + if (x*3.0 + 5.0*x != x*8.0) + link_error (); + if (3.0*x + x*5.0 != 8.0*x) + link_error (); + if (3.0*x + x*5.0 != x*8.0) + link_error (); + if (x*3.0 + x*5.0 != 8.0*x) + link_error (); + if (x*3.0 + x*5.0 != x*8.0) + link_error (); +} + +int main() +{ + test(2.0); + return 0; +} + |