aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
authorKaveh R. Ghazi <ghazi@caip.rutgers.edu>2009-09-24 20:44:55 +0000
committerKaveh Ghazi <ghazi@gcc.gnu.org>2009-09-24 20:44:55 +0000
commite3d5405d071e33540d70c62c6e24a2dfa7cc7d9d (patch)
tree942e85ee11d063e393b8d23171086e6c6108a90e /gcc/fold-const.c
parent18b802688624127aa26b3d75dd0ce41e06cbeee9 (diff)
downloadgcc-e3d5405d071e33540d70c62c6e24a2dfa7cc7d9d.zip
gcc-e3d5405d071e33540d70c62c6e24a2dfa7cc7d9d.tar.gz
gcc-e3d5405d071e33540d70c62c6e24a2dfa7cc7d9d.tar.bz2
re PR middle-end/41435 (GCC doesn't fold complex int division)
PR middle-end/41435 * fold-const.c (const_binop): Handle complex int division. * tree-complex.c (expand_complex_div_straight, expand_complex_div_wide): Update comments. testsuite: * gcc.dg/torture/builtin-math-7.c: Test complex int division at compile-time. From-SVN: r152145
Diffstat (limited to 'gcc/fold-const.c')
-rw-r--r--gcc/fold-const.c71
1 files changed, 68 insertions, 3 deletions
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 34e47c1..d754bee 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1995,9 +1995,22 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
return do_mpc_arg2 (arg1, arg2, type,
/* do_nonfinite= */ folding_initializer,
mpc_div);
+ /* Fallthru ... */
#endif
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ if (flag_complex_method == 0)
{
+ /* Keep this algorithm in sync with
+ tree-complex.c:expand_complex_div_straight().
+
+ Expand complex division to scalars, straightforward algorithm.
+ a / b = ((ar*br + ai*bi)/t) + i((ai*br - ar*bi)/t)
+ t = br*br + bi*bi
+ */
tree magsquared
= const_binop (PLUS_EXPR,
const_binop (MULT_EXPR, r2, r2, notrunc),
@@ -2014,12 +2027,64 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
const_binop (MULT_EXPR, r1, i2, notrunc),
notrunc);
- if (INTEGRAL_TYPE_P (TREE_TYPE (r1)))
- code = TRUNC_DIV_EXPR;
-
real = const_binop (code, t1, magsquared, notrunc);
imag = const_binop (code, t2, magsquared, notrunc);
}
+ else
+ {
+ /* Keep this algorithm in sync with
+ tree-complex.c:expand_complex_div_wide().
+
+ Expand complex division to scalars, modified algorithm to minimize
+ overflow with wide input ranges. */
+ tree inner_type = TREE_TYPE (type);
+ tree absr2 = fold_build1 (ABS_EXPR, inner_type, r2);
+ tree absi2 = fold_build1 (ABS_EXPR, inner_type, i2);
+ tree compare = fold_build2 (LT_EXPR, boolean_type_node, absr2, absi2);
+ if (integer_nonzerop (compare))
+ {
+ /* In the TRUE branch, we compute
+ ratio = br/bi;
+ div = (br * ratio) + bi;
+ tr = (ar * ratio) + ai;
+ ti = (ai * ratio) - ar;
+ tr = tr / div;
+ ti = ti / div; */
+ tree ratio = fold_build2 (code, inner_type, r2, i2);
+ tree div = fold_build2 (PLUS_EXPR, inner_type, i2,
+ fold_build2 (MULT_EXPR, inner_type,
+ r2, ratio));
+ real = fold_build2 (MULT_EXPR, inner_type, r1, ratio);
+ real = fold_build2 (PLUS_EXPR, inner_type, real, i1);
+ real = fold_build2 (code, inner_type, real, div);
+
+ imag = fold_build2 (MULT_EXPR, inner_type, i1, ratio);
+ imag = fold_build2 (MINUS_EXPR, inner_type, imag, r1);
+ imag = fold_build2 (code, inner_type, imag, div);
+ }
+ else
+ {
+ /* In the FALSE branch, we compute
+ ratio = d/c;
+ divisor = (d * ratio) + c;
+ tr = (b * ratio) + a;
+ ti = b - (a * ratio);
+ tr = tr / div;
+ ti = ti / div; */
+ tree ratio = fold_build2 (code, inner_type, i2, r2);
+ tree div = fold_build2 (PLUS_EXPR, inner_type, r2,
+ fold_build2 (MULT_EXPR, inner_type,
+ i2, ratio));
+
+ real = fold_build2 (MULT_EXPR, inner_type, i1, ratio);
+ real = fold_build2 (PLUS_EXPR, inner_type, real, r1);
+ real = fold_build2 (code, inner_type, real, div);
+
+ imag = fold_build2 (MULT_EXPR, inner_type, r1, ratio);
+ imag = fold_build2 (MINUS_EXPR, inner_type, i1, imag);
+ imag = fold_build2 (code, inner_type, imag, div);
+ }
+ }
break;
default: