OSDN Git Service

* c-common.c (shadow_warning): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index b4023e3..e748c15 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -43,6 +43,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "ggc.h"
 #include "real.h"
 #include "basic-block.h"
+#include "target.h"
 
 /* Each optab contains info on how this target machine
    can perform a particular operation
@@ -57,13 +58,8 @@ optab optab_table[OTI_MAX];
 
 rtx libfunc_table[LTI_MAX];
 
-/* Tables of patterns for extending one integer mode to another.  */
-enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
-
-/* Tables of patterns for converting between fixed and floating point.  */
-enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
+/* Tables of patterns for converting one mode to another.  */
+convert_optab convert_optab_table[CTI_MAX];
 
 /* Contains the optab used for each rtx code.  */
 optab code_to_optab[NUM_RTX_CODE + 1];
@@ -111,11 +107,17 @@ static enum insn_code can_fix_p (enum machine_mode, enum machine_mode, int,
 static enum insn_code can_float_p (enum machine_mode, enum machine_mode, int);
 static rtx ftruncify (rtx);
 static optab new_optab (void);
+static convert_optab new_convert_optab (void);
 static inline optab init_optab (enum rtx_code);
 static inline optab init_optabv (enum rtx_code);
+static inline convert_optab init_convert_optab (enum rtx_code);
 static void init_libfuncs (optab, int, int, const char *, int);
 static void init_integral_libfuncs (optab, const char *, int);
 static void init_floating_libfuncs (optab, const char *, int);
+static void init_interclass_conv_libfuncs (convert_optab, const char *,
+                                          enum mode_class, enum mode_class);
+static void init_intraclass_conv_libfuncs (convert_optab, const char *,
+                                          enum mode_class, bool);
 static void emit_cmp_and_jump_insn_1 (rtx, rtx, enum machine_mode,
                                      enum rtx_code, int, rtx);
 static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
@@ -1519,24 +1521,17 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       rtx real0 = 0, imag0 = 0;
       rtx real1 = 0, imag1 = 0;
       rtx realr, imagr, res;
-      rtx seq;
-      rtx equiv_value;
+      rtx seq, result;
       int ok = 0;
 
       /* Find the correct mode for the real and imaginary parts.  */
-      enum machine_mode submode = GET_MODE_INNER(mode);
+      enum machine_mode submode = GET_MODE_INNER (mode);
 
       if (submode == BLKmode)
        abort ();
 
-      if (! target)
-       target = gen_reg_rtx (mode);
-
       start_sequence ();
 
-      realr = gen_realpart (submode, target);
-      imagr = gen_imagpart (submode, target);
-
       if (GET_MODE (op0) == mode)
        {
          real0 = gen_realpart (submode, op0);
@@ -1556,6 +1551,10 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       if (real0 == 0 || real1 == 0 || ! (imag0 != 0 || imag1 != 0))
        abort ();
 
+      result = gen_reg_rtx (mode);
+      realr = gen_realpart (submode, result);
+      imagr = gen_imagpart (submode, result);
+
       switch (binoptab->code)
        {
        case PLUS:
@@ -1747,16 +1746,10 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
 
       if (ok)
        {
-         if (binoptab->code != UNKNOWN)
-           equiv_value
-             = gen_rtx_fmt_ee (binoptab->code, mode,
-                               copy_rtx (op0), copy_rtx (op1));
-         else
-           equiv_value = 0;
-
-         emit_no_conflict_block (seq, target, op0, op1, equiv_value);
-
-         return target;
+         rtx equiv = gen_rtx_fmt_ee (binoptab->code, mode,
+                                     copy_rtx (op0), copy_rtx (op1));
+         emit_no_conflict_block (seq, result, op0, op1, equiv);
+         return result;
        }
     }
 
@@ -2365,7 +2358,7 @@ expand_parity (enum machine_mode mode, rtx op0, rtx target)
              temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
                                  true);
              if (temp != 0)
-               temp = expand_binop (wider_mode, and_optab, temp, GEN_INT (1),
+               temp = expand_binop (wider_mode, and_optab, temp, const1_rtx,
                                     target, true, OPTAB_DIRECT);
              if (temp == 0)
                delete_insns_since (last);
@@ -2581,7 +2574,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
   if (unoptab->code == NEG && class == MODE_FLOAT
       && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
     {
-      const struct real_format *fmt = real_format_for_mode[mode - QFmode];
+      const struct real_format *fmt = REAL_MODE_FORMAT (mode);
       enum machine_mode imode = int_mode_for_mode (mode);
       int bitpos = (fmt != 0) ? fmt->signbit : -1;
 
@@ -2613,7 +2606,16 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
                               immed_double_const (lo, hi, imode),
                               NULL_RTX, 1, OPTAB_LIB_WIDEN);
          if (temp != 0)
-           return gen_lowpart (mode, temp);
+           {
+             rtx insn;
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             insn = emit_move_insn (target, gen_lowpart (mode, temp));
+             set_unique_reg_note (insn, REG_EQUAL,
+                                  gen_rtx_fmt_e (NEG, mode,
+                                                 copy_rtx (op0)));
+             return target;
+           }
          delete_insns_since (last);
         }
     }
@@ -2638,7 +2640,8 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
         have them return something that isn't a double-word.  */
       if (unoptab == ffs_optab || unoptab == clz_optab || unoptab == ctz_optab
          || unoptab == popcount_optab || unoptab == parity_optab)
-       outmode = TYPE_MODE (integer_type_node);
+       outmode
+           = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));
 
       start_sequence ();
 
@@ -2755,7 +2758,7 @@ expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
       && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
     {
-      const struct real_format *fmt = real_format_for_mode[mode - QFmode];
+      const struct real_format *fmt = REAL_MODE_FORMAT (mode);
       enum machine_mode imode = int_mode_for_mode (mode);
       int bitpos = (fmt != 0) ? fmt->signbit : -1;
 
@@ -2787,7 +2790,16 @@ expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
                               immed_double_const (~lo, ~hi, imode),
                               NULL_RTX, 1, OPTAB_LIB_WIDEN);
          if (temp != 0)
-           return gen_lowpart (mode, temp);
+           {
+             rtx insn;
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             insn = emit_move_insn (target, gen_lowpart (mode, temp));
+             set_unique_reg_note (insn, REG_EQUAL,
+                                  gen_rtx_fmt_e (ABS, mode,
+                                                 copy_rtx (op0)));
+             return target;
+           }
          delete_insns_since (last);
        }
     }
@@ -3175,7 +3187,7 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
 
       next = NEXT_INSN (insn);
 
-      /* Some ports (cris) create an libcall regions at their own.  We must
+      /* Some ports (cris) create a 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);
@@ -3325,9 +3337,9 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
          rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
 
          if (note != 0)
-           XEXP (note, 0) = GEN_INT (-1);
+           XEXP (note, 0) = constm1_rtx;
          else
-           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (-1),
+           REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx,
                                                  REG_NOTES (insn));
        }
 
@@ -3342,7 +3354,7 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
       rtx set = single_set (insn);
       rtx note;
 
-      /* Some ports (cris) create an libcall regions at their own.  We must
+      /* Some ports (cris) create a 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);
@@ -3568,71 +3580,71 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
 
   if (mode == BLKmode)
     {
+      enum machine_mode cmp_mode, result_mode;
+      enum insn_code cmp_code;
+      tree length_type;
+      rtx libfunc;
       rtx result;
-      enum machine_mode result_mode;
-      rtx opalign ATTRIBUTE_UNUSED
+      rtx opalign
        = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
 
+      if (size == 0)
+       abort ();
+
       emit_queue ();
       x = protect_from_queue (x, 0);
       y = protect_from_queue (y, 0);
+      size = protect_from_queue (size, 0);
 
-      if (size == 0)
-       abort ();
-#ifdef HAVE_cmpstrqi
-      if (HAVE_cmpstrqi
-         && GET_CODE (size) == CONST_INT
-         && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
-         result = gen_reg_rtx (result_mode);
-         emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
-       }
-      else
-#endif
-#ifdef HAVE_cmpstrhi
-      if (HAVE_cmpstrhi
-         && GET_CODE (size) == CONST_INT
-         && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
-         result = gen_reg_rtx (result_mode);
-         emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
-       }
-      else
-#endif
-#ifdef HAVE_cmpstrsi
-      if (HAVE_cmpstrsi)
+      /* Try to use a memory block compare insn - either cmpstr
+        or cmpmem will do.  */
+      for (cmp_mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
+          cmp_mode != VOIDmode;
+          cmp_mode = GET_MODE_WIDER_MODE (cmp_mode))
        {
-         result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
+         cmp_code = cmpmem_optab[cmp_mode];
+         if (cmp_code == CODE_FOR_nothing)
+           cmp_code = cmpstr_optab[cmp_mode];
+         if (cmp_code == CODE_FOR_nothing)
+           continue;
+
+         /* Must make sure the size fits the insn's mode.  */
+         if ((GET_CODE (size) == CONST_INT
+              && INTVAL (size) >= (1 << GET_MODE_BITSIZE (cmp_mode)))
+             || (GET_MODE_BITSIZE (GET_MODE (size))
+                 > GET_MODE_BITSIZE (cmp_mode)))
+           continue;
+
+         result_mode = insn_data[cmp_code].operand[0].mode;
          result = gen_reg_rtx (result_mode);
-         size = protect_from_queue (size, 0);
-         emit_insn (gen_cmpstrsi (result, x, y,
-                                  convert_to_mode (SImode, size, 1),
-                                  opalign));
+         size = convert_to_mode (cmp_mode, size, 1);
+         emit_insn (GEN_FCN (cmp_code) (result, x, y, size, opalign));
+
+         *px = result;
+         *py = const0_rtx;
+         *pmode = result_mode;
+         return;
        }
-      else
-#endif
-       {
+
+      /* Otherwise call a library function, memcmp if we've got it,
+        bcmp otherwise.  */
 #ifdef TARGET_MEM_FUNCTIONS
-         result = emit_library_call_value (memcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
-                                           TYPE_MODE (integer_type_node), 3,
-                                           XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
-                                           convert_to_mode (TYPE_MODE (sizetype), size,
-                                                            TREE_UNSIGNED (sizetype)),
-                                           TYPE_MODE (sizetype));
+      libfunc = memcmp_libfunc;
+      length_type = sizetype;
 #else
-         result = emit_library_call_value (bcmp_libfunc, NULL_RTX, LCT_PURE_MAKE_BLOCK,
-                                           TYPE_MODE (integer_type_node), 3,
-                                           XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
-                                           convert_to_mode (TYPE_MODE (integer_type_node),
-                                                            size,
-                                                            TREE_UNSIGNED (integer_type_node)),
-                                           TYPE_MODE (integer_type_node));
+      libfunc = bcmp_libfunc;
+      length_type = integer_type_node;
 #endif
-
-         result_mode = TYPE_MODE (integer_type_node);
-       }
+      result_mode = TYPE_MODE (integer_type_node);
+      cmp_mode = TYPE_MODE (length_type);
+      size = convert_to_mode (TYPE_MODE (length_type), size,
+                             TREE_UNSIGNED (length_type));
+
+      result = emit_library_call_value (libfunc, 0, LCT_PURE_MAKE_BLOCK,
+                                       result_mode, 3,
+                                       XEXP (x, 0), Pmode,
+                                       XEXP (y, 0), Pmode,
+                                       size, cmp_mode);
       *px = result;
       *py = const0_rtx;
       *pmode = result_mode;
@@ -3691,7 +3703,12 @@ prepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
 
   if (! (*insn_data[icode].operand[opnum].predicate)
       (x, insn_data[icode].operand[opnum].mode))
-    x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
+    {
+      if (no_new_pseudos)
+       return NULL_RTX;
+      x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
+    }
+
   return x;
 }
 
@@ -3832,339 +3849,112 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
                       enum machine_mode *pmode, 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);
+  enum rtx_code swapped = swap_condition (comparison);
+  rtx x = protect_from_queue (*px, 0);
+  rtx y = protect_from_queue (*py, 0);
+  enum machine_mode orig_mode = GET_MODE (x);
+  enum machine_mode mode;
+  rtx value, target, insns, equiv;
   rtx libfunc = 0;
-  rtx result;
-
-  if (mode == HFmode)
-    switch (comparison)
-      {
-      case EQ:
-       libfunc = eqhf2_libfunc;
-       break;
-
-      case NE:
-       libfunc = nehf2_libfunc;
-       break;
 
-      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:
-       libfunc = unordhf2_libfunc;
-       break;
-
-      default:
-       break;
-      }
-  else if (mode == SFmode)
-    switch (comparison)
-      {
-      case EQ:
-       libfunc = eqsf2_libfunc;
-       break;
-
-      case NE:
-       libfunc = nesf2_libfunc;
-       break;
-
-      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:
-       libfunc = unordsf2_libfunc;
-       break;
-
-      default:
-       break;
-      }
-  else if (mode == DFmode)
-    switch (comparison)
-      {
-      case EQ:
-       libfunc = eqdf2_libfunc;
-       break;
-
-      case NE:
-       libfunc = nedf2_libfunc;
-       break;
-
-      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:
-       libfunc = unorddf2_libfunc;
-       break;
-
-      default:
-       break;
-      }
-  else if (mode == XFmode)
-    switch (comparison)
-      {
-      case EQ:
-       libfunc = eqxf2_libfunc;
-       break;
-
-      case NE:
-       libfunc = nexf2_libfunc;
-       break;
-
-      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:
-       libfunc = unordxf2_libfunc;
-       break;
-
-      default:
-       break;
-      }
-  else if (mode == TFmode)
-    switch (comparison)
-      {
-      case EQ:
-       libfunc = eqtf2_libfunc;
-       break;
-
-      case NE:
-       libfunc = netf2_libfunc;
-       break;
-
-      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;
-         }
+  for (mode = orig_mode; mode != VOIDmode; mode = GET_MODE_WIDER_MODE (mode))
+    {
+      if ((libfunc = code_to_optab[comparison]->handlers[mode].libfunc))
        break;
 
-      case LT:
-       libfunc = lttf2_libfunc;
-       if (libfunc == NULL_RTX)
-         {
-           tmp = x; x = y; y = tmp;
-           *pcomparison = GT;
-           libfunc = gttf2_libfunc;
-         }
-       break;
+      if ((libfunc = code_to_optab[swapped]->handlers[mode].libfunc))
+       {
+         rtx tmp;
+         tmp = x; x = y; y = tmp;
+         comparison = swapped;
+         break;
+       }
+    }
 
-      case LE:
-       libfunc = letf2_libfunc;
-       if (libfunc == NULL_RTX)
-         {
-           tmp = x; x = y; y = tmp;
-           *pcomparison = GE;
-           libfunc = getf2_libfunc;
-         }
-       break;
+  if (mode == VOIDmode)
+    abort ();
 
-      case UNORDERED:
-       libfunc = unordtf2_libfunc;
-       break;
+  if (mode != orig_mode)
+    {
+      x = convert_to_mode (mode, x, 0);
+      y = convert_to_mode (mode, y, 0);
+    }
 
-      default:
-       break;
-      }
+  /* Attach a REG_EQUAL note describing the semantics of the libcall to
+     the RTL.  The allows the RTL optimizers to delete the libcall if the
+     condition can be determined at compile-time.  */
+  if (comparison == UNORDERED)
+    {
+      rtx temp = simplify_gen_relational (NE, word_mode, mode, x, x);
+      equiv = simplify_gen_relational (NE, word_mode, mode, y, y);
+      equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
+                                   temp, const_true_rtx, equiv);
+    }
   else
     {
-      enum machine_mode wider_mode;
-
-      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
-          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+      equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
+      if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
        {
-         if ((cmp_optab->handlers[(int) wider_mode].insn_code
-              != CODE_FOR_nothing)
-             || (cmp_optab->handlers[(int) wider_mode].libfunc != 0))
+         rtx true_rtx, false_rtx;
+
+         switch (comparison)
            {
-             x = protect_from_queue (x, 0);
-             y = protect_from_queue (y, 0);
-             *px = convert_to_mode (wider_mode, x, 0);
-             *py = convert_to_mode (wider_mode, y, 0);
-             prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
-             return;
+           case EQ:
+             true_rtx = const0_rtx;
+             false_rtx = const_true_rtx;
+             break;
+
+           case NE:
+             true_rtx = const_true_rtx;
+             false_rtx = const0_rtx;
+             break;
+
+           case GT:
+             true_rtx = const1_rtx;
+             false_rtx = const0_rtx;
+             break;
+
+           case GE:
+             true_rtx = const0_rtx;
+             false_rtx = constm1_rtx;
+             break;
+
+           case LT:
+             true_rtx = constm1_rtx;
+             false_rtx = const0_rtx;
+             break;
+
+           case LE:
+             true_rtx = const0_rtx;
+             false_rtx = const1_rtx;
+             break;
+
+           default:
+             abort ();
            }
+         equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
+                                       equiv, true_rtx, false_rtx);
        }
-      abort ();
     }
 
-  if (libfunc == 0)
-    abort ();
+  start_sequence ();
+  value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+                                  word_mode, 2, x, mode, y, mode);
+  insns = get_insns ();
+  end_sequence ();
+
+  target = gen_reg_rtx (word_mode);
+  emit_libcall_block (insns, target, value, equiv);
 
-  result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
-                                   word_mode, 2, x, mode, y, mode);
-  *px = result;
+
+  if (comparison == UNORDERED
+      || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
+    comparison = NE;
+
+  *px = target;
   *py = const0_rtx;
   *pmode = word_mode;
-  if (comparison == UNORDERED)
-    *pcomparison = NE;
-#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
-  else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
-    *pcomparison = NE;
-#endif
+  *pcomparison = comparison;
   *punsignedp = 0;
 }
 \f
@@ -4220,9 +4010,9 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
   /* get_condition will prefer to generate LT and GT even if the old
      comparison was against zero, so undo that canonicalization here since
      comparisons against zero are cheaper.  */
-  if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+  if (code == LT && op1 == const1_rtx)
     code = LE, op1 = const0_rtx;
-  else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+  else if (code == GT && op1 == constm1_rtx)
     code = GE, op1 = const0_rtx;
 
   if (cmode == VOIDmode)
@@ -4361,9 +4151,9 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
   /* get_condition will prefer to generate LT and GT even if the old
      comparison was against zero, so undo that canonicalization here since
      comparisons against zero are cheaper.  */
-  if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+  if (code == LT && op1 == const1_rtx)
     code = LE, op1 = const0_rtx;
-  else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+  else if (code == GT && op1 == constm1_rtx)
     code = GE, op1 = const0_rtx;
 
   if (cmode == VOIDmode)
@@ -4599,12 +4389,14 @@ enum insn_code
 can_extend_p (enum machine_mode to_mode, enum machine_mode from_mode,
              int unsignedp)
 {
+  convert_optab tab;
 #ifdef HAVE_ptr_extend
   if (unsignedp < 0)
     return CODE_FOR_ptr_extend;
-  else
 #endif
-    return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
+
+  tab = unsignedp ? zext_optab : sext_optab;
+  return tab->handlers[to_mode][from_mode].insn_code;
 }
 
 /* Generate the body of an insn to extend Y (with mode MFROM)
@@ -4614,7 +4406,8 @@ rtx
 gen_extend_insn (rtx x, rtx y, enum machine_mode mto,
                 enum machine_mode mfrom, int unsignedp)
 {
-  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
+  enum insn_code icode = can_extend_p (mto, mfrom, unsignedp);
+  return GEN_FCN (icode) (x, y);
 }
 \f
 /* can_fix_p and can_float_p say whether the target machine
@@ -4630,16 +4423,27 @@ static enum insn_code
 can_fix_p (enum machine_mode fixmode, enum machine_mode fltmode,
           int unsignedp, int *truncp_ptr)
 {
-  *truncp_ptr = 0;
-  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
-      != CODE_FOR_nothing)
-    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
+  convert_optab tab;
+  enum insn_code icode;
+
+  tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
+  icode = tab->handlers[fixmode][fltmode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      *truncp_ptr = 0;
+      return icode;
+    }
 
-  if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
+  tab = unsignedp ? ufix_optab : sfix_optab;
+  icode = tab->handlers[fixmode][fltmode].insn_code;
+  if (icode != CODE_FOR_nothing
+      && ftrunc_optab->handlers[fltmode].insn_code != CODE_FOR_nothing)
     {
       *truncp_ptr = 1;
-      return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
+      return icode;
     }
+
+  *truncp_ptr = 0;
   return CODE_FOR_nothing;
 }
 
@@ -4647,7 +4451,10 @@ static enum insn_code
 can_float_p (enum machine_mode fltmode, enum machine_mode fixmode,
             int unsignedp)
 {
-  return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
+  convert_optab tab;
+
+  tab = unsignedp ? ufloat_optab : sfloat_optab;
+  return tab->handlers[fltmode][fixmode].insn_code;
 }
 \f
 /* Generate code to convert FROM to floating point
@@ -4820,12 +4627,12 @@ expand_float (rtx to, rtx from, int unsignedp)
       goto done;
     }
 
-  /* No hardware instruction available; call a library routine to convert from
-     SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode.  */
+  /* No hardware instruction available; call a library routine.  */
     {
-      rtx libfcn;
+      rtx libfunc;
       rtx insns;
       rtx value;
+      convert_optab tab = unsignedp ? ufloat_optab : sfloat_optab;
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -4836,56 +4643,13 @@ expand_float (rtx to, rtx from, int unsignedp)
       if (flag_force_mem)
        from = force_not_mem (from);
 
-      if (GET_MODE (to) == SFmode)
-       {
-         if (GET_MODE (from) == SImode)
-           libfcn = floatsisf_libfunc;
-         else if (GET_MODE (from) == DImode)
-           libfcn = floatdisf_libfunc;
-         else if (GET_MODE (from) == TImode)
-           libfcn = floattisf_libfunc;
-         else
-           abort ();
-       }
-      else if (GET_MODE (to) == DFmode)
-       {
-         if (GET_MODE (from) == SImode)
-           libfcn = floatsidf_libfunc;
-         else if (GET_MODE (from) == DImode)
-           libfcn = floatdidf_libfunc;
-         else if (GET_MODE (from) == TImode)
-           libfcn = floattidf_libfunc;
-         else
-           abort ();
-       }
-      else if (GET_MODE (to) == XFmode)
-       {
-         if (GET_MODE (from) == SImode)
-           libfcn = floatsixf_libfunc;
-         else if (GET_MODE (from) == DImode)
-           libfcn = floatdixf_libfunc;
-         else if (GET_MODE (from) == TImode)
-           libfcn = floattixf_libfunc;
-         else
-           abort ();
-       }
-      else if (GET_MODE (to) == TFmode)
-       {
-         if (GET_MODE (from) == SImode)
-           libfcn = floatsitf_libfunc;
-         else if (GET_MODE (from) == DImode)
-           libfcn = floatditf_libfunc;
-         else if (GET_MODE (from) == TImode)
-           libfcn = floattitf_libfunc;
-         else
-           abort ();
-       }
-      else
+      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+      if (!libfunc)
        abort ();
 
       start_sequence ();
 
-      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
                                       GET_MODE (to), 1, from,
                                       GET_MODE (from));
       insns = get_insns ();
@@ -4926,7 +4690,6 @@ expand_fix (rtx to, rtx from, int unsignedp)
   rtx target = to;
   enum machine_mode fmode, imode;
   int must_trunc = 0;
-  rtx libfcn = 0;
 
   /* We first try to find a pair of modes, one real and one integer, at
      least as wide as FROM and TO, respectively, in which we can open-code
@@ -5067,57 +4830,16 @@ expand_fix (rtx to, rtx from, int unsignedp)
 
       expand_fix (target, from, unsignedp);
     }
-  else if (GET_MODE (from) == SFmode)
-    {
-      if (GET_MODE (to) == SImode)
-       libfcn = unsignedp ? fixunssfsi_libfunc : fixsfsi_libfunc;
-      else if (GET_MODE (to) == DImode)
-       libfcn = unsignedp ? fixunssfdi_libfunc : fixsfdi_libfunc;
-      else if (GET_MODE (to) == TImode)
-       libfcn = unsignedp ? fixunssfti_libfunc : fixsfti_libfunc;
-      else
-       abort ();
-    }
-  else if (GET_MODE (from) == DFmode)
-    {
-      if (GET_MODE (to) == SImode)
-       libfcn = unsignedp ? fixunsdfsi_libfunc : fixdfsi_libfunc;
-      else if (GET_MODE (to) == DImode)
-       libfcn = unsignedp ? fixunsdfdi_libfunc : fixdfdi_libfunc;
-      else if (GET_MODE (to) == TImode)
-       libfcn = unsignedp ? fixunsdfti_libfunc : fixdfti_libfunc;
-      else
-       abort ();
-    }
-  else if (GET_MODE (from) == XFmode)
-    {
-      if (GET_MODE (to) == SImode)
-       libfcn = unsignedp ? fixunsxfsi_libfunc : fixxfsi_libfunc;
-      else if (GET_MODE (to) == DImode)
-       libfcn = unsignedp ? fixunsxfdi_libfunc : fixxfdi_libfunc;
-      else if (GET_MODE (to) == TImode)
-       libfcn = unsignedp ? fixunsxfti_libfunc : fixxfti_libfunc;
-      else
-       abort ();
-    }
-  else if (GET_MODE (from) == TFmode)
-    {
-      if (GET_MODE (to) == SImode)
-       libfcn = unsignedp ? fixunstfsi_libfunc : fixtfsi_libfunc;
-      else if (GET_MODE (to) == DImode)
-       libfcn = unsignedp ? fixunstfdi_libfunc : fixtfdi_libfunc;
-      else if (GET_MODE (to) == TImode)
-       libfcn = unsignedp ? fixunstfti_libfunc : fixtfti_libfunc;
-      else
-       abort ();
-    }
   else
-    abort ();
-
-  if (libfcn)
     {
       rtx insns;
       rtx value;
+      rtx libfunc;
+      
+      convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
+      libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
+      if (!libfunc)
+       abort ();
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -5127,7 +4849,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
 
       start_sequence ();
 
-      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+      value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
                                       GET_MODE (to), 1, from,
                                       GET_MODE (from));
       insns = get_insns ();
@@ -5162,7 +4884,7 @@ static optab
 new_optab (void)
 {
   int i;
-  optab op = (optab) ggc_alloc (sizeof (struct optab));
+  optab op = ggc_alloc (sizeof (struct optab));
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       op->handlers[i].insn_code = CODE_FOR_nothing;
@@ -5172,6 +4894,20 @@ new_optab (void)
   return op;
 }
 
+static convert_optab
+new_convert_optab (void)
+{
+  int i, j;
+  convert_optab op = ggc_alloc (sizeof (struct convert_optab));
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    for (j = 0; j < NUM_MACHINE_MODES; j++)
+      {
+       op->handlers[i][j].insn_code = CODE_FOR_nothing;
+       op->handlers[i][j].libfunc = 0;
+      }
+  return op;
+}
+
 /* Same, but fill in its code as CODE, and write it into the
    code_to_optab table.  */
 static inline optab
@@ -5193,10 +4929,19 @@ init_optabv (enum rtx_code code)
   return op;
 }
 
+/* Conversion optabs never go in the code_to_optab table.  */
+static inline convert_optab
+init_convert_optab (enum rtx_code code)
+{
+  convert_optab op = new_convert_optab ();
+  op->code = code;
+  return op;
+}
+
 /* Initialize the libfunc fields of an entire group of entries in some
    optab.  Each entry is set equal to a string consisting of a leading
    pair of underscores followed by a generic operation name followed by
-   a mode name (downshifted to lower case) followed by a single character
+   a mode name (downshifted to lowercase) followed by a single character
    representing the number of operands for the given operation (which is
    usually one of the characters '2', '3', or '4').
 
@@ -5265,20 +5010,122 @@ init_integral_libfuncs (optab optable, const char *opname, int suffix)
 static void
 init_floating_libfuncs (optab optable, const char *opname, int suffix)
 {
-  enum machine_mode fmode, dmode, lmode;
-
-  fmode = float_type_node ? TYPE_MODE (float_type_node) : VOIDmode;
-  dmode = double_type_node ? TYPE_MODE (double_type_node) : VOIDmode;
-  lmode = long_double_type_node ? TYPE_MODE (long_double_type_node) : VOIDmode;
-
-  if (fmode != VOIDmode)
-    init_libfuncs (optable, fmode, fmode, opname, suffix);
-  if (dmode != fmode && dmode != VOIDmode)
-    init_libfuncs (optable, dmode, dmode, opname, suffix);
-  if (lmode != dmode && lmode != VOIDmode)
-    init_libfuncs (optable, lmode, lmode, opname, suffix);
+  init_libfuncs (optable, MIN_MODE_FLOAT, MAX_MODE_FLOAT, opname, suffix);
 }
 
+/* Initialize the libfunc fields of an entire group of entries of an
+   inter-mode-class conversion optab.  The string formation rules are
+   similar to the ones for init_libfuncs, above, but instead of having
+   a mode name and an operand count these functions have two mode names
+   and no operand count.  */
+static void
+init_interclass_conv_libfuncs (convert_optab tab, const char *opname,
+                              enum mode_class from_class,
+                              enum mode_class to_class)
+{
+  enum machine_mode first_from_mode = GET_CLASS_NARROWEST_MODE (from_class);
+  enum machine_mode first_to_mode = GET_CLASS_NARROWEST_MODE (to_class);
+  size_t opname_len = strlen (opname);
+  size_t max_mname_len = 0;
+
+  enum machine_mode fmode, tmode;
+  const char *fname, *tname;
+  const char *q;
+  char *libfunc_name, *suffix;
+  char *p;
+
+  for (fmode = first_from_mode;
+       fmode != VOIDmode;
+       fmode = GET_MODE_WIDER_MODE (fmode))
+    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (fmode)));
+
+  for (tmode = first_to_mode;
+       tmode != VOIDmode;
+       tmode = GET_MODE_WIDER_MODE (tmode))
+    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (tmode)));
+
+  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+  libfunc_name[0] = '_';
+  libfunc_name[1] = '_';
+  memcpy (&libfunc_name[2], opname, opname_len);
+  suffix = libfunc_name + opname_len + 2;
+
+  for (fmode = first_from_mode; fmode != VOIDmode;
+       fmode = GET_MODE_WIDER_MODE (fmode))
+    for (tmode = first_to_mode; tmode != VOIDmode;
+        tmode = GET_MODE_WIDER_MODE (tmode))
+      {
+       fname = GET_MODE_NAME (fmode);
+       tname = GET_MODE_NAME (tmode);
+
+       p = suffix;
+       for (q = fname; *q; p++, q++)
+         *p = TOLOWER (*q);
+       for (q = tname; *q; p++, q++)
+         *p = TOLOWER (*q);
+
+       *p = '\0';
+
+       tab->handlers[tmode][fmode].libfunc
+         = init_one_libfunc (ggc_alloc_string (libfunc_name,
+                                               p - libfunc_name));
+      }
+}
+
+/* Initialize the libfunc fields of an entire group of entries of an
+   intra-mode-class conversion optab.  The string formation rules are
+   similar to the ones for init_libfunc, above.  WIDENING says whether
+   the optab goes from narrow to wide modes or vice versa.  These functions
+   have two mode names _and_ an operand count.  */
+static void
+init_intraclass_conv_libfuncs (convert_optab tab, const char *opname,
+                              enum mode_class class, bool widening)
+{
+  enum machine_mode first_mode = GET_CLASS_NARROWEST_MODE (class);
+  size_t opname_len = strlen (opname);
+  size_t max_mname_len = 0;
+
+  enum machine_mode nmode, wmode;
+  const char *nname, *wname;
+  const char *q;
+  char *libfunc_name, *suffix;
+  char *p;
+
+  for (nmode = first_mode; nmode != VOIDmode;
+       nmode = GET_MODE_WIDER_MODE (nmode))
+    max_mname_len = MAX (max_mname_len, strlen (GET_MODE_NAME (nmode)));
+
+  libfunc_name = alloca (2 + opname_len + 2*max_mname_len + 1 + 1);
+  libfunc_name[0] = '_';
+  libfunc_name[1] = '_';
+  memcpy (&libfunc_name[2], opname, opname_len);
+  suffix = libfunc_name + opname_len + 2;
+
+  for (nmode = first_mode; nmode != VOIDmode;
+       nmode = GET_MODE_WIDER_MODE (nmode))
+    for (wmode = GET_MODE_WIDER_MODE (nmode); wmode != VOIDmode;
+        wmode = GET_MODE_WIDER_MODE (wmode))
+      {
+       nname = GET_MODE_NAME (nmode);
+       wname = GET_MODE_NAME (wmode);
+
+       p = suffix;
+       for (q = widening ? nname : wname; *q; p++, q++)
+         *p = TOLOWER (*q);
+       for (q = widening ? wname : nname; *q; p++, q++)
+         *p = TOLOWER (*q);
+
+       *p++ = '2';
+       *p = '\0';
+
+       tab->handlers[widening ? wmode : nmode]
+                    [widening ? nmode : wmode].libfunc
+         = init_one_libfunc (ggc_alloc_string (libfunc_name,
+                                               p - libfunc_name));
+      }
+}
+
+
 rtx
 init_one_libfunc (const char *name)
 {
@@ -5303,36 +5150,40 @@ init_one_libfunc (const char *name)
   return symbol;
 }
 
+/* Call this to reset the function entry for one optab (OPTABLE) in mode
+   MODE to NAME, which should be either 0 or a string constant.  */
+void
+set_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
+{
+  if (name)
+    optable->handlers[mode].libfunc = init_one_libfunc (name);
+  else
+    optable->handlers[mode].libfunc = 0;
+}
+
+/* Call this to reset the function entry for one conversion optab
+   (OPTABLE) from mode FMODE to mode TMODE to NAME, which should be
+   either 0 or a string constant.  */
+void
+set_conv_libfunc (convert_optab optable, enum machine_mode tmode,
+                 enum machine_mode fmode, const char *name)
+{
+  if (name)
+    optable->handlers[tmode][fmode].libfunc = init_one_libfunc (name);
+  else
+    optable->handlers[tmode][fmode].libfunc = 0;
+}
+
 /* Call this once to initialize the contents of the optabs
    appropriately for the current target machine.  */
 
 void
 init_optabs (void)
 {
-  unsigned int i, j, k;
+  unsigned int i;
 
   /* Start by initializing all tables to contain CODE_FOR_nothing.  */
 
-  for (i = 0; i < ARRAY_SIZE (fixtab); i++)
-    for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
-      for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
-       fixtab[i][j][k] = CODE_FOR_nothing;
-
-  for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
-    for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
-      for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
-       fixtrunctab[i][j][k] = CODE_FOR_nothing;
-
-  for (i = 0; i < ARRAY_SIZE (floattab); i++)
-    for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
-      for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
-       floattab[i][j][k] = CODE_FOR_nothing;
-
-  for (i = 0; i < ARRAY_SIZE (extendtab); i++)
-    for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
-      for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
-       extendtab[i][j][k] = CODE_FOR_nothing;
-
   for (i = 0; i < NUM_RTX_CODE; i++)
     setcc_gen_code[i] = CODE_FOR_nothing;
 
@@ -5382,6 +5233,15 @@ init_optabs (void)
 
   ucmp_optab = init_optab (UNKNOWN);
   tst_optab = init_optab (UNKNOWN);
+
+  eq_optab = init_optab (EQ);
+  ne_optab = init_optab (NE);
+  gt_optab = init_optab (GT);
+  ge_optab = init_optab (GE);
+  lt_optab = init_optab (LT);
+  le_optab = init_optab (LE);
+  unord_optab = init_optab (UNORDERED);
+
   neg_optab = init_optab (NEG);
   negv_optab = init_optabv (NEG);
   abs_optab = init_optab (ABS);
@@ -5397,7 +5257,7 @@ init_optabs (void)
   floor_optab = init_optab (UNKNOWN);
   ceil_optab = init_optab (UNKNOWN);
   round_optab = init_optab (UNKNOWN);
-  trunc_optab = init_optab (UNKNOWN);
+  btrunc_optab = init_optab (UNKNOWN);
   nearbyint_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
@@ -5411,10 +5271,26 @@ init_optabs (void)
   cstore_optab = init_optab (UNKNOWN);
   push_optab = init_optab (UNKNOWN);
 
+  vec_extract_optab = init_optab (UNKNOWN);
+  vec_set_optab = init_optab (UNKNOWN);
+  vec_init_optab = init_optab (UNKNOWN);
+  /* Conversions.  */
+  sext_optab = init_convert_optab (SIGN_EXTEND);
+  zext_optab = init_convert_optab (ZERO_EXTEND);
+  trunc_optab = init_convert_optab (TRUNCATE);
+  sfix_optab = init_convert_optab (FIX);
+  ufix_optab = init_convert_optab (UNSIGNED_FIX);
+  sfixtrunc_optab = init_convert_optab (UNKNOWN);
+  ufixtrunc_optab = init_convert_optab (UNKNOWN);
+  sfloat_optab = init_convert_optab (FLOAT);
+  ufloat_optab = init_convert_optab (UNSIGNED_FLOAT);
+
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       movstr_optab[i] = CODE_FOR_nothing;
       clrstr_optab[i] = CODE_FOR_nothing;
+      cmpstr_optab[i] = CODE_FOR_nothing;
+      cmpmem_optab[i] = CODE_FOR_nothing;
 
 #ifdef HAVE_SECONDARY_RELOADS
       reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
@@ -5424,14 +5300,6 @@ init_optabs (void)
   /* Fill in the optabs with the insns we support.  */
   init_all_optabs ();
 
-#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
-  /* This flag says the same insns that convert to a signed fixnum
-     also convert validly to an unsigned one.  */
-  for (i = 0; i < NUM_MACHINE_MODES; i++)
-    for (j = 0; j < NUM_MACHINE_MODES; j++)
-      fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
-#endif
-
   /* Initialize the optabs with the names of the library functions.  */
   init_integral_libfuncs (add_optab, "add", '3');
   init_floating_libfuncs (add_optab, "add", '3');
@@ -5482,72 +5350,34 @@ init_optabs (void)
   init_integral_libfuncs (ucmp_optab, "ucmp", '2');
   init_floating_libfuncs (cmp_optab, "cmp", '2');
 
-#ifdef MULSI3_LIBCALL
-  smul_optab->handlers[(int) SImode].libfunc
-    = init_one_libfunc (MULSI3_LIBCALL);
-#endif
-#ifdef MULDI3_LIBCALL
-  smul_optab->handlers[(int) DImode].libfunc
-    = init_one_libfunc (MULDI3_LIBCALL);
-#endif
-
-#ifdef DIVSI3_LIBCALL
-  sdiv_optab->handlers[(int) SImode].libfunc
-    = init_one_libfunc (DIVSI3_LIBCALL);
-#endif
-#ifdef DIVDI3_LIBCALL
-  sdiv_optab->handlers[(int) DImode].libfunc
-    = init_one_libfunc (DIVDI3_LIBCALL);
-#endif
-
-#ifdef UDIVSI3_LIBCALL
-  udiv_optab->handlers[(int) SImode].libfunc
-    = init_one_libfunc (UDIVSI3_LIBCALL);
-#endif
-#ifdef UDIVDI3_LIBCALL
-  udiv_optab->handlers[(int) DImode].libfunc
-    = init_one_libfunc (UDIVDI3_LIBCALL);
-#endif
-
-#ifdef MODSI3_LIBCALL
-  smod_optab->handlers[(int) SImode].libfunc
-    = init_one_libfunc (MODSI3_LIBCALL);
-#endif
-#ifdef MODDI3_LIBCALL
-  smod_optab->handlers[(int) DImode].libfunc
-    = init_one_libfunc (MODDI3_LIBCALL);
-#endif
-
-#ifdef UMODSI3_LIBCALL
-  umod_optab->handlers[(int) SImode].libfunc
-    = init_one_libfunc (UMODSI3_LIBCALL);
-#endif
-#ifdef UMODDI3_LIBCALL
-  umod_optab->handlers[(int) DImode].libfunc
-    = init_one_libfunc (UMODDI3_LIBCALL);
-#endif
-
-  /* Use cabs for DC complex abs, since systems generally have cabs.
-     Don't define any libcall for SCmode, so that cabs will be used.  */
-  abs_optab->handlers[(int) DCmode].libfunc
-    = init_one_libfunc ("cabs");
+  /* EQ etc are floating point only.  */
+  init_floating_libfuncs (eq_optab, "eq", '2');
+  init_floating_libfuncs (ne_optab, "ne", '2');
+  init_floating_libfuncs (gt_optab, "gt", '2');
+  init_floating_libfuncs (ge_optab, "ge", '2');
+  init_floating_libfuncs (lt_optab, "lt", '2');
+  init_floating_libfuncs (le_optab, "le", '2');
+  init_floating_libfuncs (unord_optab, "unord", '2');
+
+  /* Conversions.  */
+  init_interclass_conv_libfuncs (sfloat_optab, "float", MODE_INT, MODE_FLOAT);
+  init_interclass_conv_libfuncs (sfix_optab, "fix",     MODE_FLOAT, MODE_INT);
+  init_interclass_conv_libfuncs (ufix_optab, "fixuns",  MODE_FLOAT, MODE_INT);
+
+  /* sext_optab is also used for FLOAT_EXTEND.  */
+  init_intraclass_conv_libfuncs (sext_optab, "extend", MODE_FLOAT, true);
+  init_intraclass_conv_libfuncs (trunc_optab, "trunc", MODE_FLOAT, false);
+
+  /* Use cabs for double complex abs, since systems generally have cabs.
+     Don't define any libcall for float complex, so that cabs will be used.  */
+  if (complex_double_type_node)
+    abs_optab->handlers[TYPE_MODE (complex_double_type_node)].libfunc
+      = init_one_libfunc ("cabs");
 
   /* The ffs function operates on `int'.  */
   ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
     = init_one_libfunc ("ffs");
 
-  extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
-  extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
-  extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
-  extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
-  extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
-
-  truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
-  truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
-  trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
-  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");
@@ -5572,94 +5402,6 @@ init_optabs (void)
   unwind_sjlj_unregister_libfunc
     = init_one_libfunc ("_Unwind_SjLj_Unregister");
 
-  eqhf2_libfunc = init_one_libfunc ("__eqhf2");
-  nehf2_libfunc = init_one_libfunc ("__nehf2");
-  gthf2_libfunc = init_one_libfunc ("__gthf2");
-  gehf2_libfunc = init_one_libfunc ("__gehf2");
-  lthf2_libfunc = init_one_libfunc ("__lthf2");
-  lehf2_libfunc = init_one_libfunc ("__lehf2");
-  unordhf2_libfunc = init_one_libfunc ("__unordhf2");
-
-  eqsf2_libfunc = init_one_libfunc ("__eqsf2");
-  nesf2_libfunc = init_one_libfunc ("__nesf2");
-  gtsf2_libfunc = init_one_libfunc ("__gtsf2");
-  gesf2_libfunc = init_one_libfunc ("__gesf2");
-  ltsf2_libfunc = init_one_libfunc ("__ltsf2");
-  lesf2_libfunc = init_one_libfunc ("__lesf2");
-  unordsf2_libfunc = init_one_libfunc ("__unordsf2");
-
-  eqdf2_libfunc = init_one_libfunc ("__eqdf2");
-  nedf2_libfunc = init_one_libfunc ("__nedf2");
-  gtdf2_libfunc = init_one_libfunc ("__gtdf2");
-  gedf2_libfunc = init_one_libfunc ("__gedf2");
-  ltdf2_libfunc = init_one_libfunc ("__ltdf2");
-  ledf2_libfunc = init_one_libfunc ("__ledf2");
-  unorddf2_libfunc = init_one_libfunc ("__unorddf2");
-
-  eqxf2_libfunc = init_one_libfunc ("__eqxf2");
-  nexf2_libfunc = init_one_libfunc ("__nexf2");
-  gtxf2_libfunc = init_one_libfunc ("__gtxf2");
-  gexf2_libfunc = init_one_libfunc ("__gexf2");
-  ltxf2_libfunc = init_one_libfunc ("__ltxf2");
-  lexf2_libfunc = init_one_libfunc ("__lexf2");
-  unordxf2_libfunc = init_one_libfunc ("__unordxf2");
-
-  eqtf2_libfunc = init_one_libfunc ("__eqtf2");
-  netf2_libfunc = init_one_libfunc ("__netf2");
-  gttf2_libfunc = init_one_libfunc ("__gttf2");
-  getf2_libfunc = init_one_libfunc ("__getf2");
-  lttf2_libfunc = init_one_libfunc ("__lttf2");
-  letf2_libfunc = init_one_libfunc ("__letf2");
-  unordtf2_libfunc = init_one_libfunc ("__unordtf2");
-
-  floatsisf_libfunc = init_one_libfunc ("__floatsisf");
-  floatdisf_libfunc = init_one_libfunc ("__floatdisf");
-  floattisf_libfunc = init_one_libfunc ("__floattisf");
-
-  floatsidf_libfunc = init_one_libfunc ("__floatsidf");
-  floatdidf_libfunc = init_one_libfunc ("__floatdidf");
-  floattidf_libfunc = init_one_libfunc ("__floattidf");
-
-  floatsixf_libfunc = init_one_libfunc ("__floatsixf");
-  floatdixf_libfunc = init_one_libfunc ("__floatdixf");
-  floattixf_libfunc = init_one_libfunc ("__floattixf");
-
-  floatsitf_libfunc = init_one_libfunc ("__floatsitf");
-  floatditf_libfunc = init_one_libfunc ("__floatditf");
-  floattitf_libfunc = init_one_libfunc ("__floattitf");
-
-  fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
-  fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
-  fixsfti_libfunc = init_one_libfunc ("__fixsfti");
-
-  fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
-  fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
-  fixdfti_libfunc = init_one_libfunc ("__fixdfti");
-
-  fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
-  fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
-  fixxfti_libfunc = init_one_libfunc ("__fixxfti");
-
-  fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
-  fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
-  fixtfti_libfunc = init_one_libfunc ("__fixtfti");
-
-  fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
-  fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
-  fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
-
-  fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
-  fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
-  fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
-
-  fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
-  fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
-  fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
-
-  fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
-  fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
-  fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
-
   /* For function entry/exit instrumentation.  */
   profile_function_entry_libfunc
     = init_one_libfunc ("__cyg_profile_func_enter");
@@ -5672,10 +5414,8 @@ init_optabs (void)
   if (HAVE_conditional_trap)
     trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
 
-#ifdef INIT_TARGET_OPTABS
   /* Allow the target to add more libcalls or rename some, etc.  */
-  INIT_TARGET_OPTABS;
-#endif
+  targetm.init_libfuncs ();
 }
 \f
 /* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
@@ -5702,6 +5442,11 @@ gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
   start_sequence ();
   op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
   op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
+  if (!op1 || !op2)
+    {
+      end_sequence ();
+      return 0;
+    }
   emit_insn (GEN_FCN (icode) (op1, op2));
 
   PUT_CODE (trap_rtx, code);