diff options
author | Kaveh R. Ghazi <ghazi@caip.rutgers.edu> | 2009-09-24 20:44:55 +0000 |
---|---|---|
committer | Kaveh Ghazi <ghazi@gcc.gnu.org> | 2009-09-24 20:44:55 +0000 |
commit | e3d5405d071e33540d70c62c6e24a2dfa7cc7d9d (patch) | |
tree | 942e85ee11d063e393b8d23171086e6c6108a90e /gcc/fold-const.c | |
parent | 18b802688624127aa26b3d75dd0ce41e06cbeee9 (diff) | |
download | gcc-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.c | 71 |
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: |