OSDN Git Service

* gcc.c (default_compilers): Add missing initializers.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index b0953eb..5fe24b7 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.
 
@@ -58,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];
@@ -110,13 +105,18 @@ static void prepare_cmp_insn (rtx *, rtx *, enum rtx_code *, rtx,
 static enum insn_code can_fix_p (enum machine_mode, enum machine_mode, int,
                                 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 *,
@@ -153,8 +153,11 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
       || 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) != '<')
+  if (GET_RTX_CLASS (code) != RTX_COMM_ARITH
+      && GET_RTX_CLASS (code) != RTX_BIN_ARITH
+      && GET_RTX_CLASS (code) != RTX_COMM_COMPARE
+      && GET_RTX_CLASS (code) != RTX_COMPARE
+      && GET_RTX_CLASS (code) != RTX_UNARY)
     return 1;
 
   if (GET_CODE (target) == ZERO_EXTRACT)
@@ -190,7 +193,7 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
        }
     }
 
-  if (GET_RTX_CLASS (code) == '1')
+  if (GET_RTX_CLASS (code) == RTX_UNARY)
     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));
@@ -718,7 +721,7 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
      try to make the first operand a register.
      Even better, try to make it the same as the target.
      Also try to make the last operand a constant.  */
-  if (GET_RTX_CLASS (binoptab->code) == 'c'
+  if (GET_RTX_CLASS (binoptab->code) == RTX_COMM_ARITH
       || binoptab == smul_widen_optab
       || binoptab == umul_widen_optab
       || binoptab == smul_highpart_optab
@@ -1084,8 +1087,12 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       int shift_count, left_shift, outof_word;
 
       /* If TARGET is the same as one of the operands, the REG_EQUAL note
-        won't be accurate, so use a new target.  */
-      if (target == 0 || target == op0 || target == op1)
+        won't be accurate, so use a new target. Do this also if target is not
+        a REG, first because having a register instead may open optimization
+        oportunities, and second because if target and op0 happen to be MEMs
+        designating the same location, we would risk clobbering it too early
+        in the code sequence we generate below.  */
+      if (target == 0 || target == op0 || target == op1 || ! REG_P (target))
        target = gen_reg_rtx (mode);
 
       start_sequence ();
@@ -1520,24 +1527,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);
@@ -1557,6 +1557,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:
@@ -1748,16 +1752,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;
        }
     }
 
@@ -2149,6 +2147,109 @@ sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
   return 0;
 }
 \f
+/* Generate code to perform an operation specified by UNOPPTAB
+   on operand OP0, with two results to TARG0 and TARG1.
+   We assume that the order of the operands for the instruction
+   is TARG0, TARG1, OP0.
+
+   Either TARG0 or TARG1 may be zero, but what that means is that
+   the result is not actually wanted.  We will generate it into
+   a dummy pseudo-reg and discard it.  They may not both be zero.
+
+   Returns 1 if this operation can be performed; 0 if not.  */
+
+int
+expand_twoval_unop (optab unoptab, rtx targ0, rtx targ1, rtx op0,
+                   int unsignedp)
+{
+  enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
+  enum mode_class class;
+  enum machine_mode wider_mode;
+  rtx entry_last = get_last_insn ();
+  rtx last;
+
+  class = GET_MODE_CLASS (mode);
+
+  op0 = protect_from_queue (op0, 0);
+
+  if (flag_force_mem)
+    {
+      op0 = force_not_mem (op0);
+    }
+
+  if (targ0)
+    targ0 = protect_from_queue (targ0, 1);
+  else
+    targ0 = gen_reg_rtx (mode);
+  if (targ1)
+    targ1 = protect_from_queue (targ1, 1);
+  else
+    targ1 = gen_reg_rtx (mode);
+
+  /* Record where to go back to if we fail.  */
+  last = get_last_insn ();
+
+  if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      int icode = (int) unoptab->handlers[(int) mode].insn_code;
+      enum machine_mode mode0 = insn_data[icode].operand[2].mode;
+      rtx pat;
+      rtx xop0 = op0;
+
+      if (GET_MODE (xop0) != VOIDmode
+         && GET_MODE (xop0) != mode0)
+       xop0 = convert_to_mode (mode0, xop0, unsignedp);
+
+      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
+      if (! (*insn_data[icode].operand[2].predicate) (xop0, mode0))
+       xop0 = copy_to_mode_reg (mode0, xop0);
+
+      /* We could handle this, but we should always be called with a pseudo
+        for our targets and all insns should take them as outputs.  */
+      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+         || ! (*insn_data[icode].operand[1].predicate) (targ1, mode))
+       abort ();
+
+      pat = GEN_FCN (icode) (targ0, targ1, xop0);
+      if (pat)
+       {
+         emit_insn (pat);
+         return 1;
+       }
+      else
+       delete_insns_since (last);
+    }
+
+  /* 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)
+    {
+      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+       {
+         if (unoptab->handlers[(int) wider_mode].insn_code
+             != CODE_FOR_nothing)
+           {
+             rtx t0 = gen_reg_rtx (wider_mode);
+             rtx t1 = gen_reg_rtx (wider_mode);
+             rtx cop0 = convert_modes (wider_mode, mode, op0, unsignedp);
+
+             if (expand_twoval_unop (unoptab, t0, t1, cop0, unsignedp))
+               {
+                 convert_move (targ0, t0, unsignedp);
+                 convert_move (targ1, t1, unsignedp);
+                 return 1;
+               }
+             else
+               delete_insns_since (last);
+           }
+       }
+    }
+
+  delete_insns_since (entry_last);
+  return 0;
+}
+\f
 /* Generate code to perform an operation specified by BINOPTAB
    on operands OP0 and OP1, with two results to TARG1 and TARG2.
    We assume that the order of the operands for the instruction
@@ -2366,7 +2467,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);
@@ -2614,7 +2715,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);
         }
     }
@@ -2789,7 +2899,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);
        }
     }
@@ -3327,9 +3446,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));
        }
 
@@ -3570,111 +3689,87 @@ 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_cmpmemqi
-      if (HAVE_cmpmemqi
-         && GET_CODE (size) == CONST_INT
-         && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpmemqi].operand[0].mode;
-         result = gen_reg_rtx (result_mode);
-         emit_insn (gen_cmpmemqi (result, x, y, size, opalign));
-       }
-      else
-#endif
-#ifdef HAVE_cmpmemhi
-      if (HAVE_cmpmemhi
-         && GET_CODE (size) == CONST_INT
-         && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpmemhi].operand[0].mode;
-         result = gen_reg_rtx (result_mode);
-         emit_insn (gen_cmpmemhi (result, x, y, size, opalign));
-       }
-      else
-#endif
-#ifdef HAVE_cmpmemsi
-      if (HAVE_cmpmemsi)
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpmemsi].operand[0].mode;
-         result = gen_reg_rtx (result_mode);
-         size = protect_from_queue (size, 0);
-         emit_insn (gen_cmpmemsi (result, x, y,
-                                  convert_to_mode (SImode, size, 1),
-                                  opalign));
-       }
-      else
-#endif
-#ifdef HAVE_cmpstrqi
-      if (HAVE_cmpstrqi
-         && GET_CODE (size) == CONST_INT
-         && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
+      /* 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_cmpstrqi].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);
-         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)
-       {
-         result_mode = insn_data[(int) CODE_FOR_cmpstrsi].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,
+                             TYPE_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;
       return;
     }
 
+  /* Don't allow operands to the compare to trap, as that can put the
+     compare and branch in different basic blocks.  */
+  if (flag_non_call_exceptions)
+    {
+      if (may_trap_p (x))
+       x = force_reg (mode, x);
+      if (may_trap_p (y))
+       y = force_reg (mode, y);
+    }
+
   *px = x;
   *py = y;
   if (can_compare_p (*pcomparison, mode, purpose))
@@ -3904,70 +3999,62 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
       y = convert_to_mode (mode, y, 0);
     }
 
-  /* If we're optimizing 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 (optimize
-      && ! side_effects_p (x)
-      && ! side_effects_p (y))
+  /* 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)
     {
-      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
+      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
+    {
+      equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
+      if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
        {
-         equiv = simplify_gen_relational (comparison, word_mode, mode, x, y);
-         if (! FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
-           {
-             rtx true_rtx, false_rtx;
-
-             switch (comparison)
-               {
-               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;
+         rtx true_rtx, false_rtx;
 
-               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);
+         switch (comparison)
+           {
+           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);
        }
     }
-  else
-    equiv = NULL_RTX;
 
   start_sequence ();
   value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
@@ -4421,12 +4508,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)
@@ -4436,7 +4525,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
@@ -4452,16 +4542,30 @@ 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)
+  /* FIXME: This requires a port to define both FIX and FTRUNC pattern
+     for this to work. We need to rework the fix* and ftrunc* patterns
+     and documentation.  */
+  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;
 }
 
@@ -4469,7 +4573,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
@@ -4642,12 +4749,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);
@@ -4658,56 +4765,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 ();
@@ -4731,15 +4795,8 @@ expand_float (rtx to, rtx from, int unsignedp)
     }
 }
 \f
-/* expand_fix: generate code to convert FROM to fixed point
-   and store in TO.  FROM must be floating point.  */
-
-static rtx
-ftruncify (rtx x)
-{
-  rtx temp = gen_reg_rtx (GET_MODE (x));
-  return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
-}
+/* Generate code to convert FROM to fixed point and store in TO.  FROM
+   must be floating point.  */
 
 void
 expand_fix (rtx to, rtx from, int unsignedp)
@@ -4748,7 +4805,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
@@ -4775,7 +4831,11 @@ expand_fix (rtx to, rtx from, int unsignedp)
              from = convert_to_mode (fmode, from, 0);
 
            if (must_trunc)
-             from = ftruncify (from);
+             {
+               rtx temp = gen_reg_rtx (GET_MODE (from));
+               from = expand_unop (GET_MODE (from), ftrunc_optab, from,
+                                   temp, 0);
+             }
 
            if (imode != GET_MODE (to))
              target = gen_reg_rtx (imode);
@@ -4889,57 +4949,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);
@@ -4949,7 +4968,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 ();
@@ -4994,6 +5013,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
@@ -5015,10 +5048,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').
 
@@ -5087,20 +5129,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)
 {
@@ -5136,36 +5280,29 @@ set_optab_libfunc (optab optable, enum machine_mode mode, const char *name)
     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;
 
@@ -5239,12 +5376,17 @@ 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);
+  sincos_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
   exp_optab = init_optab (UNKNOWN);
+  exp10_optab = init_optab (UNKNOWN);
+  exp2_optab = init_optab (UNKNOWN);
   log_optab = init_optab (UNKNOWN);
+  log10_optab = init_optab (UNKNOWN);
+  log2_optab = init_optab (UNKNOWN);
   tan_optab = init_optab (UNKNOWN);
   atan_optab = init_optab (UNKNOWN);
   strlen_optab = init_optab (UNKNOWN);
@@ -5253,10 +5395,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;
@@ -5266,14 +5424,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');
@@ -5333,27 +5483,25 @@ init_optabs (void)
   init_floating_libfuncs (le_optab, "le", '2');
   init_floating_libfuncs (unord_optab, "unord", '2');
 
-  /* 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");
+  /* 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");
@@ -5378,54 +5526,6 @@ init_optabs (void)
   unwind_sjlj_unregister_libfunc
     = init_one_libfunc ("_Unwind_SjLj_Unregister");
 
-  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");