aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Burley <craig@jcb-sc.com>1999-05-18 01:05:14 +0000
committerCraig Burley <craig@jcb-sc.com>1999-05-18 01:05:14 +0000
commitf9555ee958bd43d88e090dd8d971cbc8ac9e78a1 (patch)
treebf672e6d747e77a35f1c2998b3ff0cc8a94b55b6
parent69a1e153a38af6a43fc5b79d03416b00404c352e (diff)
improve open-coding of complex divide, use new method in g77
git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@26993 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/f/ChangeLog10
-rw-r--r--gcc/f/com.c5
-rw-r--r--gcc/f/version.c2
-rw-r--r--gcc/flags.h6
-rw-r--r--gcc/optabs.c489
-rw-r--r--gcc/toplev.c6
7 files changed, 426 insertions, 105 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fa3ed179733..a117c6c299c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+Tue May 18 03:53:37 1999 Craig Burley <craig@jcb-sc.com>
+
+ Improve open-coding of complex divide:
+ * flags.h: Declare new front-end-malleable flag.
+ * toplev.c: Define new flag.
+ * optabs.c (expand_cmplxdiv_straight): New function to do original
+ open-coding.
+ (expand_cmplxdiv_wide): New function to do new open-coding,
+ from Toon Moene, with changes (call to emit_barrier, dropping
+ of spurious `ok = 1;', plus the obvious `break;' -> `return 0;').
+ (expand_binop): A bit of spacing fixing, while at it.
+ Use new functions instead of inlining the open-coding code.
+
Tue May 18 00:51:46 1999 Krister Walfridsson <cato@df.lth.se>
* configure.in (arm*-*-netbsd*): Use collect2.
diff --git a/gcc/f/ChangeLog b/gcc/f/ChangeLog
index a9642049932..92de51ab922 100644
--- a/gcc/f/ChangeLog
+++ b/gcc/f/ChangeLog
@@ -1,3 +1,13 @@
+Tue May 18 03:52:04 1999 Craig Burley <craig@jcb-sc.com>
+
+ Support use of back end's improved open-coding of complex divide:
+ * com.c (ffecom_tree_divide_): Use RDIV_EXPR for complex divide,
+ instead of run-time call to [cz]_div, if `-Os' option specified.
+ (lang_init_options): Tell back end we want support for wide range
+ of inputs to complex divide.
+
+ * Bump version.
+
Tue May 18 00:21:34 1999 Zack Weinberg <zack@rabi.phys.columbia.edu>
* lang-specs.h: Define __GNUC__ and __GNUC_MINOR__ only if -no-gcc
diff --git a/gcc/f/com.c b/gcc/f/com.c
index a3e0eb1b3a0..c04c4a77089 100644
--- a/gcc/f/com.c
+++ b/gcc/f/com.c
@@ -9378,6 +9378,10 @@ ffecom_tree_divide_ (tree tree_type, tree left, tree right,
right);
case COMPLEX_TYPE:
+ if (! optimize_size)
+ return ffecom_2 (RDIV_EXPR, tree_type,
+ left,
+ right);
{
ffecomGfrt ix;
@@ -15019,6 +15023,7 @@ lang_init_options ()
flag_reduce_all_givs = 1;
flag_argument_noalias = 2;
flag_errno_math = 0;
+ flag_complex_divide_method = 1;
}
void
diff --git a/gcc/f/version.c b/gcc/f/version.c
index 6705384221d..3d7362ad843 100644
--- a/gcc/f/version.c
+++ b/gcc/f/version.c
@@ -1 +1 @@
-const char *ffe_version_string = "0.5.24-19990513";
+const char *ffe_version_string = "0.5.24-19990515";
diff --git a/gcc/flags.h b/gcc/flags.h
index df736988cce..a3cc073383e 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -296,6 +296,12 @@ extern int flag_fast_math;
extern int flag_errno_math;
+/* 0 means straightforward implementation of complex divide acceptable.
+ 1 means wide ranges of inputs must work for complex divide.
+ 2 means C9X-like requirements for complex divide (not yet implemented). */
+
+extern int flag_complex_divide_method;
+
/* Nonzero means to run loop optimizations twice. */
extern int flag_rerun_loop_opt;
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 75f224c4809..9b4d4f1059c 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -246,6 +246,14 @@ enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
static int add_equal_note PROTO((rtx, rtx, enum rtx_code, rtx, rtx));
static rtx widen_operand PROTO((rtx, enum machine_mode,
enum machine_mode, int, int));
+static int expand_cmplxdiv_straight PROTO((rtx, rtx, rtx, rtx,
+ rtx, rtx, enum machine_mode,
+ int, enum optab_methods,
+ enum mode_class, optab));
+static int expand_cmplxdiv_wide PROTO((rtx, rtx, rtx, rtx,
+ rtx, rtx, enum machine_mode,
+ int, enum optab_methods,
+ enum mode_class, optab));
static enum insn_code can_fix_p PROTO((enum machine_mode, enum machine_mode,
int, int *));
static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,
@@ -348,6 +356,365 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
return result;
}
+/* Generate code to perform a straightforward complex divide. */
+
+static int
+expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
+ rtx realr, rtx imagr, enum machine_mode submode,
+ int unsignedp, enum optab_methods methods,
+ enum mode_class class, optab binoptab)
+{
+ rtx divisor;
+ rtx real_t, imag_t;
+ rtx temp1, temp2;
+ rtx res;
+
+ /* Don't fetch these from memory more than once. */
+ real0 = force_reg (submode, real0);
+ real1 = force_reg (submode, real1);
+
+ if (imag0 != 0)
+ imag0 = force_reg (submode, imag0);
+
+ imag1 = force_reg (submode, imag1);
+
+ /* Divisor: c*c + d*d. */
+ temp1 = expand_binop (submode, smul_optab, real1, real1,
+ NULL_RTX, unsignedp, methods);
+
+ temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0 || temp2 == 0)
+ return 0;
+
+ divisor = expand_binop (submode, add_optab, temp1, temp2,
+ NULL_RTX, unsignedp, methods);
+ if (divisor == 0)
+ return 0;
+
+ if (imag0 == 0)
+ {
+ /* Mathematically, ((a)(c-id))/divisor. */
+ /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)). */
+
+ /* Calculate the dividend. */
+ real_t = expand_binop (submode, smul_optab, real0, real1,
+ NULL_RTX, unsignedp, methods);
+
+ imag_t = expand_binop (submode, smul_optab, real0, imag1,
+ NULL_RTX, unsignedp, methods);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+
+ imag_t = expand_unop (submode, neg_optab, imag_t,
+ NULL_RTX, unsignedp);
+ }
+ else
+ {
+ /* Mathematically, ((a+ib)(c-id))/divider. */
+ /* Calculate the dividend. */
+ temp1 = expand_binop (submode, smul_optab, real0, real1,
+ NULL_RTX, unsignedp, methods);
+
+ temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0 || temp2 == 0)
+ return 0;
+
+ real_t = expand_binop (submode, add_optab, temp1, temp2,
+ NULL_RTX, unsignedp, methods);
+
+ temp1 = expand_binop (submode, smul_optab, imag0, real1,
+ NULL_RTX, unsignedp, methods);
+
+ temp2 = expand_binop (submode, smul_optab, real0, imag1,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0 || temp2 == 0)
+ return 0;
+
+ imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+ NULL_RTX, unsignedp, methods);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+ }
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, real_t, divisor,
+ realr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ real_t, divisor, realr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != realr)
+ emit_move_insn (realr, res);
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, imag_t, divisor,
+ imagr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ imag_t, divisor, imagr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != imagr)
+ emit_move_insn (imagr, res);
+
+ return 1;
+}
+
+/* Generate code to perform a wide-input-range-acceptable complex divide. */
+
+static int
+expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
+ rtx realr, rtx imagr, enum machine_mode submode,
+ int unsignedp, enum optab_methods methods,
+ enum mode_class class, optab binoptab)
+{
+ rtx ratio, divisor;
+ rtx real_t, imag_t;
+ rtx temp1, temp2, lab1, lab2;
+ enum machine_mode mode;
+ int align;
+ rtx res;
+
+ /* Don't fetch these from memory more than once. */
+ real0 = force_reg (submode, real0);
+ real1 = force_reg (submode, real1);
+
+ if (imag0 != 0)
+ imag0 = force_reg (submode, imag0);
+
+ imag1 = force_reg (submode, imag1);
+
+ temp1 = expand_unop (submode, abs_optab, real1, NULL_RTX,
+ unsignedp);
+
+ temp2 = expand_unop (submode, abs_optab, imag1, NULL_RTX,
+ unsignedp);
+
+ if (temp1 == 0 || temp2 == 0)
+ return 0;
+
+ mode = GET_MODE (temp1);
+ align = GET_MODE_ALIGNMENT (mode);
+ lab1 = gen_label_rtx ();
+ emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
+ mode, unsignedp, align, lab1);
+
+ /* |c| >= |d|; use ratio d/c to scale dividend and divisor. */
+
+ if (class == MODE_COMPLEX_FLOAT)
+ ratio = expand_binop (submode, binoptab, imag1, real1,
+ NULL_RTX, unsignedp, methods);
+ else
+ ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ imag1, real1, NULL_RTX, unsignedp);
+
+ if (ratio == 0)
+ return 0;
+
+ /* Calculate divisor. */
+
+ temp1 = expand_binop (submode, smul_optab, imag1, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ divisor = expand_binop (submode, add_optab, temp1, real1,
+ NULL_RTX, unsignedp, methods);
+
+ if (divisor == 0)
+ return 0;
+
+ /* Calculate dividend. */
+
+ if (imag0 == 0)
+ {
+ real_t = real0;
+
+ /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)). */
+
+ imag_t = expand_binop (submode, smul_optab, real0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (imag_t == 0)
+ return 0;
+
+ imag_t = expand_unop (submode, neg_optab, imag_t,
+ NULL_RTX, unsignedp);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+ }
+ else
+ {
+ /* Compute (a+ib)/(c+id) as
+ (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)). */
+
+ temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ real_t = expand_binop (submode, add_optab, temp1, real0,
+ NULL_RTX, unsignedp, methods);
+
+ temp1 = expand_binop (submode, smul_optab, real0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ imag_t = expand_binop (submode, sub_optab, imag0, temp1,
+ NULL_RTX, unsignedp, methods);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+ }
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, real_t, divisor,
+ realr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ real_t, divisor, realr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != realr)
+ emit_move_insn (realr, res);
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, imag_t, divisor,
+ imagr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ imag_t, divisor, imagr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != imagr)
+ emit_move_insn (imagr, res);
+
+ lab2 = gen_label_rtx ();
+ emit_jump_insn (gen_jump (lab2));
+ emit_barrier ();
+
+ emit_label (lab1);
+
+ /* |d| > |c|; use ratio c/d to scale dividend and divisor. */
+
+ if (class == MODE_COMPLEX_FLOAT)
+ ratio = expand_binop (submode, binoptab, real1, imag1,
+ NULL_RTX, unsignedp, methods);
+ else
+ ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ real1, imag1, NULL_RTX, unsignedp);
+
+ if (ratio == 0)
+ return 0;
+
+ /* Calculate divisor. */
+
+ temp1 = expand_binop (submode, smul_optab, real1, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ divisor = expand_binop (submode, add_optab, temp1, imag1,
+ NULL_RTX, unsignedp, methods);
+
+ if (divisor == 0)
+ return 0;
+
+ /* Calculate dividend. */
+
+ if (imag0 == 0)
+ {
+ /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d). */
+
+ real_t = expand_binop (submode, smul_optab, real0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ imag_t = expand_unop (submode, neg_optab, real0,
+ NULL_RTX, unsignedp);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+ }
+ else
+ {
+ /* Compute (a+ib)/(c+id) as
+ (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d). */
+
+ temp1 = expand_binop (submode, smul_optab, real0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ real_t = expand_binop (submode, add_optab, temp1, imag0,
+ NULL_RTX, unsignedp, methods);
+
+ temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+ NULL_RTX, unsignedp, methods);
+
+ if (temp1 == 0)
+ return 0;
+
+ imag_t = expand_binop (submode, sub_optab, temp1, real0,
+ NULL_RTX, unsignedp, methods);
+
+ if (real_t == 0 || imag_t == 0)
+ return 0;
+ }
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, real_t, divisor,
+ realr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ real_t, divisor, realr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != realr)
+ emit_move_insn (realr, res);
+
+ if (class == MODE_COMPLEX_FLOAT)
+ res = expand_binop (submode, binoptab, imag_t, divisor,
+ imagr, unsignedp, methods);
+ else
+ res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+ imag_t, divisor, imagr, unsignedp);
+
+ if (res == 0)
+ return 0;
+
+ if (res != imagr)
+ emit_move_insn (imagr, res);
+
+ emit_label (lab2);
+
+ return 1;
+}
+
/* Generate code to perform an operation specified by BINOPTAB
on operands OP0 and OP1, with result having machine-mode MODE.
@@ -1219,12 +1586,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
start_sequence ();
- realr = gen_realpart (submode, target);
+ realr = gen_realpart (submode, target);
imagr = gen_imagpart (submode, target);
if (GET_MODE (op0) == mode)
{
- real0 = gen_realpart (submode, op0);
+ real0 = gen_realpart (submode, op0);
imag0 = gen_imagpart (submode, op0);
}
else
@@ -1232,7 +1599,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
if (GET_MODE (op1) == mode)
{
- real1 = gen_realpart (submode, op1);
+ real1 = gen_realpart (submode, op1);
imag1 = gen_imagpart (submode, op1);
}
else
@@ -1390,111 +1757,25 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
}
else
{
- /* Divisor is of complex type:
- X/(a+ib) */
- rtx divisor;
- rtx real_t, imag_t;
- rtx temp1, temp2;
-
- /* Don't fetch these from memory more than once. */
- real0 = force_reg (submode, real0);
- real1 = force_reg (submode, real1);
-
- if (imag0 != 0)
- imag0 = force_reg (submode, imag0);
-
- imag1 = force_reg (submode, imag1);
-
- /* Divisor: c*c + d*d */
- temp1 = expand_binop (submode, smul_optab, real1, real1,
- NULL_RTX, unsignedp, methods);
-
- temp2 = expand_binop (submode, smul_optab, imag1, imag1,
- NULL_RTX, unsignedp, methods);
-
- if (temp1 == 0 || temp2 == 0)
- break;
-
- divisor = expand_binop (submode, add_optab, temp1, temp2,
- NULL_RTX, unsignedp, methods);
- if (divisor == 0)
- break;
-
- if (imag0 == 0)
+ switch (flag_complex_divide_method)
{
- /* ((a)(c-id))/divisor */
- /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */
-
- /* Calculate the dividend */
- real_t = expand_binop (submode, smul_optab, real0, real1,
- NULL_RTX, unsignedp, methods);
-
- imag_t = expand_binop (submode, smul_optab, real0, imag1,
- NULL_RTX, unsignedp, methods);
-
- if (real_t == 0 || imag_t == 0)
- break;
-
- imag_t = expand_unop (submode, neg_optab, imag_t,
- NULL_RTX, unsignedp);
- }
- else
- {
- /* ((a+ib)(c-id))/divider */
- /* Calculate the dividend */
- temp1 = expand_binop (submode, smul_optab, real0, real1,
- NULL_RTX, unsignedp, methods);
-
- temp2 = expand_binop (submode, smul_optab, imag0, imag1,
- NULL_RTX, unsignedp, methods);
-
- if (temp1 == 0 || temp2 == 0)
- break;
-
- real_t = expand_binop (submode, add_optab, temp1, temp2,
- NULL_RTX, unsignedp, methods);
-
- temp1 = expand_binop (submode, smul_optab, imag0, real1,
- NULL_RTX, unsignedp, methods);
-
- temp2 = expand_binop (submode, smul_optab, real0, imag1,
- NULL_RTX, unsignedp, methods);
-
- if (temp1 == 0 || temp2 == 0)
- break;
+ case 0:
+ ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
+ realr, imagr, submode,
+ unsignedp, methods,
+ class, binoptab);
+ break;
- imag_t = expand_binop (submode, sub_optab, temp1, temp2,
- NULL_RTX, unsignedp, methods);
+ case 1:
+ ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
+ realr, imagr, submode,
+ unsignedp, methods,
+ class, binoptab);
+ break;
- if (real_t == 0 || imag_t == 0)
- break;
+ default:
+ abort ();
}
-
- if (class == MODE_COMPLEX_FLOAT)
- res = expand_binop (submode, binoptab, real_t, divisor,
- realr, unsignedp, methods);
- else
- res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
- real_t, divisor, realr, unsignedp);
-
- if (res == 0)
- break;
- else if (res != realr)
- emit_move_insn (realr, res);
-
- if (class == MODE_COMPLEX_FLOAT)
- res = expand_binop (submode, binoptab, imag_t, divisor,
- imagr, unsignedp, methods);
- else
- res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
- imag_t, divisor, imagr, unsignedp);
-
- if (res == 0)
- break;
- else if (res != imagr)
- emit_move_insn (imagr, res);
-
- ok = 1;
}
break;
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 7a1277cedce..194535116b3 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -563,6 +563,12 @@ int flag_fast_math = 0;
int flag_errno_math = 1;
+/* 0 means straightforward implementation of complex divide acceptable.
+ 1 means wide ranges of inputs must work for complex divide.
+ 2 means C9X-like requirements for complex divide (not yet implemented). */
+
+int flag_complex_divide_method = 0;
+
/* Nonzero means all references through pointers are volatile. */
int flag_volatile;