From c64f913e0035db3d4a4137405b768d2f50c30eea Mon Sep 17 00:00:00 2001 From: Craig Burley Date: Tue, 18 May 1999 01:05:14 +0000 Subject: [PATCH] improve open-coding of complex divide, use new method in g77 From-SVN: r26993 --- gcc/ChangeLog | 13 ++ gcc/f/ChangeLog | 10 + gcc/f/com.c | 5 + gcc/f/version.c | 2 +- gcc/flags.h | 6 + gcc/optabs.c | 489 ++++++++++++++++++++++++++++++++++++++---------- gcc/toplev.c | 6 + 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 + + 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 * 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 + + 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 * 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)) */ + case 0: + ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1, + realr, imagr, submode, + unsignedp, methods, + class, binoptab); + break; - /* 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); + 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; - - imag_t = expand_unop (submode, neg_optab, imag_t, - NULL_RTX, unsignedp); + default: + abort (); } - 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; - - imag_t = expand_binop (submode, sub_optab, temp1, temp2, - NULL_RTX, unsignedp, methods); - - if (real_t == 0 || imag_t == 0) - break; - } - - 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;