OSDN Git Service

* ChangeLog: Follow spelling conventions.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index da72ffd..f098aa6 100644 (file)
@@ -108,8 +108,6 @@ 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));
@@ -120,8 +118,13 @@ static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
                                            enum rtx_code, int, rtx));
 static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
                                         enum machine_mode *, int *));
+static rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
+                                       rtx, rtx, rtx, int,
+                                       enum optab_methods));
+static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
+                                      int));
 \f
-/* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
+/* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
    operation).
 
@@ -132,43 +135,65 @@ static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
    again, ensuring that TARGET is not one of the operands.  */
 
 static int
-add_equal_note (seq, target, code, op0, op1)
-     rtx seq;
+add_equal_note (insns, target, code, op0, op1)
+     rtx insns;
      rtx target;
      enum rtx_code code;
      rtx op0, op1;
 {
-  rtx set;
-  int i;
+  rtx last_insn, insn, set;
   rtx note;
 
-  if ((GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
-       && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
-      || GET_CODE (seq) != SEQUENCE
-      || (set = single_set (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))) == 0
-      || GET_CODE (target) == ZERO_EXTRACT
-      || (! rtx_equal_p (SET_DEST (set), target)
-         /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
-            SUBREG.  */
-         && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
-             || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
-                               target))))
+  if (! insns
+      || ! INSN_P (insns)
+      || NEXT_INSN (insns) == NULL_RTX)
+    abort ();
+
+  if (GET_RTX_CLASS (code) != '1' && GET_RTX_CLASS (code) != '2'
+      && GET_RTX_CLASS (code) != 'c' && GET_RTX_CLASS (code) != '<')
+    return 1;
+
+  if (GET_CODE (target) == ZERO_EXTRACT)
+    return 1;
+
+  for (last_insn = insns;
+       NEXT_INSN (last_insn) != NULL_RTX;
+       last_insn = NEXT_INSN (last_insn))
+    ;
+
+  set = single_set (last_insn);
+  if (set == NULL_RTX)
+    return 1;
+
+  if (! rtx_equal_p (SET_DEST (set), target)
+      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
+        SUBREG.  */
+      && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
+         || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
+                           target)))
     return 1;
 
   /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
      besides the last insn.  */
   if (reg_overlap_mentioned_p (target, op0)
       || (op1 && reg_overlap_mentioned_p (target, op1)))
-    for (i = XVECLEN (seq, 0) - 2; i >= 0; i--)
-      if (reg_set_p (target, XVECEXP (seq, 0, i)))
-       return 0;
+    {
+      insn = PREV_INSN (last_insn);
+      while (insn != NULL_RTX)
+       {
+         if (reg_set_p (target, insn))
+           return 0;
+
+         insn = PREV_INSN (insn);
+       }
+    }
 
   if (GET_RTX_CLASS (code) == '1')
     note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
   else
     note = gen_rtx_fmt_ee (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
 
-  set_unique_reg_note (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1), REG_EQUAL, note);
+  set_unique_reg_note (last_insn, REG_EQUAL, note);
 
   return 1;
 }
@@ -214,22 +239,6 @@ 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
@@ -283,7 +292,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   if (divisor == 0)
     return 0;
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       /* Mathematically, ((a)(c-id))/divisor.  */
       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
@@ -449,7 +458,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       real_t = real0;
 
@@ -554,7 +563,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
 
@@ -770,34 +779,24 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        }
 
       /* In case the insn wants input operands in modes different from
-        the result, convert the operands.  It would seem that we
-        don't need to convert CONST_INTs, but we do, so that they're
-        a properly sign-extended for their modes; we choose the
-        widest mode between mode and mode[01], so that, in a widening
-        operation, we call convert_modes with different FROM and TO
-        modes, which ensures the value is sign-extended.  Shift
-        operations are an exception, because the second operand needs
-        not be extended to the mode of the result.  */
-
-      if (GET_MODE (op0) != mode0
-         && mode0 != VOIDmode)
+        those of the actual operands, convert the operands.  It would
+        seem that we don't need to convert CONST_INTs, but we do, so
+        that they're properly zero-extended or sign-extended for their
+        modes; shift operations are an exception, because the second
+        operand need not be extended to the mode of the result.  */
+
+      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
        xop0 = convert_modes (mode0,
                              GET_MODE (op0) != VOIDmode
                              ? GET_MODE (op0)
-                             : GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode0)
-                             ? mode
-                             : mode0,
+                             : mode,
                              xop0, unsignedp);
 
-      if (GET_MODE (xop1) != mode1
-         && mode1 != VOIDmode)
+      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
        xop1 = convert_modes (mode1,
                              GET_MODE (op1) != VOIDmode
                              ? GET_MODE (op1)
-                             : (GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode1)
-                                && ! shift_op)
-                             ? mode
-                             : mode1,
+                             : (shift_op ? mode1 : mode),
                              xop1, unsignedp);
 
       /* Now, if insn's predicates don't allow our operands, put them into
@@ -817,10 +816,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       pat = GEN_FCN (icode) (temp, xop0, xop1);
       if (pat)
        {
-         /* If PAT is a multi-insn sequence, try to add an appropriate
+         /* If PAT is composed of more than one insn, try to add an appropriate
             REG_EQUAL note to it.  If we can't because TEMP conflicts with an
             operand, call ourselves again, this time without a target.  */
-         if (GET_CODE (pat) == SEQUENCE
+         if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
              && ! add_equal_note (pat, temp, binoptab->code, xop0, xop1))
            {
              delete_insns_since (last);
@@ -1195,7 +1194,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (shift_count != BITS_PER_WORD)
            emit_no_conflict_block (insns, target, op0, op1, equiv_value);
          else
-           emit_insns (insns);
+           emit_insn (insns);
 
 
          return target;
@@ -1208,9 +1207,9 @@ 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;
-      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+      const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
       rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
       rtx xop0, xop1, xtarget;
 
@@ -1296,7 +1295,7 @@ 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)
            {
@@ -1509,6 +1508,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       delete_insns_since (last);
     }
 
+  /* Open-code the vector operations if we have no hardware support
+     for them.  */
+  if (class == MODE_VECTOR_INT || class == MODE_VECTOR_FLOAT)
+    return expand_vector_binop (mode, binoptab, op0, op1, target,
+                               unsignedp, methods);
+
   /* We need to open-code the complex type operations: '+, -, * and /' */
 
   /* At this point we allow operations between two similar complex
@@ -1576,11 +1581,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else if (res != realr)
            emit_move_insn (realr, res);
 
-         if (!complex_part_zero_p (imag0, class, submode)
-             && !complex_part_zero_p (imag1, class, submode))
+         if (imag0 != 0 && imag1 != 0)
            res = expand_binop (submode, binoptab, imag0, imag1,
                                imagr, unsignedp, methods);
-         else if (!complex_part_zero_p (imag0, class, submode))
+         else if (imag0 != 0)
            res = imag0;
          else if (binoptab->code == MINUS)
             res = expand_unop (submode,
@@ -1600,8 +1604,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        case MULT:
          /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
 
-         if (!complex_part_zero_p (imag0, class, submode)
-              && !complex_part_zero_p (imag1, class, submode))
+         if (imag0 != 0 && imag1 != 0)
            {
              rtx temp1, temp2;
 
@@ -1664,7 +1667,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              else if (res != realr)
                emit_move_insn (realr, res);
 
-             if (!complex_part_zero_p (imag0, class, submode))
+             if (imag0 != 0)
                res = expand_binop (submode, binoptab,
                                    real1, imag0, imagr, unsignedp, methods);
              else
@@ -1683,7 +1686,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 (complex_part_zero_p (imag1, class, submode))
+         if (imag1 == 0)
            {
              /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
 
@@ -1878,6 +1881,232 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
   delete_insns_since (entry_last);
   return 0;
 }
+
+/* Like expand_binop, but for open-coding vectors binops.  */
+
+static rtx
+expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
+     enum machine_mode mode;
+     optab binoptab;
+     rtx op0, op1;
+     rtx target;
+     int unsignedp;
+     enum optab_methods methods;
+{
+  enum machine_mode submode, tmode;
+  int size, elts, subsize, subbitsize, i;
+  rtx t, a, b, res, seq;
+  enum mode_class class;
+
+  class = GET_MODE_CLASS (mode);
+
+  size =  GET_MODE_SIZE (mode);
+  submode = GET_MODE_INNER (mode);
+
+  /* Search for the widest vector mode with the same inner mode that is
+     still narrower than MODE and that allows to open-code this operator.
+     Note, if we find such a mode and the handler later decides it can't
+     do the expansion, we'll be called recursively with the narrower mode.  */
+  for (tmode = GET_CLASS_NARROWEST_MODE (class);
+       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
+       tmode = GET_MODE_WIDER_MODE (tmode))
+    {
+      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
+         && binoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
+       submode = tmode;
+    }
+
+  switch (binoptab->code)
+    {
+    case AND:
+    case IOR:
+    case XOR:
+      tmode = int_mode_for_mode (mode);
+      if (tmode != BLKmode)
+       submode = tmode;
+    case PLUS:
+    case MINUS:
+    case MULT:
+    case DIV:
+      subsize = GET_MODE_SIZE (submode);
+      subbitsize = GET_MODE_BITSIZE (submode);
+      elts = size / subsize;
+
+      /* If METHODS is OPTAB_DIRECT, we don't insist on the exact mode,
+        but that we operate on more than one element at a time.  */
+      if (subsize == GET_MODE_UNIT_SIZE (mode) && methods == OPTAB_DIRECT)
+       return 0;
+
+      start_sequence ();
+
+      /* Errors can leave us with a const0_rtx as operand.  */
+      if (GET_MODE (op0) != mode)
+       op0 = copy_to_mode_reg (mode, op0);
+      if (GET_MODE (op1) != mode)
+       op1 = copy_to_mode_reg (mode, op1);
+
+      if (!target)
+       target = gen_reg_rtx (mode);
+
+      for (i = 0; i < elts; ++i)
+       {
+         /* If this is part of a register, and not the first item in the
+            word, we can't store using a SUBREG - that would clobber
+            previous results.
+            And storing with a SUBREG is only possible for the least
+            significant part, hence we can't do it for big endian
+            (unless we want to permute the evaluation order.  */
+         if (GET_CODE (target) == REG
+             && (BYTES_BIG_ENDIAN
+                 ? subsize < UNITS_PER_WORD
+                 : ((i * subsize) % UNITS_PER_WORD) != 0))
+           t = NULL_RTX;
+         else
+           t = simplify_gen_subreg (submode, target, mode, i * subsize);
+         if (CONSTANT_P (op0))
+           a = simplify_gen_subreg (submode, op0, mode, i * subsize);
+         else
+           a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
+                                  NULL_RTX, submode, submode, size);
+         if (CONSTANT_P (op1))
+           b = simplify_gen_subreg (submode, op1, mode, i * subsize);
+         else
+           b = extract_bit_field (op1, subbitsize, i * subbitsize, unsignedp,
+                                  NULL_RTX, submode, submode, size);
+
+         if (binoptab->code == DIV)
+           {
+             if (class == MODE_VECTOR_FLOAT)
+               res = expand_binop (submode, binoptab, a, b, t,
+                                   unsignedp, methods);
+             else
+               res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                                    a, b, t, unsignedp);
+           }
+         else
+           res = expand_binop (submode, binoptab, a, b, t,
+                               unsignedp, methods);
+
+         if (res == 0)
+           break;
+
+         if (t)
+           emit_move_insn (t, res);
+         else
+           store_bit_field (target, subbitsize, i * subbitsize, submode, res,
+                            size);
+       }
+      break;
+
+    default:
+      abort ();
+    }
+
+  seq = get_insns ();
+  end_sequence ();
+  emit_insn (seq);
+
+  return target;
+}
+
+/* Like expand_unop but for open-coding vector unops.  */
+
+static rtx
+expand_vector_unop (mode, unoptab, op0, target, unsignedp)
+     enum machine_mode mode;
+     optab unoptab;
+     rtx op0;
+     rtx target;
+     int unsignedp;
+{
+  enum machine_mode submode, tmode;
+  int size, elts, subsize, subbitsize, i;
+  rtx t, a, res, seq;
+
+  size =  GET_MODE_SIZE (mode);
+  submode = GET_MODE_INNER (mode);
+
+  /* Search for the widest vector mode with the same inner mode that is
+     still narrower than MODE and that allows to open-code this operator.
+     Note, if we find such a mode and the handler later decides it can't
+     do the expansion, we'll be called recursively with the narrower mode.  */
+  for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (mode));
+       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
+       tmode = GET_MODE_WIDER_MODE (tmode))
+    {
+      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
+         && unoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
+       submode = tmode;
+    }
+  /* If there is no negate operation, try doing a subtract from zero.  */
+  if (unoptab == neg_optab && GET_MODE_CLASS (submode) == MODE_INT
+      /* Avoid infinite recursion when an
+        error has left us with the wrong mode.  */
+      && GET_MODE (op0) == mode)
+    {    
+      rtx temp;
+      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
+                           target, unsignedp, OPTAB_DIRECT);
+      if (temp)
+       return temp;
+    }
+
+  if (unoptab == one_cmpl_optab)
+    {
+      tmode = int_mode_for_mode (mode);
+      if (tmode != BLKmode)
+       submode = tmode;
+    }
+
+  subsize = GET_MODE_SIZE (submode);
+  subbitsize = GET_MODE_BITSIZE (submode);
+  elts = size / subsize;
+
+  /* Errors can leave us with a const0_rtx as operand.  */
+  if (GET_MODE (op0) != mode)
+    op0 = copy_to_mode_reg (mode, op0);
+
+  if (!target)
+    target = gen_reg_rtx (mode);
+
+  start_sequence ();
+
+  for (i = 0; i < elts; ++i)
+    {
+      /* If this is part of a register, and not the first item in the
+        word, we can't store using a SUBREG - that would clobber
+        previous results.
+        And storing with a SUBREG is only possible for the least
+        significant part, hence we can't do it for big endian
+        (unless we want to permute the evaluation order.  */
+      if (GET_CODE (target) == REG
+         && (BYTES_BIG_ENDIAN
+             ?  subsize < UNITS_PER_WORD
+             : ((i * subsize) % UNITS_PER_WORD) != 0))
+       t = NULL_RTX;
+      else
+       t = simplify_gen_subreg (submode, target, mode, i * subsize);
+      if (CONSTANT_P (op0))
+       a = simplify_gen_subreg (submode, op0, mode, i * subsize);
+      else
+       a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
+                              t, submode, submode, size);
+
+      res = expand_unop (submode, unoptab, a, t, unsignedp);
+
+      if (t)
+       emit_move_insn (t, res);
+      else
+       store_bit_field (target, subbitsize, i * subbitsize, submode, res,
+                        size);
+    }
+
+  seq = get_insns ();
+  end_sequence ();
+  emit_insn (seq);
+
+  return target;
+}
 \f
 /* Expand a binary operator which has both signed and unsigned forms.
    UOPTAB is the optab for unsigned operations, and SOPTAB is for
@@ -2002,13 +2231,25 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
       rtx pat;
       rtx xop0 = op0, xop1 = op1;
 
-      /* In case this insn wants input operands in modes different from the
-        result, convert the operands.  */
-      if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0)
-       xop0 = convert_to_mode (mode0, xop0, unsignedp);
+      /* In case the insn wants input operands in modes different from
+        those of the actual operands, convert the operands.  It would
+        seem that we don't need to convert CONST_INTs, but we do, so
+        that they're properly zero-extended or sign-extended for their
+        modes.  */
 
-      if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1)
-       xop1 = convert_to_mode (mode1, xop1, unsignedp);
+      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
+       xop0 = convert_modes (mode0,
+                             GET_MODE (op0) != VOIDmode
+                             ? GET_MODE (op0)
+                             : mode,
+                             xop0, unsignedp);
+
+      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
+       xop1 = convert_modes (mode1,
+                             GET_MODE (op1) != VOIDmode
+                             ? GET_MODE (op1)
+                             : mode,
+                             xop1, unsignedp);
 
       /* Now, if insn doesn't accept these operands, put them into pseudos.  */
       if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
@@ -2146,7 +2387,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       pat = GEN_FCN (icode) (temp, xop0);
       if (pat)
        {
-         if (GET_CODE (pat) == SEQUENCE
+         if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
              && ! add_equal_note (pat, temp, unoptab->code, xop0, NULL_RTX))
            {
              delete_insns_since (last);
@@ -2302,6 +2543,9 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       return target;
     }
 
+  if (class == MODE_VECTOR_FLOAT || class == MODE_VECTOR_INT)
+    return expand_vector_unop (mode, unoptab, op0, target, unsignedp);
+
   /* It can't be done in this mode.  Can we do it in a wider mode?  */
 
   if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
@@ -2538,7 +2782,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
       pat = GEN_FCN (icode) (temp, xop0);
       if (pat)
        {
-         if (GET_CODE (pat) == SEQUENCE
+         if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
              && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 
                                   NULL_RTX))
            {
@@ -2707,7 +2951,7 @@ emit_unop_insn (icode, target, op0, code)
 
   pat = GEN_FCN (icode) (temp, op0);
 
-  if (GET_CODE (pat) == SEQUENCE && code != UNKNOWN)
+  if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
     add_equal_note (pat, temp, code, op0, NULL_RTX);
   
   emit_insn (pat);
@@ -2754,12 +2998,12 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
   rtx prev, next, first, last, insn;
 
   if (GET_CODE (target) != REG || reload_in_progress)
-    return emit_insns (insns);
+    return emit_insn (insns);
   else
     for (insn = insns; insn; insn = NEXT_INSN (insn))
       if (GET_CODE (insn) != INSN
          || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
-       return emit_insns (insns);
+       return emit_insn (insns);
 
   /* First emit all insns that do not store into words of the output and remove
      these from the list.  */
@@ -4082,7 +4326,7 @@ have_sub2_insn (x, y)
 }
 
 /* Generate the body of an instruction to copy Y into X.
-   It may be a SEQUENCE, if one insn isn't enough.  */
+   It may be a list of insns, if one insn isn't enough.  */
 
 rtx
 gen_move_insn (x, y)
@@ -4153,7 +4397,7 @@ gen_move_insn (x, y)
 
   start_sequence ();
   emit_move_insn_1 (x, y);
-  seq = gen_sequence ();
+  seq = get_insns ();
   end_sequence ();
   return seq;
 }
@@ -4733,7 +4977,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;
@@ -4865,19 +5109,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.  */
 
@@ -4964,6 +5195,8 @@ init_optabs ()
   sqrt_optab = init_optab (SQRT);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
+  exp_optab = init_optab (UNKNOWN);
+  log_optab = init_optab (UNKNOWN);
   strlen_optab = init_optab (UNKNOWN);
   cbranch_optab = init_optab (UNKNOWN);
   cmov_optab = init_optab (UNKNOWN);
@@ -5228,18 +5461,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 ()
@@ -5247,7 +5477,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
@@ -5277,7 +5506,7 @@ gen_cond_trap (code, op1, op2, tcode)
       if (insn)
        {
          emit_insn (insn);
-         insn = gen_sequence ();
+         insn = get_insns ();
        }
       end_sequence();
       return insn;
@@ -5286,3 +5515,5 @@ gen_cond_trap (code, op1, op2, tcode)
 
   return 0;
 }
+
+#include "gt-optabs.h"