improve open-coding of complex divide, use new method in g77
authorburley <burley@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 18 May 1999 01:05:14 +0000 (01:05 +0000)
committerburley <burley@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 18 May 1999 01:05:14 +0000 (01:05 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@26993 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/f/ChangeLog
gcc/f/com.c
gcc/f/version.c
gcc/flags.h
gcc/optabs.c
gcc/toplev.c

index fa3ed17..a117c6c 100644 (file)
@@ -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.
index a964204..92de51a 100644 (file)
@@ -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
index a3e0eb1..c04c4a7 100644 (file)
@@ -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
index 6705384..3d7362a 100644 (file)
@@ -1 +1 @@
-const char *ffe_version_string = "0.5.24-19990513";
+const char *ffe_version_string = "0.5.24-19990515";
index df73698..a3cc073 100644 (file)
@@ -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;
index 75f224c..9b4d4f1 100644 (file)
@@ -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;
 }
 \f
+/* 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;
+}
+\f
+/* 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;
+}
+\f
 /* 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;
          
index 7a1277c..1945351 100644 (file)
@@ -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;