aboutsummaryrefslogtreecommitdiff
path: root/gcc/fold-const.c
diff options
context:
space:
mode:
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: