OSDN Git Service

Merge from pch-branch up to tag pch-commit-20020603.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 0db33ca..2b366ad 100644 (file)
@@ -108,6 +108,8 @@ static rtx ftruncify        PARAMS ((rtx));
 static optab new_optab PARAMS ((void));
 static inline optab init_optab PARAMS ((enum rtx_code));
 static inline optab init_optabv        PARAMS ((enum rtx_code));
+static inline int complex_part_zero_p PARAMS ((rtx, enum mode_class,
+                                               enum machine_mode));
 static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
 static void init_integral_libfuncs PARAMS ((optab, const char *, int));
 static void init_floating_libfuncs PARAMS ((optab, const char *, int));
@@ -212,6 +214,22 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
   return result;
 }
 \f
+/* Test whether either the real or imaginary part of a complex floating
+   point number is 0.0, so that it can be ignored (when compiling
+   with -funsafe-math-optimizations). */
+
+static inline int
+complex_part_zero_p (part, class, submode)
+  rtx part;
+  enum mode_class class;
+  enum machine_mode submode;
+{
+  return part == 0 ||
+         (flag_unsafe_math_optimizations
+          && class == MODE_COMPLEX_FLOAT
+          && part == CONST0_RTX (submode));
+}
+
 /* Generate code to perform a straightforward complex divide.  */
 
 static int
@@ -265,7 +283,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   if (divisor == 0)
     return 0;
 
-  if (imag0 == 0)
+  if (complex_part_zero_p (imag0, class, submode))
     {
       /* Mathematically, ((a)(c-id))/divisor.  */
       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
@@ -431,7 +449,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (imag0 == 0)
+  if (complex_part_zero_p (imag0, class, submode))
     {
       real_t = real0;
 
@@ -536,7 +554,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (imag0 == 0)
+  if (complex_part_zero_p (imag0, class, submode))
     {
       /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
 
@@ -1190,11 +1208,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
       && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
     {
-      int i;
+      unsigned int i;
       optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
-      unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
       rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
-      rtx xop0, xop1;
+      rtx xop0, xop1, xtarget;
 
       /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
         value is one of those, use it.  Otherwise, use 1 since it is the
@@ -1209,19 +1227,20 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       xop0 = force_reg (mode, op0);
       xop1 = force_reg (mode, op1);
 
-      if (target == 0 || GET_CODE (target) != REG
-         || target == xop0 || target == xop1)
-       target = gen_reg_rtx (mode);
+      xtarget = gen_reg_rtx (mode);
+
+      if (target == 0 || GET_CODE (target) != REG)
+       target = xtarget;
 
       /* Indicate for flow that the entire target reg is being set.  */
       if (GET_CODE (target) == REG)
-       emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
+       emit_insn (gen_rtx_CLOBBER (VOIDmode, xtarget));
 
       /* Do the actual arithmetic.  */
       for (i = 0; i < nwords; i++)
        {
          int index = (WORDS_BIG_ENDIAN ? nwords - i - 1 : i);
-         rtx target_piece = operand_subword (target, index, 1, mode);
+         rtx target_piece = operand_subword (xtarget, index, 1, mode);
          rtx op0_piece = operand_subword_force (xop0, index, mode);
          rtx op1_piece = operand_subword_force (xop1, index, mode);
          rtx x;
@@ -1277,11 +1296,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          carry_in = carry_out;
        }       
 
-      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
+      if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
        {
          if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
-             rtx temp = emit_move_insn (target, target);
+             rtx temp = emit_move_insn (target, xtarget);
 
              set_unique_reg_note (temp,
                                   REG_EQUAL,
@@ -1443,6 +1462,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
                                   NULL_RTX, 0, OPTAB_DIRECT);
 
+         if (!REG_P (product_high))
+           product_high = force_reg (word_mode, product_high);
+
          if (temp != 0)
            temp = expand_binop (word_mode, add_optab, temp, product_high,
                                 product_high, 0, next_methods);
@@ -1462,6 +1484,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (temp != 0 && temp != product_high)
            emit_move_insn (product_high, temp);
 
+         emit_move_insn (operand_subword (product, high, 1, mode), product_high);
+
          if (temp != 0)
            {
              if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
@@ -1535,7 +1559,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       else
        real1 = op1;
 
-      if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
+      if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
        abort ();
 
       switch (binoptab->code)
@@ -1552,10 +1576,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else if (res != realr)
            emit_move_insn (realr, res);
 
-         if (imag0 && imag1)
+         if (!complex_part_zero_p (imag0, class, submode)
+             && !complex_part_zero_p (imag1, class, submode))
            res = expand_binop (submode, binoptab, imag0, imag1,
                                imagr, unsignedp, methods);
-         else if (imag0)
+         else if (!complex_part_zero_p (imag0, class, submode))
            res = imag0;
          else if (binoptab->code == MINUS)
             res = expand_unop (submode,
@@ -1575,7 +1600,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        case MULT:
          /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
 
-         if (imag0 && imag1)
+         if (!complex_part_zero_p (imag0, class, submode)
+              && !complex_part_zero_p (imag1, class, submode))
            {
              rtx temp1, temp2;
 
@@ -1638,7 +1664,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              else if (res != realr)
                emit_move_insn (realr, res);
 
-             if (imag0 != 0)
+             if (!complex_part_zero_p (imag0, class, submode))
                res = expand_binop (submode, binoptab,
                                    real1, imag0, imagr, unsignedp, methods);
              else
@@ -1657,7 +1683,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        case DIV:
          /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
          
-         if (imag1 == 0)
+         if (complex_part_zero_p (imag1, class, submode))
            {
              /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
 
@@ -2739,11 +2765,18 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
      these from the list.  */
   for (insn = insns; insn; insn = next)
     {
-      rtx set = 0;
+      rtx set = 0, note;
       int i;
 
       next = NEXT_INSN (insn);
 
+      /* Some ports (cris) create an libcall regions at their own.  We must
+        avoid any potential nesting of LIBCALLs.  */
+      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
+       remove_note (insn, note);
+      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
+       remove_note (insn, note);
+
       if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
          || GET_CODE (PATTERN (insn)) == CLOBBER)
        set = PATTERN (insn);
@@ -2906,6 +2939,14 @@ emit_libcall_block (insns, target, result, equiv)
   for (insn = insns; insn; insn = next)
     {
       rtx set = single_set (insn);
+      rtx note;
+
+      /* Some ports (cris) create an libcall regions at their own.  We must
+        avoid any potential nesting of LIBCALLs.  */
+      if ((note = find_reg_note (insn, REG_LIBCALL, NULL)) != NULL)
+       remove_note (insn, note);
+      if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
+       remove_note (insn, note);
 
       next = NEXT_INSN (insn);
 
@@ -3399,6 +3440,7 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
      int *punsignedp;
 {
   enum rtx_code comparison = *pcomparison;
+  rtx tmp;
   rtx x = *px = protect_from_queue (*px, 0);
   rtx y = *py = protect_from_queue (*py, 0);
   enum machine_mode mode = GET_MODE (x);
@@ -3418,18 +3460,42 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
 
       case GT:
        libfunc = gthf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LT;
+           libfunc = lthf2_libfunc;
+         }
        break;
 
       case GE:
        libfunc = gehf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LE;
+           libfunc = lehf2_libfunc;
+         }
        break;
 
       case LT:
        libfunc = lthf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GT;
+           libfunc = gthf2_libfunc;
+         }
        break;
 
       case LE:
        libfunc = lehf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GE;
+           libfunc = gehf2_libfunc;
+         }
        break;
 
       case UNORDERED:
@@ -3452,18 +3518,42 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
 
       case GT:
        libfunc = gtsf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LT;
+           libfunc = ltsf2_libfunc;
+         }
        break;
 
       case GE:
        libfunc = gesf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LE;
+           libfunc = lesf2_libfunc;
+         }
        break;
 
       case LT:
        libfunc = ltsf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GT;
+           libfunc = gtsf2_libfunc;
+         }
        break;
 
       case LE:
        libfunc = lesf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GE;
+           libfunc = gesf2_libfunc;
+         }
        break;
 
       case UNORDERED:
@@ -3486,18 +3576,42 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
 
       case GT:
        libfunc = gtdf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LT;
+           libfunc = ltdf2_libfunc;
+         }
        break;
 
       case GE:
        libfunc = gedf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LE;
+           libfunc = ledf2_libfunc;
+         }
        break;
 
       case LT:
        libfunc = ltdf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GT;
+           libfunc = gtdf2_libfunc;
+         }
        break;
 
       case LE:
        libfunc = ledf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GE;
+           libfunc = gedf2_libfunc;
+         }
        break;
 
       case UNORDERED:
@@ -3520,18 +3634,42 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
 
       case GT:
        libfunc = gtxf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LT;
+           libfunc = ltxf2_libfunc;
+         }
        break;
 
       case GE:
        libfunc = gexf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LE;
+           libfunc = lexf2_libfunc;
+         }
        break;
 
       case LT:
        libfunc = ltxf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GT;
+           libfunc = gtxf2_libfunc;
+         }
        break;
 
       case LE:
        libfunc = lexf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GE;
+           libfunc = gexf2_libfunc;
+         }
        break;
 
       case UNORDERED:
@@ -3554,18 +3692,42 @@ prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
 
       case GT:
        libfunc = gttf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LT;
+           libfunc = lttf2_libfunc;
+         }
        break;
 
       case GE:
        libfunc = getf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = LE;
+           libfunc = letf2_libfunc;
+         }
        break;
 
       case LT:
        libfunc = lttf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GT;
+           libfunc = gttf2_libfunc;
+         }
        break;
 
       case LE:
        libfunc = letf2_libfunc;
+       if (libfunc == NULL_RTX)
+         {
+           tmp = x; x = y; y = tmp;
+           *pcomparison = GE;
+           libfunc = getf2_libfunc;
+         }
        break;
 
       case UNORDERED:
@@ -4439,9 +4601,9 @@ expand_fix (to, from, unsignedp)
                                 NULL_RTX, 0, OPTAB_LIB_WIDEN);
          expand_fix (to, target, 0);
          target = expand_binop (GET_MODE (to), xor_optab, to,
-                                GEN_INT (trunc_int_for_mode
-                                         ((HOST_WIDE_INT) 1 << (bitsize - 1),
-                                          GET_MODE (to))),
+                                gen_int_mode
+                                ((HOST_WIDE_INT) 1 << (bitsize - 1),
+                                 GET_MODE (to)),
                                 to, 1, OPTAB_LIB_WIDEN);
 
          if (target != to)
@@ -4571,7 +4733,7 @@ static optab
 new_optab ()
 {
   int i;
-  optab op = (optab) xmalloc (sizeof (struct optab));
+  optab op = (optab) ggc_alloc (sizeof (struct optab));
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       op->handlers[i].insn_code = CODE_FOR_nothing;
@@ -4689,7 +4851,8 @@ rtx
 init_one_libfunc (name)
      const char *name;
 {
-  /* Create a FUNCTION_DECL that can be passed to ENCODE_SECTION_INFO.  */
+  /* Create a FUNCTION_DECL that can be passed to
+     targetm.encode_section_info.  */
   /* ??? We don't have any type information except for this is
      a function.  Pretend this is "int foo()".  */
   tree decl = build_decl (FUNCTION_DECL, get_identifier (name),
@@ -4702,19 +4865,6 @@ init_one_libfunc (name)
   return XEXP (DECL_RTL (decl), 0);
 }
 
-/* Mark ARG (which is really an OPTAB *) for GC.  */
-
-void
-mark_optab (arg)
-     void *arg;
-{
-  optab o = *(optab *) arg;
-  int i;
-
-  for (i = 0; i < NUM_MACHINE_MODES; ++i)
-    ggc_mark_rtx (o->handlers[i].libfunc);
-}
-
 /* Call this once to initialize the contents of the optabs
    appropriately for the current target machine.  */
 
@@ -4940,6 +5090,7 @@ init_optabs ()
   truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
   trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
 
+  abort_libfunc = init_one_libfunc ("abort");
   memcpy_libfunc = init_one_libfunc ("memcpy");
   memmove_libfunc = init_one_libfunc ("memmove");
   bcopy_libfunc = init_one_libfunc ("bcopy");
@@ -5064,18 +5215,15 @@ init_optabs ()
   /* Allow the target to add more libcalls or rename some, etc.  */
   INIT_TARGET_OPTABS;
 #endif
-
-  /* Add these GC roots.  */
-  ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab);
-  ggc_add_rtx_root (libfunc_table, LTI_MAX);
 }
 \f
+static GTY(()) rtx trap_rtx;
+
 #ifdef HAVE_conditional_trap
 /* The insn generating function can not take an rtx_code argument.
    TRAP_RTX is used as an rtx argument.  Its code is replaced with
    the code to be used in the trap insn and all other fields are
    ignored.  */
-static rtx trap_rtx;
 
 static void
 init_traps ()
@@ -5083,7 +5231,6 @@ init_traps ()
   if (HAVE_conditional_trap)
     {
       trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
-      ggc_add_rtx_root (&trap_rtx, 1);
     }
 }
 #endif
@@ -5122,3 +5269,5 @@ gen_cond_trap (code, op1, op2, tcode)
 
   return 0;
 }
+
+#include "gt-optabs.h"