OSDN Git Service

* c-common.c (shadow_warning): Delete.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index d3568b2..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 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 
 /* Include insn-config.h before expr.h so that HAVE_conditional_move
@@ -40,6 +42,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "reload.h"
 #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
@@ -54,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];
@@ -85,46 +84,54 @@ enum insn_code setcc_gen_code[NUM_RTX_CODE];
 enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
 #endif
 
-static int add_equal_note      PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
-static rtx widen_operand       PARAMS ((rtx, enum machine_mode,
-                                      enum machine_mode, int, int));
-static int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
-                                          rtx, rtx, enum machine_mode,
-                                          int, enum optab_methods,
-                                          enum mode_class, optab));
-static int expand_cmplxdiv_wide PARAMS ((rtx, rtx, rtx, rtx,
-                                      rtx, rtx, enum machine_mode,
-                                      int, enum optab_methods,
-                                      enum mode_class, optab));
-static void prepare_cmp_insn PARAMS ((rtx *, rtx *, enum rtx_code *, rtx,
-                                     enum machine_mode *, int *,
-                                     enum can_compare_purpose));
-static enum insn_code can_fix_p        PARAMS ((enum machine_mode, enum machine_mode,
-                                      int, int *));
-static enum insn_code can_float_p PARAMS ((enum machine_mode,
-                                          enum machine_mode,
-                                          int));
-static rtx ftruncify   PARAMS ((rtx));
-static optab new_optab PARAMS ((void));
-static inline optab init_optab PARAMS ((enum rtx_code));
-static inline optab init_optabv        PARAMS ((enum rtx_code));
-static inline int complex_part_zero_p PARAMS ((rtx, enum mode_class,
-                                               enum machine_mode));
-static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
-static void init_integral_libfuncs PARAMS ((optab, const char *, int));
-static void init_floating_libfuncs PARAMS ((optab, const char *, int));
-#ifdef HAVE_conditional_trap
-static void init_traps PARAMS ((void));
+/* The insn generating function can not take an rtx_code argument.
+   TRAP_RTX is used as an rtx argument.  Its code is replaced with
+   the code to be used in the trap insn and all other fields are ignored.  */
+static GTY(()) rtx trap_rtx;
+
+static int add_equal_note (rtx, rtx, enum rtx_code, rtx, rtx);
+static rtx widen_operand (rtx, enum machine_mode, enum machine_mode, int,
+                         int);
+static int expand_cmplxdiv_straight (rtx, rtx, rtx, rtx, rtx, rtx,
+                                    enum machine_mode, int,
+                                    enum optab_methods, enum mode_class,
+                                    optab);
+static int expand_cmplxdiv_wide (rtx, rtx, rtx, rtx, rtx, rtx,
+                                enum machine_mode, int, enum optab_methods,
+                                enum mode_class, optab);
+static void prepare_cmp_insn (rtx *, rtx *, enum rtx_code *, rtx,
+                             enum machine_mode *, int *,
+                             enum can_compare_purpose);
+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 *,
+                                  enum machine_mode *, int *);
+static rtx expand_vector_binop (enum machine_mode, optab, rtx, rtx, rtx, int,
+                               enum optab_methods);
+static rtx expand_vector_unop (enum machine_mode, optab, rtx, rtx, int);
+static rtx widen_clz (enum machine_mode, rtx, rtx);
+static rtx expand_parity (enum machine_mode, rtx, rtx);
+
+#ifndef HAVE_conditional_trap
+#define HAVE_conditional_trap 0
+#define gen_conditional_trap(a,b) (abort (), NULL_RTX)
 #endif
-static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
-                                           enum rtx_code, int, rtx));
-static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
-                                        enum machine_mode *, int *));
-static rtx expand_vector_binop PARAMS ((enum machine_mode, optab,
-                                       rtx, rtx, rtx, int,
-                                       enum optab_methods));
-static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
-                                      int));
 \f
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -137,11 +144,7 @@ static rtx expand_vector_unop PARAMS ((enum machine_mode, optab, rtx, rtx,
    again, ensuring that TARGET is not one of the operands.  */
 
 static int
-add_equal_note (insns, target, code, op0, op1)
-     rtx insns;
-     rtx target;
-     enum rtx_code code;
-     rtx op0, op1;
+add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
 {
   rtx last_insn, insn, set;
   rtx note;
@@ -168,11 +171,9 @@ add_equal_note (insns, target, code, op0, op1)
     return 1;
 
   if (! rtx_equal_p (SET_DEST (set), target)
-      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside the
-        SUBREG.  */
+      /* For a STRICT_LOW_PART, the REG_NOTE applies to what is inside it.  */
       && (GET_CODE (SET_DEST (set)) != STRICT_LOW_PART
-         || ! rtx_equal_p (SUBREG_REG (XEXP (SET_DEST (set), 0)),
-                           target)))
+         || ! rtx_equal_p (XEXP (SET_DEST (set), 0), target)))
     return 1;
 
   /* If TARGET is in OP0 or OP1, check if anything in SEQ sets TARGET
@@ -202,16 +203,13 @@ add_equal_note (insns, target, code, op0, op1)
 \f
 /* Widen OP to MODE and return the rtx for the widened operand.  UNSIGNEDP
    says whether OP is signed or unsigned.  NO_EXTEND is nonzero if we need
-   not actually do a sign-extend or zero-extend, but can leave the 
+   not actually do a sign-extend or zero-extend, but can leave the
    higher-order bits of the result rtx undefined, for example, in the case
    of logical operations, but not right shifts.  */
 
 static rtx
-widen_operand (op, mode, oldmode, unsignedp, no_extend)
-     rtx op;
-     enum machine_mode mode, oldmode;
-     int unsignedp;
-     int no_extend;
+widen_operand (rtx op, enum machine_mode mode, enum machine_mode oldmode,
+              int unsignedp, int no_extend)
 {
   rtx result;
 
@@ -241,33 +239,13 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
   return result;
 }
 \f
-/* Test whether either the real or imaginary part of a complex floating
-   point number is 0.0, so that it can be ignored (when compiling
-   with -funsafe-math-optimizations). */
-
-static inline int
-complex_part_zero_p (part, class, submode)
-  rtx part;
-  enum mode_class class;
-  enum machine_mode submode;
-{
-  return part == 0 ||
-         (flag_unsafe_math_optimizations
-          && class == MODE_COMPLEX_FLOAT
-          && part == CONST0_RTX (submode));
-}
-
 /* Generate code to perform a straightforward complex divide.  */
 
 static int
-expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
-                         unsignedp, methods, class, binoptab)
-  rtx real0, real1, imag0, imag1, realr, imagr;
-  enum machine_mode submode;
-  int unsignedp;
-  enum optab_methods methods;
-  enum mode_class class;
-  optab binoptab;
+expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
+                         rtx realr, rtx imagr, enum machine_mode submode,
+                         int unsignedp, enum optab_methods methods,
+                         enum mode_class class, optab binoptab)
 {
   rtx divisor;
   rtx real_t, imag_t;
@@ -277,7 +255,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   optab this_sub_optab = sub_optab;
   optab this_neg_optab = neg_optab;
   optab this_mul_optab = smul_optab;
-             
+
   if (binoptab == sdivv_optab)
     {
       this_add_optab = addv_optab;
@@ -310,7 +288,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
   if (divisor == 0)
     return 0;
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       /* Mathematically, ((a)(c-id))/divisor.  */
       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
@@ -318,7 +296,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
       /* Calculate the dividend.  */
       real_t = expand_binop (submode, this_mul_optab, real0, real1,
                             NULL_RTX, unsignedp, methods);
-                 
+
       imag_t = expand_binop (submode, this_mul_optab, real0, imag1,
                             NULL_RTX, unsignedp, methods);
 
@@ -343,7 +321,7 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
 
       real_t = expand_binop (submode, this_add_optab, temp1, temp2,
                             NULL_RTX, unsignedp, methods);
-                 
+
       temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
                            NULL_RTX, unsignedp, methods);
 
@@ -392,14 +370,10 @@ expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
 /* Generate code to perform a wide-input-range-acceptable complex divide.  */
 
 static int
-expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
-                     unsignedp, methods, class, binoptab)
-  rtx real0, real1, imag0, imag1, realr, imagr;
-  enum machine_mode submode;
-  int unsignedp;
-  enum optab_methods methods;
-  enum mode_class class;
-  optab binoptab;
+expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1, rtx realr,
+                     rtx imagr, enum machine_mode submode, int unsignedp,
+                     enum optab_methods methods, enum mode_class class,
+                     optab binoptab)
 {
   rtx ratio, divisor;
   rtx real_t, imag_t;
@@ -418,7 +392,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
       this_neg_optab = negv_optab;
       this_mul_optab = smulv_optab;
     }
-             
+
   /* Don't fetch these from memory more than once.  */
   real0 = force_reg (submode, real0);
   real1 = force_reg (submode, real1);
@@ -476,7 +450,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       real_t = real0;
 
@@ -581,7 +555,7 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
 
   /* Calculate dividend.  */
 
-  if (complex_part_zero_p (imag0, class, submode))
+  if (imag0 == 0)
     {
       /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
 
@@ -656,15 +630,11 @@ expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
 rtx
-expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
-     enum machine_mode mode;
-     enum rtx_code code;
-     rtx op0, op1;
-     rtx target;
-     int unsignedp;
-     enum optab_methods methods;
+expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
+                    rtx op1, rtx target, int unsignedp,
+                    enum optab_methods methods)
 {
-  optab binop = code_to_optab [(int) code];
+  optab binop = code_to_optab[(int) code];
   if (binop == 0)
     abort ();
 
@@ -683,13 +653,8 @@ expand_simple_binop (mode, code, op0, op1, target, unsignedp, methods)
    this may or may not be TARGET.  */
 
 rtx
-expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
-     enum machine_mode mode;
-     optab binoptab;
-     rtx op0, op1;
-     rtx target;
-     int unsignedp;
-     enum optab_methods methods;
+expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
+             rtx target, int unsignedp, enum optab_methods methods)
 {
   enum optab_methods next_methods
     = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
@@ -698,7 +663,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
   enum machine_mode wider_mode;
   rtx temp;
   int commutative_op = 0;
-  int shift_op = (binoptab->code ==  ASHIFT
+  int shift_op = (binoptab->code == ASHIFT
                  || binoptab->code == ASHIFTRT
                  || binoptab->code == LSHIFTRT
                  || binoptab->code == ROTATE
@@ -715,8 +680,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
   if (flag_force_mem)
     {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
+      /* Load duplicate non-volatile operands once.  */
+      if (rtx_equal_p (op0, op1) && ! volatile_refs_p (op0))
+       {
+         op0 = force_not_mem (op0);
+         op1 = op0;
+       }
+      else
+       {
+         op0 = force_not_mem (op0);
+         op1 = force_not_mem (op1);
+       }
     }
 
   /* If subtracting an integer constant, convert this into an addition of
@@ -797,34 +771,23 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        }
 
       /* In case the insn wants input operands in modes different from
-        the result, convert the operands.  It would seem that we
-        don't need to convert CONST_INTs, but we do, so that they're
-        a properly sign-extended for their modes; we choose the
-        widest mode between mode and mode[01], so that, in a widening
-        operation, we call convert_modes with different FROM and TO
-        modes, which ensures the value is sign-extended.  Shift
-        operations are an exception, because the second operand needs
-        not be extended to the mode of the result.  */
-
-      if (GET_MODE (op0) != mode0
-         && mode0 != VOIDmode)
+        those of the actual operands, convert the operands.  It would
+        seem that we don't need to convert CONST_INTs, but we do, so
+        that they're properly zero-extended, sign-extended or truncated
+        for their mode.  */
+
+      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
        xop0 = convert_modes (mode0,
                              GET_MODE (op0) != VOIDmode
                              ? GET_MODE (op0)
-                             : GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode0)
-                             ? mode
-                             : mode0,
+                             : mode,
                              xop0, unsignedp);
 
-      if (GET_MODE (xop1) != mode1
-         && mode1 != VOIDmode)
+      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
        xop1 = convert_modes (mode1,
                              GET_MODE (op1) != VOIDmode
                              ? GET_MODE (op1)
-                             : (GET_MODE_SIZE (mode) > GET_MODE_SIZE (mode1)
-                                && ! shift_op)
-                             ? mode
-                             : mode1,
+                             : mode,
                              xop1, unsignedp);
 
       /* Now, if insn's predicates don't allow our operands, put them into
@@ -1087,7 +1050,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (inter != 0)
            inter = expand_binop (word_mode, binoptab, outof_input,
                                  op1, outof_target, unsignedp, next_methods);
-         
+
          if (inter != 0 && inter != outof_target)
            emit_move_insn (outof_target, inter);
        }
@@ -1166,7 +1129,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (shift_count > BITS_PER_WORD)
            {
              first_shift_count = GEN_INT (shift_count - BITS_PER_WORD);
-             second_shift_count = GEN_INT (2*BITS_PER_WORD - shift_count);
+             second_shift_count = GEN_INT (2 * BITS_PER_WORD - shift_count);
            }
          else
            {
@@ -1179,7 +1142,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                     NULL_RTX, unsignedp, next_methods);
          into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
                                     into_input, second_shift_count,
-                                    into_target, unsignedp, next_methods);
+                                    NULL_RTX, unsignedp, next_methods);
 
          if (into_temp1 != 0 && into_temp2 != 0)
            inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
@@ -1195,7 +1158,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                      NULL_RTX, unsignedp, next_methods);
          outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
                                      outof_input, second_shift_count,
-                                     outof_target, unsignedp, next_methods);
+                                     NULL_RTX, unsignedp, next_methods);
 
          if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
            inter = expand_binop (word_mode, ior_optab,
@@ -1237,7 +1200,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
     {
       unsigned int i;
       optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
-      int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+      const unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
       rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
       rtx xop0, xop1, xtarget;
 
@@ -1293,7 +1256,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (i > 0)
            {
              rtx newx;
-             
+
              /* Add/subtract previous carry to main result.  */
              newx = expand_binop (word_mode,
                                   normalizep == 1 ? binoptab : otheroptab,
@@ -1321,20 +1284,23 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
            }
 
          carry_in = carry_out;
-       }       
+       }
 
       if (i == GET_MODE_BITSIZE (mode) / (unsigned) BITS_PER_WORD)
        {
-         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+             || ! rtx_equal_p (target, xtarget))
            {
              rtx temp = emit_move_insn (target, xtarget);
 
              set_unique_reg_note (temp,
-                                  REG_EQUAL,
+                                  REG_EQUAL,
                                   gen_rtx_fmt_ee (binoptab->code, mode,
                                                   copy_rtx (xop0),
                                                   copy_rtx (xop1)));
            }
+         else
+           target = xtarget;
 
          return target;
        }
@@ -1346,7 +1312,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
   /* If we want to multiply two two-word values and have normal and widening
      multiplies of single-word values, we can do this with three smaller
      multiplications.  Note that we do not make a REG_NO_CONFLICT block here
-     because we are not operating on one word at a time. 
+     because we are not operating on one word at a time.
 
      The multiplication proceeds as follows:
                                 _______________________
@@ -1500,7 +1466,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
            emit_move_insn (product_high, temp);
 
          if (temp != 0)
-           temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 
+           temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
                                 NULL_RTX, 0, OPTAB_DIRECT);
 
          if (temp != 0)
@@ -1519,7 +1485,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                {
                  temp = emit_move_insn (product, product);
                  set_unique_reg_note (temp,
-                                      REG_EQUAL,
+                                      REG_EQUAL,
                                       gen_rtx_fmt_ee (MULT, mode,
                                                       copy_rtx (op0),
                                                       copy_rtx (op1)));
@@ -1555,27 +1521,17 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       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
-       = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-                        class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-                        0);
+      /* Find the correct mode for the real and imaginary parts.  */
+      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);
@@ -1595,6 +1551,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       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:
@@ -1609,11 +1569,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else if (res != realr)
            emit_move_insn (realr, res);
 
-         if (!complex_part_zero_p (imag0, class, submode)
-             && !complex_part_zero_p (imag1, class, submode))
+         if (imag0 != 0 && imag1 != 0)
            res = expand_binop (submode, binoptab, imag0, imag1,
                                imagr, unsignedp, methods);
-         else if (!complex_part_zero_p (imag0, class, submode))
+         else if (imag0 != 0)
            res = imag0;
          else if (binoptab->code == MINUS)
             res = expand_unop (submode,
@@ -1633,8 +1592,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        case MULT:
          /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
 
-         if (!complex_part_zero_p (imag0, class, submode)
-              && !complex_part_zero_p (imag1, class, submode))
+         if (imag0 != 0 && imag1 != 0)
            {
              rtx temp1, temp2;
 
@@ -1666,11 +1624,16 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              temp1 = expand_binop (submode, binoptab, real0, imag1,
                                    NULL_RTX, unsignedp, methods);
 
-             temp2 = expand_binop (submode, binoptab, real1, imag0,
-                                   NULL_RTX, unsignedp, methods);
+             /* Avoid expanding redundant multiplication for the common
+                case of squaring a complex number.  */
+             if (rtx_equal_p (real0, real1) && rtx_equal_p (imag0, imag1))
+               temp2 = temp1;
+             else
+               temp2 = expand_binop (submode, binoptab, real1, imag0,
+                                     NULL_RTX, unsignedp, methods);
 
              if (temp1 == 0 || temp2 == 0)
-                 break;
+               break;
 
              res = (expand_binop
                      (submode,
@@ -1697,7 +1660,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              else if (res != realr)
                emit_move_insn (realr, res);
 
-             if (!complex_part_zero_p (imag0, class, submode))
+             if (imag0 != 0)
                res = expand_binop (submode, binoptab,
                                    real1, imag0, imagr, unsignedp, methods);
              else
@@ -1715,8 +1678,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
        case DIV:
          /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
-         
-         if (complex_part_zero_p (imag1, class, submode))
+
+         if (imag1 == 0)
            {
              /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
 
@@ -1773,7 +1736,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                }
            }
          break;
-         
+
        default:
          abort ();
        }
@@ -1783,16 +1746,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       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;
        }
     }
 
@@ -1915,48 +1872,90 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 /* Like expand_binop, but for open-coding vectors binops.  */
 
 static rtx
-expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
-     enum machine_mode mode;
-     optab binoptab;
-     rtx op0, op1;
-     rtx target;
-     int unsignedp;
-     enum optab_methods methods;
+expand_vector_binop (enum machine_mode mode, optab binoptab, rtx op0,
+                    rtx op1, rtx target, int unsignedp,
+                    enum optab_methods methods)
 {
-  enum machine_mode submode;
-  int elts, subsize, i;
+  enum machine_mode submode, tmode;
+  int size, elts, subsize, subbitsize, i;
   rtx t, a, b, res, seq;
   enum mode_class class;
 
   class = GET_MODE_CLASS (mode);
 
+  size = GET_MODE_SIZE (mode);
   submode = GET_MODE_INNER (mode);
-  subsize = GET_MODE_UNIT_SIZE (mode);
-  elts = GET_MODE_NUNITS (mode);
-
-  if (!target)
-    target = gen_reg_rtx (mode);
 
-  start_sequence ();
-
-  /* FIXME: Optimally, we should try to do this in narrower vector
-     modes if available.  E.g. When trying V8SI, try V4SI, else
-     V2SI, else decay into SI.  */
+  /* Search for the widest vector mode with the same inner mode that is
+     still narrower than MODE and that allows to open-code this operator.
+     Note, if we find such a mode and the handler later decides it can't
+     do the expansion, we'll be called recursively with the narrower mode.  */
+  for (tmode = GET_CLASS_NARROWEST_MODE (class);
+       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
+       tmode = GET_MODE_WIDER_MODE (tmode))
+    {
+      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
+         && binoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
+       submode = tmode;
+    }
 
   switch (binoptab->code)
     {
+    case AND:
+    case IOR:
+    case XOR:
+      tmode = int_mode_for_mode (mode);
+      if (tmode != BLKmode)
+       submode = tmode;
     case PLUS:
     case MINUS:
     case MULT:
     case DIV:
+      subsize = GET_MODE_SIZE (submode);
+      subbitsize = GET_MODE_BITSIZE (submode);
+      elts = size / subsize;
+
+      /* If METHODS is OPTAB_DIRECT, we don't insist on the exact mode,
+        but that we operate on more than one element at a time.  */
+      if (subsize == GET_MODE_UNIT_SIZE (mode) && methods == OPTAB_DIRECT)
+       return 0;
+
+      start_sequence ();
+
+      /* Errors can leave us with a const0_rtx as operand.  */
+      if (GET_MODE (op0) != mode)
+       op0 = copy_to_mode_reg (mode, op0);
+      if (GET_MODE (op1) != mode)
+       op1 = copy_to_mode_reg (mode, op1);
+
+      if (!target)
+       target = gen_reg_rtx (mode);
+
       for (i = 0; i < elts; ++i)
        {
-         t = simplify_gen_subreg (submode, target, mode,
-                                  i * subsize);
-         a = simplify_gen_subreg (submode, op0, mode,
-                                  i * subsize);
-         b = simplify_gen_subreg (submode, op1, mode,
-                                  i * subsize);
+         /* If this is part of a register, and not the first item in the
+            word, we can't store using a SUBREG - that would clobber
+            previous results.
+            And storing with a SUBREG is only possible for the least
+            significant part, hence we can't do it for big endian
+            (unless we want to permute the evaluation order.  */
+         if (GET_CODE (target) == REG
+             && (BYTES_BIG_ENDIAN
+                 ? subsize < UNITS_PER_WORD
+                 : ((i * subsize) % UNITS_PER_WORD) != 0))
+           t = NULL_RTX;
+         else
+           t = simplify_gen_subreg (submode, target, mode, i * subsize);
+         if (CONSTANT_P (op0))
+           a = simplify_gen_subreg (submode, op0, mode, i * subsize);
+         else
+           a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
+                                  NULL_RTX, submode, submode, size);
+         if (CONSTANT_P (op1))
+           b = simplify_gen_subreg (submode, op1, mode, i * subsize);
+         else
+           b = extract_bit_field (op1, subbitsize, i * subbitsize, unsignedp,
+                                  NULL_RTX, submode, submode, size);
 
          if (binoptab->code == DIV)
            {
@@ -1974,7 +1973,11 @@ expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          if (res == 0)
            break;
 
-         emit_move_insn (t, res);
+         if (t)
+           emit_move_insn (t, res);
+         else
+           store_bit_field (target, subbitsize, i * subbitsize, submode, res,
+                            size);
        }
       break;
 
@@ -1992,38 +1995,89 @@ expand_vector_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 /* Like expand_unop but for open-coding vector unops.  */
 
 static rtx
-expand_vector_unop (mode, unoptab, op0, target, unsignedp)
-     enum machine_mode mode;
-     optab unoptab;
-     rtx op0;
-     rtx target;
-     int unsignedp;
+expand_vector_unop (enum machine_mode mode, optab unoptab, rtx op0,
+                   rtx target, int unsignedp)
 {
-  enum machine_mode submode;
-  int elts, subsize, i;
+  enum machine_mode submode, tmode;
+  int size, elts, subsize, subbitsize, i;
   rtx t, a, res, seq;
 
+  size = GET_MODE_SIZE (mode);
   submode = GET_MODE_INNER (mode);
-  subsize = GET_MODE_UNIT_SIZE (mode);
-  elts = GET_MODE_NUNITS (mode);
+
+  /* Search for the widest vector mode with the same inner mode that is
+     still narrower than MODE and that allows to open-code this operator.
+     Note, if we find such a mode and the handler later decides it can't
+     do the expansion, we'll be called recursively with the narrower mode.  */
+  for (tmode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (mode));
+       GET_MODE_SIZE (tmode) < GET_MODE_SIZE (mode);
+       tmode = GET_MODE_WIDER_MODE (tmode))
+    {
+      if (GET_MODE_INNER (tmode) == GET_MODE_INNER (mode)
+         && unoptab->handlers[(int) tmode].insn_code != CODE_FOR_nothing)
+       submode = tmode;
+    }
+  /* If there is no negate operation, try doing a subtract from zero.  */
+  if (unoptab == neg_optab && GET_MODE_CLASS (submode) == MODE_INT
+      /* Avoid infinite recursion when an
+        error has left us with the wrong mode.  */
+      && GET_MODE (op0) == mode)
+    {
+      rtx temp;
+      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
+                           target, unsignedp, OPTAB_DIRECT);
+      if (temp)
+       return temp;
+    }
+
+  if (unoptab == one_cmpl_optab)
+    {
+      tmode = int_mode_for_mode (mode);
+      if (tmode != BLKmode)
+       submode = tmode;
+    }
+
+  subsize = GET_MODE_SIZE (submode);
+  subbitsize = GET_MODE_BITSIZE (submode);
+  elts = size / subsize;
+
+  /* Errors can leave us with a const0_rtx as operand.  */
+  if (GET_MODE (op0) != mode)
+    op0 = copy_to_mode_reg (mode, op0);
 
   if (!target)
     target = gen_reg_rtx (mode);
 
   start_sequence ();
 
-  /* FIXME: Optimally, we should try to do this in narrower vector
-     modes if available.  E.g. When trying V8SI, try V4SI, else
-     V2SI, else decay into SI.  */
-
   for (i = 0; i < elts; ++i)
     {
-      t = simplify_gen_subreg (submode, target, mode, i * subsize);
-      a = simplify_gen_subreg (submode, op0, mode, i * subsize);
+      /* If this is part of a register, and not the first item in the
+        word, we can't store using a SUBREG - that would clobber
+        previous results.
+        And storing with a SUBREG is only possible for the least
+        significant part, hence we can't do it for big endian
+        (unless we want to permute the evaluation order.  */
+      if (GET_CODE (target) == REG
+         && (BYTES_BIG_ENDIAN
+             ?  subsize < UNITS_PER_WORD
+             : ((i * subsize) % UNITS_PER_WORD) != 0))
+       t = NULL_RTX;
+      else
+       t = simplify_gen_subreg (submode, target, mode, i * subsize);
+      if (CONSTANT_P (op0))
+       a = simplify_gen_subreg (submode, op0, mode, i * subsize);
+      else
+       a = extract_bit_field (op0, subbitsize, i * subbitsize, unsignedp,
+                              t, submode, submode, size);
 
       res = expand_unop (submode, unoptab, a, t, unsignedp);
 
-      emit_move_insn (t, res);
+      if (t)
+       emit_move_insn (t, res);
+      else
+       store_bit_field (target, subbitsize, i * subbitsize, submode, res,
+                        size);
     }
 
   seq = get_insns ();
@@ -2041,12 +2095,9 @@ expand_vector_unop (mode, unoptab, op0, target, unsignedp)
    of an unsigned wider operation, since the result would be the same.  */
 
 rtx
-sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
-    enum machine_mode mode;
-    optab uoptab, soptab;
-    rtx op0, op1, target;
-    int unsignedp;
-    enum optab_methods methods;
+sign_expand_binop (enum machine_mode mode, optab uoptab, optab soptab,
+                  rtx op0, rtx op1, rtx target, int unsignedp,
+                  enum optab_methods methods)
 {
   rtx temp;
   optab direct_optab = unsignedp ? uoptab : soptab;
@@ -2103,11 +2154,8 @@ sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
    Returns 1 if this operation can be performed; 0 if not.  */
 
 int
-expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
-     optab binoptab;
-     rtx op0, op1;
-     rtx targ0, targ1;
-     int unsignedp;
+expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
+                    int unsignedp)
 {
   enum machine_mode mode = GET_MODE (targ0 ? targ0 : targ1);
   enum mode_class class;
@@ -2156,13 +2204,25 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
       rtx pat;
       rtx xop0 = op0, xop1 = op1;
 
-      /* In case this insn wants input operands in modes different from the
-        result, convert the operands.  */
-      if (GET_MODE (op0) != VOIDmode && GET_MODE (op0) != mode0)
-       xop0 = convert_to_mode (mode0, xop0, unsignedp);
+      /* In case the insn wants input operands in modes different from
+        those of the actual operands, convert the operands.  It would
+        seem that we don't need to convert CONST_INTs, but we do, so
+        that they're properly zero-extended, sign-extended or truncated
+        for their mode.  */
+
+      if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
+       xop0 = convert_modes (mode0,
+                             GET_MODE (op0) != VOIDmode
+                             ? GET_MODE (op0)
+                             : mode,
+                             xop0, unsignedp);
 
-      if (GET_MODE (op1) != VOIDmode && GET_MODE (op1) != mode1)
-       xop1 = convert_to_mode (mode1, xop1, unsignedp);
+      if (GET_MODE (op1) != mode1 && mode1 != VOIDmode)
+       xop1 = convert_modes (mode1,
+                             GET_MODE (op1) != VOIDmode
+                             ? GET_MODE (op1)
+                             : mode,
+                             xop1, unsignedp);
 
       /* Now, if insn doesn't accept these operands, put them into pseudos.  */
       if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
@@ -2176,7 +2236,7 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
       if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
          || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
        abort ();
-       
+
       pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
       if (pat)
        {
@@ -2223,20 +2283,93 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
 rtx
-expand_simple_unop (mode, code, op0, target, unsignedp)
-     enum machine_mode mode;
-     enum rtx_code code;
-     rtx op0;
-     rtx target;
-     int unsignedp;
+expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
+                   rtx target, int unsignedp)
 {
-  optab unop = code_to_optab [(int) code];
+  optab unop = code_to_optab[(int) code];
   if (unop == 0)
     abort ();
 
   return expand_unop (mode, unop, op0, target, unsignedp);
 }
 
+/* Try calculating
+       (clz:narrow x)
+   as
+       (clz:wide (zero_extend:wide x)) - ((width wide) - (width narrow)).  */
+static rtx
+widen_clz (enum machine_mode mode, rtx op0, rtx target)
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+    {
+      enum machine_mode wider_mode;
+      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
+          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+       {
+         if (clz_optab->handlers[(int) wider_mode].insn_code
+             != CODE_FOR_nothing)
+           {
+             rtx xop0, temp, last;
+
+             last = get_last_insn ();
+
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             xop0 = widen_operand (op0, wider_mode, mode, true, false);
+             temp = expand_unop (wider_mode, clz_optab, xop0, NULL_RTX, true);
+             if (temp != 0)
+               temp = expand_binop (wider_mode, sub_optab, temp,
+                                    GEN_INT (GET_MODE_BITSIZE (wider_mode)
+                                             - GET_MODE_BITSIZE (mode)),
+                                    target, true, OPTAB_DIRECT);
+             if (temp == 0)
+               delete_insns_since (last);
+
+             return temp;
+           }
+       }
+    }
+  return 0;
+}
+
+/* Try calculating (parity x) as (and (popcount x) 1), where
+   popcount can also be done in a wider mode.  */
+static rtx
+expand_parity (enum machine_mode mode, rtx op0, rtx target)
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
+    {
+      enum machine_mode wider_mode;
+      for (wider_mode = mode; wider_mode != VOIDmode;
+          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
+       {
+         if (popcount_optab->handlers[(int) wider_mode].insn_code
+             != CODE_FOR_nothing)
+           {
+             rtx xop0, temp, last;
+
+             last = get_last_insn ();
+
+             if (target == 0)
+               target = gen_reg_rtx (mode);
+             xop0 = widen_operand (op0, wider_mode, mode, true, false);
+             temp = expand_unop (wider_mode, popcount_optab, xop0, NULL_RTX,
+                                 true);
+             if (temp != 0)
+               temp = expand_binop (wider_mode, and_optab, temp, const1_rtx,
+                                    target, true, OPTAB_DIRECT);
+             if (temp == 0)
+               delete_insns_since (last);
+
+             return temp;
+           }
+       }
+    }
+  return 0;
+}
+
 /* Generate code to perform an operation specified by UNOPTAB
    on operand OP0, with result having machine-mode MODE.
 
@@ -2249,12 +2382,8 @@ expand_simple_unop (mode, code, op0, target, unsignedp)
    this may or may not be TARGET.  */
 
 rtx
-expand_unop (mode, unoptab, op0, target, unsignedp)
-     enum machine_mode mode;
-     optab unoptab;
-     rtx op0;
-     rtx target;
-     int unsignedp;
+expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
+            int unsignedp)
 {
   enum mode_class class;
   enum machine_mode wider_mode;
@@ -2308,7 +2437,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
            }
 
          emit_insn (pat);
-         
+
          return temp;
        }
       else
@@ -2317,6 +2446,16 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
   /* It can't be done in this mode.  Can we open-code it in a wider mode?  */
 
+  /* Widening clz needs special treatment.  */
+  if (unoptab == clz_optab)
+    {
+      temp = widen_clz (mode, op0, target);
+      if (temp)
+       return temp;
+      else
+       goto try_libcall;
+    }
+
   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))
@@ -2333,7 +2472,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
                                  (unoptab == neg_optab
                                   || unoptab == one_cmpl_optab)
                                  && class == MODE_INT);
-             
+
            temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                unsignedp);
 
@@ -2397,18 +2536,15 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       rtx x;
       rtx seq;
 
-      /* Find the correct mode for the real and imaginary parts */
-      enum machine_mode submode
-       = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-                        class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-                        0);
+      /* Find the correct mode for the real and imaginary parts.  */
+      enum machine_mode submode = GET_MODE_INNER (mode);
 
       if (submode == BLKmode)
        abort ();
 
       if (target == 0)
        target = gen_reg_rtx (mode);
-      
+
       start_sequence ();
 
       target_piece = gen_imagpart (submode, target);
@@ -2434,22 +2570,90 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       return target;
     }
 
+  /* Try negating floating point values by flipping the sign bit.  */
+  if (unoptab->code == NEG && class == MODE_FLOAT
+      && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+    {
+      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;
+
+      if (imode != BLKmode && bitpos >= 0 && fmt->has_signed_zero)
+       {
+         HOST_WIDE_INT hi, lo;
+         rtx last = get_last_insn ();
+
+         /* Handle targets with different FP word orders.  */
+         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+           {
+             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+           }
+
+         if (bitpos < HOST_BITS_PER_WIDE_INT)
+           {
+             hi = 0;
+             lo = (HOST_WIDE_INT) 1 << bitpos;
+           }
+         else
+           {
+             hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+             lo = 0;
+           }
+         temp = expand_binop (imode, xor_optab,
+                              gen_lowpart (imode, op0),
+                              immed_double_const (lo, hi, imode),
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+         if (temp != 0)
+           {
+             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);
+        }
+    }
+
+  /* Try calculating parity (x) as popcount (x) % 2.  */
+  if (unoptab == parity_optab)
+    {
+      temp = expand_parity (mode, op0, target);
+      if (temp)
+       return temp;
+    }
+
+ try_libcall:
   /* Now try a library call in this mode.  */
   if (unoptab->handlers[(int) mode].libfunc)
     {
       rtx insns;
       rtx value;
+      enum machine_mode outmode = mode;
+
+      /* All of these functions return small values.  Thus we choose to
+        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
+           = GET_MODE (hard_libcall_value (TYPE_MODE (integer_type_node)));
 
       start_sequence ();
 
       /* Pass 1 for NO_QUEUE so we don't lose any increments
         if the libcall is cse'd or moved.  */
       value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
-                                      NULL_RTX, LCT_CONST, mode, 1, op0, mode);
+                                      NULL_RTX, LCT_CONST, outmode,
+                                      1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
-      target = gen_reg_rtx (mode);
+      target = gen_reg_rtx (outmode);
       emit_libcall_block (insns, target, value,
                          gen_rtx_fmt_e (unoptab->code, mode, op0));
 
@@ -2480,10 +2684,18 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
                                    (unoptab == neg_optab
                                     || unoptab == one_cmpl_optab)
                                    && class == MODE_INT);
-             
+
              temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                  unsignedp);
 
+             /* If we are generating clz using wider mode, adjust the
+                result.  */
+             if (unoptab == clz_optab && temp != 0)
+               temp = expand_binop (wider_mode, sub_optab, temp,
+                                    GEN_INT (GET_MODE_BITSIZE (wider_mode)
+                                             - GET_MODE_BITSIZE (mode)),
+                                    target, true, OPTAB_DIRECT);
+
              if (temp)
                {
                  if (class != MODE_INT)
@@ -2505,7 +2717,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
   /* If there is no negate operation, try doing a subtract from zero.
      The US Software GOFAST library needs this.  */
   if (unoptab->code == NEG)
-    {    
+    {
       rtx temp;
       temp = expand_binop (mode,
                            unoptab == negv_optab ? subv_optab : sub_optab,
@@ -2514,7 +2726,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       if (temp)
        return temp;
     }
-      
+
   return 0;
 }
 \f
@@ -2528,14 +2740,10 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
  */
 
 rtx
-expand_abs (mode, op0, target, result_unsignedp, safe)
-     enum machine_mode mode;
-     rtx op0;
-     rtx target;
-     int result_unsignedp;
-     int safe;
+expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
+                  int result_unsignedp)
 {
-  rtx temp, op1;
+  rtx temp;
 
   if (! flag_trapv)
     result_unsignedp = 1;
@@ -2546,6 +2754,56 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
   if (temp != 0)
     return temp;
 
+  /* For floating point modes, try clearing the sign bit.  */
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+    {
+      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;
+
+      if (imode != BLKmode && bitpos >= 0)
+       {
+         HOST_WIDE_INT hi, lo;
+         rtx last = get_last_insn ();
+
+         /* Handle targets with different FP word orders.  */
+         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
+           {
+             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
+             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
+           }
+
+         if (bitpos < HOST_BITS_PER_WIDE_INT)
+           {
+             hi = 0;
+             lo = (HOST_WIDE_INT) 1 << bitpos;
+           }
+         else
+           {
+             hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+             lo = 0;
+           }
+         temp = expand_binop (imode, and_optab,
+                              gen_lowpart (imode, op0),
+                              immed_double_const (~lo, ~hi, imode),
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+         if (temp != 0)
+           {
+             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);
+       }
+    }
+
   /* If we have a MAX insn, we can do this as MAX (x, -x).  */
   if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
@@ -2582,6 +2840,22 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
        return temp;
     }
 
+  return NULL_RTX;
+}
+
+rtx
+expand_abs (enum machine_mode mode, rtx op0, rtx target,
+           int result_unsignedp, int safe)
+{
+  rtx temp, op1;
+
+  if (! flag_trapv)
+    result_unsignedp = 1;
+
+  temp = expand_abs_nojump (mode, op0, target, result_unsignedp);
+  if (temp != 0)
+    return temp;
+
   /* If that does not win, use conditional jump and negate.  */
 
   /* It is safe to use the target if it is the same
@@ -2605,7 +2879,7 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
      compare word by word.  Rely on CSE to optimize constant cases.  */
   if (GET_MODE_CLASS (mode) == MODE_INT
       && ! can_compare_p (GE, mode, ccp_jump))
-    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 
+    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx,
                                  NULL_RTX, op1);
   else
     do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
@@ -2630,11 +2904,8 @@ expand_abs (mode, op0, target, result_unsignedp, safe)
    UNSIGNEDP is relevant for complex integer modes.  */
 
 rtx
-expand_complex_abs (mode, op0, target, unsignedp)
-     enum machine_mode mode;
-     rtx op0;
-     rtx target;
-     int unsignedp;
+expand_complex_abs (enum machine_mode mode, rtx op0, rtx target,
+                   int unsignedp)
 {
   enum mode_class class = GET_MODE_CLASS (mode);
   enum machine_mode wider_mode;
@@ -2645,10 +2916,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
   optab this_abs_optab;
 
   /* Find the correct mode for the real and imaginary parts.  */
-  enum machine_mode submode
-    = mode_for_size (GET_MODE_UNIT_SIZE (mode) * BITS_PER_UNIT,
-                    class == MODE_COMPLEX_INT ? MODE_INT : MODE_FLOAT,
-                    0);
+  enum machine_mode submode = GET_MODE_INNER (mode);
 
   if (submode == BLKmode)
     abort ();
@@ -2696,16 +2964,16 @@ expand_complex_abs (mode, op0, target, unsignedp)
       if (pat)
        {
          if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX
-             && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 
+             && ! add_equal_note (pat, temp, this_abs_optab->code, xop0,
                                   NULL_RTX))
            {
              delete_insns_since (last);
-             return expand_unop (mode, this_abs_optab, op0, NULL_RTX, 
+             return expand_unop (mode, this_abs_optab, op0, NULL_RTX,
                                  unsignedp);
            }
 
          emit_insn (pat);
-         
+
          return temp;
        }
       else
@@ -2717,7 +2985,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
   for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
        wider_mode = GET_MODE_WIDER_MODE (wider_mode))
     {
-      if (this_abs_optab->handlers[(int) wider_mode].insn_code 
+      if (this_abs_optab->handlers[(int) wider_mode].insn_code
          != CODE_FOR_nothing)
        {
          rtx xop0 = op0;
@@ -2833,11 +3101,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
    the value that is stored into TARGET.  */
 
 void
-emit_unop_insn (icode, target, op0, code)
-     int icode;
-     rtx target;
-     rtx op0;
-     enum rtx_code code;
+emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
 {
   rtx temp;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -2866,7 +3130,7 @@ emit_unop_insn (icode, target, op0, code)
 
   if (INSN_P (pat) && NEXT_INSN (pat) != NULL_RTX && code != UNKNOWN)
     add_equal_note (pat, temp, code, op0, NULL_RTX);
-  
+
   emit_insn (pat);
 
   if (temp != target)
@@ -2887,12 +3151,12 @@ emit_unop_insn (icode, target, op0, code)
 
    INSNS is a block of code generated to perform the operation, not including
    the CLOBBER and final copy.  All insns that compute intermediate values
-   are first emitted, followed by the block as described above.  
+   are first emitted, followed by the block as described above.
 
    TARGET, OP0, and OP1 are the output and inputs of the operations,
    respectively.  OP1 may be zero for a unary operation.
 
-   EQUIV, if non-zero, is an expression to be placed into a REG_EQUAL note
+   EQUIV, if nonzero, is an expression to be placed into a REG_EQUAL note
    on the last insn.
 
    If TARGET is not a register, INSNS is simply emitted with no special
@@ -2902,11 +3166,7 @@ emit_unop_insn (icode, target, op0, code)
    The final insn emitted is returned.  */
 
 rtx
-emit_no_conflict_block (insns, target, op0, op1, equiv)
-     rtx insns;
-     rtx target;
-     rtx op0, op1;
-     rtx equiv;
+emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
 {
   rtx prev, next, first, last, insn;
 
@@ -2927,7 +3187,7 @@ emit_no_conflict_block (insns, target, op0, op1, 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);
@@ -3043,11 +3303,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
    block is delimited by REG_RETVAL and REG_LIBCALL notes.  */
 
 void
-emit_libcall_block (insns, target, result, equiv)
-     rtx insns;
-     rtx target;
-     rtx result;
-     rtx equiv;
+emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
 {
   rtx final_dest = target;
   rtx prev, next, first, last, insn;
@@ -3056,7 +3312,7 @@ emit_libcall_block (insns, target, result, equiv)
      into a MEM later.  Protect the libcall block from this change.  */
   if (! REG_P (target) || REG_USERVAR_P (target))
     target = gen_reg_rtx (GET_MODE (target));
-  
+
   /* If we're using non-call exceptions, a libcall corresponding to an
      operation that may trap may also trap.  */
   if (flag_non_call_exceptions && may_trap_p (equiv))
@@ -3065,7 +3321,7 @@ emit_libcall_block (insns, target, result, equiv)
        if (GET_CODE (insn) == CALL_INSN)
          {
            rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
-           
+
            if (note != 0 && INTVAL (XEXP (note, 0)) <= 0)
              remove_note (insn, note);
          }
@@ -3079,11 +3335,11 @@ emit_libcall_block (insns, target, result, equiv)
       if (GET_CODE (insn) == CALL_INSN)
        {
          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));
        }
 
@@ -3098,7 +3354,7 @@ emit_libcall_block (insns, target, result, 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);
@@ -3126,6 +3382,11 @@ emit_libcall_block (insns, target, result, equiv)
 
          add_insn (insn);
        }
+
+      /* Some ports use a loop to copy large arguments onto the stack.
+        Don't move anything outside such a loop.  */
+      if (GET_CODE (insn) == CODE_LABEL)
+       break;
     }
 
   prev = get_last_insn ();
@@ -3164,18 +3425,33 @@ emit_libcall_block (insns, target, result, equiv)
   /* Encapsulate the block so it gets manipulated as a unit.  */
   if (!flag_non_call_exceptions || !may_trap_p (equiv))
     {
-      REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
-                                            REG_NOTES (first));
-      REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
-                                           REG_NOTES (last));
+      /* We can't attach the REG_LIBCALL and REG_RETVAL notes
+        when the encapsulated region would not be in one basic block,
+        i.e. when there is a control_flow_insn_p insn between FIRST and LAST.
+       */
+      bool attach_libcall_retval_notes = true;
+      next = NEXT_INSN (last);
+      for (insn = first; insn != next; insn = NEXT_INSN (insn))
+       if (control_flow_insn_p (insn))
+         {
+           attach_libcall_retval_notes = false;
+           break;
+         }
+
+      if (attach_libcall_retval_notes)
+       {
+         REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+                                                REG_NOTES (first));
+         REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
+                                               REG_NOTES (last));
+       }
     }
 }
 \f
 /* Generate code to store zero in X.  */
 
 void
-emit_clr_insn (x)
-     rtx x;
+emit_clr_insn (rtx x)
 {
   emit_move_insn (x, const0_rtx);
 }
@@ -3184,8 +3460,7 @@ emit_clr_insn (x)
    assuming it contains zero beforehand.  */
 
 void
-emit_0_to_1_insn (x)
-     rtx x;
+emit_0_to_1_insn (rtx x)
 {
   emit_move_insn (x, const1_rtx);
 }
@@ -3195,35 +3470,33 @@ emit_0_to_1_insn (x)
    comparison code we will be using.
 
    ??? Actually, CODE is slightly weaker than that.  A target is still
-   required to implement all of the normal bcc operations, but not 
+   required to implement all of the normal bcc operations, but not
    required to implement all (or any) of the unordered bcc operations.  */
-  
+
 int
-can_compare_p (code, mode, purpose)
-     enum rtx_code code;
-     enum machine_mode mode;
-     enum can_compare_purpose purpose;
+can_compare_p (enum rtx_code code, enum machine_mode mode,
+              enum can_compare_purpose purpose)
 {
   do
     {
-      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+      if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        {
          if (purpose == ccp_jump)
-           return bcc_gen_fctn[(int)code] != NULL;
+           return bcc_gen_fctn[(int) code] != NULL;
          else if (purpose == ccp_store_flag)
-           return setcc_gen_code[(int)code] != CODE_FOR_nothing;
+           return setcc_gen_code[(int) code] != CODE_FOR_nothing;
          else
            /* There's only one cmov entry point, and it's allowed to fail.  */
            return 1;
        }
       if (purpose == ccp_jump
-         && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+         && cbranch_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        return 1;
       if (purpose == ccp_cmov
-         && cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+         && cmov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        return 1;
       if (purpose == ccp_store_flag
-         && cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+         && cstore_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
        return 1;
 
       mode = GET_MODE_WIDER_MODE (mode);
@@ -3250,13 +3523,9 @@ can_compare_p (code, mode, purpose)
    should perform the comparison on the modified values.  */
 
 static void
-prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
-     rtx *px, *py;
-     enum rtx_code *pcomparison;
-     rtx size;
-     enum machine_mode *pmode;
-     int *punsignedp;
-     enum can_compare_purpose purpose;
+prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
+                 enum machine_mode *pmode, int *punsignedp,
+                 enum can_compare_purpose purpose)
 {
   enum machine_mode mode = *pmode;
   rtx x = *px, y = *py;
@@ -3272,8 +3541,17 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
 
   if (mode != BLKmode && flag_force_mem)
     {
-      x = force_not_mem (x);
-      y = force_not_mem (y);
+      /* Load duplicate non-volatile operands once.  */
+      if (rtx_equal_p (x, y) && ! volatile_refs_p (x))
+       {
+         x = force_not_mem (x);
+         y = x;
+       }
+      else
+       {
+         x = force_not_mem (x);
+         y = force_not_mem (y);
+       }
     }
 
   /* If we are inside an appropriately-short loop and one operand is an
@@ -3291,7 +3569,7 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
      states that canonical comparisons are required only for targets which
      have cc0.  */
   if (CONSTANT_P (x) && ! CONSTANT_P (y))
-    abort();
+    abort ();
 #endif
 
   /* Don't let both operands fail to indicate the mode.  */
@@ -3302,77 +3580,71 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
 
   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
-         emit_library_call (memcmp_libfunc, 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
-         emit_library_call (bcmp_libfunc, 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
-
-         /* Immediately move the result of the libcall into a pseudo
-            register so reload doesn't clobber the value if it needs
-            the return register for a spill reg.  */
-         result = gen_reg_rtx (TYPE_MODE (integer_type_node));
-         result_mode = TYPE_MODE (integer_type_node);
-         emit_move_insn (result,
-                         hard_libcall_value (result_mode));
-       }
+      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;
@@ -3396,14 +3668,8 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
       if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
        libfunc = ucmp_optab->handlers[(int) mode].libfunc;
 
-      emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode,
-                        y, mode);
-
-      /* Immediately move the result of the libcall into a pseudo
-        register so reload doesn't clobber the value if it needs
-        the return register for a spill reg.  */
-      result = gen_reg_rtx (word_mode);
-      emit_move_insn (result, hard_libcall_value (word_mode));
+      result = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST_MAKE_BLOCK,
+                                       word_mode, 2, x, mode, y, mode);
 
       /* Integer comparison returns a result that must be compared against 1,
         so that even if we do an unsigned compare afterward,
@@ -3427,12 +3693,8 @@ prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, purpose)
    that it is accepted by the operand predicate.  Return the new value.  */
 
 rtx
-prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
-     int icode;
-     rtx x;
-     int opnum;
-     enum machine_mode mode, wider_mode;
-     int unsignedp;
+prepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
+                enum machine_mode wider_mode, int unsignedp)
 {
   x = protect_from_queue (x, 0);
 
@@ -3441,7 +3703,12 @@ prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
 
   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;
 }
 
@@ -3451,12 +3718,8 @@ prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
    be NULL_RTX which indicates that only a comparison is to be generated.  */
 
 static void
-emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
-     rtx x, y;
-     enum machine_mode mode;
-     enum rtx_code comparison;
-     int unsignedp;
-     rtx label;
+emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
+                         enum rtx_code comparison, int unsignedp, rtx label)
 {
   rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
   enum mode_class class = GET_MODE_CLASS (mode);
@@ -3469,9 +3732,9 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
       PUT_MODE (test, wider_mode);
 
       if (label)
-       {         
-         icode = cbranch_optab->handlers[(int)wider_mode].insn_code;
-         
+       {
+         icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
+
          if (icode != CODE_FOR_nothing
              && (*insn_data[icode].operand[0].predicate) (test, wider_mode))
            {
@@ -3511,7 +3774,8 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
        break;
 
       wider_mode = GET_MODE_WIDER_MODE (wider_mode);
-    } while (wider_mode != VOIDmode);
+    }
+  while (wider_mode != VOIDmode);
 
   abort ();
 }
@@ -3534,13 +3798,8 @@ emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
    unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
 
 void
-emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
-     rtx x, y;
-     enum rtx_code comparison;
-     rtx size;
-     enum machine_mode mode;
-     int unsignedp;
-     rtx label;
+emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
+                        enum machine_mode mode, int unsignedp, rtx label)
 {
   rtx op0 = x, op1 = y;
 
@@ -3576,12 +3835,8 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, label)
 /* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
 
 void
-emit_cmp_insn (x, y, comparison, size, mode, unsignedp)
-     rtx x, y;
-     enum rtx_code comparison;
-     rtx size;
-     enum machine_mode mode;
-     int unsignedp;
+emit_cmp_insn (rtx x, rtx y, enum rtx_code comparison, rtx size,
+              enum machine_mode mode, int unsignedp)
 {
   emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, 0);
 }
@@ -3590,362 +3845,125 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp)
    COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
 
 static void
-prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
-     rtx *px, *py;
-     enum rtx_code *pcomparison;
-     enum machine_mode *pmode;
-     int *punsignedp;
+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);
+
 
-  emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, y,
-                    mode);
+  if (comparison == UNORDERED
+      || FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
+    comparison = NE;
 
-  /* Immediately move the result of the libcall into a pseudo
-     register so reload doesn't clobber the value if it needs
-     the return register for a spill reg.  */
-  result = gen_reg_rtx (word_mode);
-  emit_move_insn (result, hard_libcall_value (word_mode));
-  *px = result;
+  *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
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
 
 void
-emit_indirect_jump (loc)
-     rtx loc;
+emit_indirect_jump (rtx loc)
 {
-  if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate)
+  if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate)
         (loc, Pmode)))
     loc = copy_to_mode_reg (Pmode, loc);
 
@@ -3970,15 +3988,9 @@ emit_indirect_jump (loc)
    is not supported.  */
 
 rtx
-emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
-                      unsignedp)
-     rtx target;
-     enum rtx_code code;
-     rtx op0, op1;
-     enum machine_mode cmode;
-     rtx op2, op3;
-     enum machine_mode mode;
-     int unsignedp;
+emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
+                      enum machine_mode cmode, rtx op2, rtx op3,
+                      enum machine_mode mode, int unsignedp)
 {
   rtx tem, subtarget, comparison, insn;
   enum insn_code icode;
@@ -3998,9 +4010,9 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
   /* 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)
@@ -4059,7 +4071,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
   /* Everything should now be in the suitable form, so emit the compare insn
      and then the conditional move.  */
 
-  comparison 
+  comparison
     = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
 
   /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
@@ -4068,7 +4080,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
      situation.  */
   if (GET_CODE (comparison) != code)
     return NULL_RTX;
-  
+
   insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
 
   /* If that failed, then give up.  */
@@ -4083,7 +4095,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
   return target;
 }
 
-/* Return non-zero if a conditional move of mode MODE is supported.
+/* Return nonzero if a conditional move of mode MODE is supported.
 
    This function is for combine so it can tell whether an insn that looks
    like a conditional move is actually supported by the hardware.  If we
@@ -4092,8 +4104,7 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
    comparisons, and vice versa.  How do we handle them?  */
 
 int
-can_conditionally_move_p (mode)
-     enum machine_mode mode;
+can_conditionally_move_p (enum machine_mode mode)
 {
   if (movcc_gen_code[mode] != CODE_FOR_nothing)
     return 1;
@@ -4102,9 +4113,132 @@ can_conditionally_move_p (mode)
 }
 
 #endif /* HAVE_conditional_move */
+
+/* Emit a conditional addition instruction if the machine supports one for that
+   condition and machine mode.
+
+   OP0 and OP1 are the operands that should be compared using CODE.  CMODE is
+   the mode to use should they be constants.  If it is VOIDmode, they cannot
+   both be constants.
+
+   OP2 should be stored in TARGET if the comparison is true, otherwise OP2+OP3
+   should be stored there.  MODE is the mode to use should they be constants.
+   If it is VOIDmode, they cannot both be constants.
+
+   The result is either TARGET (perhaps modified) or NULL_RTX if the operation
+   is not supported.  */
+
+rtx
+emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
+                     enum machine_mode cmode, rtx op2, rtx op3,
+                     enum machine_mode mode, int unsignedp)
+{
+  rtx tem, subtarget, comparison, insn;
+  enum insn_code icode;
+  enum rtx_code reversed;
+
+  /* If one operand is constant, make it the second one.  Only do this
+     if the other operand is not constant as well.  */
+
+  if (swap_commutative_operands_p (op0, op1))
+    {
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+      code = swap_condition (code);
+    }
+
+  /* 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 && op1 == const1_rtx)
+    code = LE, op1 = const0_rtx;
+  else if (code == GT && op1 == constm1_rtx)
+    code = GE, op1 = const0_rtx;
+
+  if (cmode == VOIDmode)
+    cmode = GET_MODE (op0);
+
+  if (swap_commutative_operands_p (op2, op3)
+      && ((reversed = reversed_comparison_code_parts (code, op0, op1, NULL))
+          != UNKNOWN))
+    {
+      tem = op2;
+      op2 = op3;
+      op3 = tem;
+      code = reversed;
+    }
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (op2);
+
+  icode = addcc_optab->handlers[(int) mode].insn_code;
+
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  if (flag_force_mem)
+    {
+      op2 = force_not_mem (op2);
+      op3 = force_not_mem (op3);
+    }
+
+  if (target)
+    target = protect_from_queue (target, 1);
+  else
+    target = gen_reg_rtx (mode);
+
+  subtarget = target;
+
+  emit_queue ();
+
+  op2 = protect_from_queue (op2, 0);
+  op3 = protect_from_queue (op3, 0);
+
+  /* If the insn doesn't accept these operands, put them in pseudos.  */
+
+  if (! (*insn_data[icode].operand[0].predicate)
+      (subtarget, insn_data[icode].operand[0].mode))
+    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
+
+  if (! (*insn_data[icode].operand[2].predicate)
+      (op2, insn_data[icode].operand[2].mode))
+    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
+
+  if (! (*insn_data[icode].operand[3].predicate)
+      (op3, insn_data[icode].operand[3].mode))
+    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
+
+  /* Everything should now be in the suitable form, so emit the compare insn
+     and then the conditional move.  */
+
+  comparison
+    = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX);
+
+  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
+  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
+     return NULL and let the caller figure out how best to deal with this
+     situation.  */
+  if (GET_CODE (comparison) != code)
+    return NULL_RTX;
+
+  insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
+
+  /* If that failed, then give up.  */
+  if (insn == 0)
+    return 0;
+
+  emit_insn (insn);
+
+  if (subtarget != target)
+    convert_move (target, subtarget, 0);
+
+  return target;
+}
 \f
-/* These functions generate an insn body and return it
-   rather than emitting the insn.
+/* These functions attempt to generate an insn body, rather than
+   emitting the insn, but if the gen function already emits them, we
+   make no attempt to turn them back into naked patterns.
 
    They do not protect from queued increments,
    because they may be used 1) in protect_from_queue itself
@@ -4113,10 +4247,9 @@ can_conditionally_move_p (mode)
 /* Generate and return an insn body to add Y to X.  */
 
 rtx
-gen_add2_insn (x, y)
-     rtx x, y;
+gen_add2_insn (rtx x, rtx y)
 {
-  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 
+  int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (! ((*insn_data[icode].operand[0].predicate)
         (x, insn_data[icode].operand[0].mode))
@@ -4132,12 +4265,11 @@ gen_add2_insn (x, y)
 /* Generate and return an insn body to add r1 and c,
    storing the result in r0.  */
 rtx
-gen_add3_insn (r0, r1, c)
-     rtx r0, r1, c;
+gen_add3_insn (rtx r0, rtx r1, rtx c)
 {
   int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
 
-    if (icode == CODE_FOR_nothing
+  if (icode == CODE_FOR_nothing
       || ! ((*insn_data[icode].operand[0].predicate)
            (r0, insn_data[icode].operand[0].mode))
       || ! ((*insn_data[icode].operand[1].predicate)
@@ -4150,15 +4282,14 @@ gen_add3_insn (r0, r1, c)
 }
 
 int
-have_add2_insn (x, y)
-     rtx x, y;
+have_add2_insn (rtx x, rtx y)
 {
   int icode;
 
   if (GET_MODE (x) == VOIDmode)
     abort ();
 
-  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 
+  icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (icode == CODE_FOR_nothing)
     return 0;
@@ -4177,10 +4308,9 @@ have_add2_insn (x, y)
 /* Generate and return an insn body to subtract Y from X.  */
 
 rtx
-gen_sub2_insn (x, y)
-     rtx x, y;
+gen_sub2_insn (rtx x, rtx y)
 {
-  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 
+  int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (! ((*insn_data[icode].operand[0].predicate)
         (x, insn_data[icode].operand[0].mode))
@@ -4196,12 +4326,11 @@ gen_sub2_insn (x, y)
 /* Generate and return an insn body to subtract r1 and c,
    storing the result in r0.  */
 rtx
-gen_sub3_insn (r0, r1, c)
-     rtx r0, r1, c;
+gen_sub3_insn (rtx r0, rtx r1, rtx c)
 {
   int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
 
-    if (icode == CODE_FOR_nothing
+  if (icode == CODE_FOR_nothing
       || ! ((*insn_data[icode].operand[0].predicate)
            (r0, insn_data[icode].operand[0].mode))
       || ! ((*insn_data[icode].operand[1].predicate)
@@ -4214,15 +4343,14 @@ gen_sub3_insn (r0, r1, c)
 }
 
 int
-have_sub2_insn (x, y)
-     rtx x, y;
+have_sub2_insn (rtx x, rtx y)
 {
   int icode;
 
   if (GET_MODE (x) == VOIDmode)
     abort ();
 
-  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 
+  icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (icode == CODE_FOR_nothing)
     return 0;
@@ -4242,72 +4370,10 @@ have_sub2_insn (x, y)
    It may be a list of insns, if one insn isn't enough.  */
 
 rtx
-gen_move_insn (x, y)
-     rtx x, y;
+gen_move_insn (rtx x, rtx y)
 {
-  enum machine_mode mode = GET_MODE (x);
-  enum insn_code insn_code;
   rtx seq;
 
-  if (mode == VOIDmode)
-    mode = GET_MODE (y); 
-
-  insn_code = mov_optab->handlers[(int) mode].insn_code;
-
-  /* Handle MODE_CC modes:  If we don't have a special move insn for this mode,
-     find a mode to do it in.  If we have a movcc, use it.  Otherwise,
-     find the MODE_INT mode of the same width.  */
-
-  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
-    {
-      enum machine_mode tmode = VOIDmode;
-      rtx x1 = x, y1 = y;
-
-      if (mode != CCmode
-         && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
-       tmode = CCmode;
-      else
-       for (tmode = QImode; tmode != VOIDmode;
-            tmode = GET_MODE_WIDER_MODE (tmode))
-         if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
-           break;
-
-      if (tmode == VOIDmode)
-       abort ();
-
-      /* Get X and Y in TMODE.  We can't use gen_lowpart here because it
-        may call change_address which is not appropriate if we were
-        called when a reload was in progress.  We don't have to worry
-        about changing the address since the size in bytes is supposed to
-        be the same.  Copy the MEM to change the mode and move any
-        substitutions from the old MEM to the new one.  */
-
-      if (reload_in_progress)
-       {
-         x = gen_lowpart_common (tmode, x1);
-         if (x == 0 && GET_CODE (x1) == MEM)
-           {
-             x = adjust_address_nv (x1, tmode, 0);
-             copy_replacements (x1, x);
-           }
-
-         y = gen_lowpart_common (tmode, y1);
-         if (y == 0 && GET_CODE (y1) == MEM)
-           {
-             y = adjust_address_nv (y1, tmode, 0);
-             copy_replacements (y1, y);
-           }
-       }
-      else
-       {
-         x = gen_lowpart (tmode, x);
-         y = gen_lowpart (tmode, y);
-       }
-         
-      insn_code = mov_optab->handlers[(int) tmode].insn_code;
-      return (GEN_FCN (insn_code) (x, y));
-    }
-
   start_sequence ();
   emit_move_insn_1 (x, y);
   seq = get_insns ();
@@ -4320,28 +4386,28 @@ gen_move_insn (x, y)
    no such operation exists, CODE_FOR_nothing will be returned.  */
 
 enum insn_code
-can_extend_p (to_mode, from_mode, unsignedp)
-     enum machine_mode to_mode, from_mode;
-     int unsignedp;
+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)
    into X (with mode MTO).  Do zero-extension if UNSIGNEDP is nonzero.  */
 
 rtx
-gen_extend_insn (x, y, mto, mfrom, unsignedp)
-     rtx x, y;
-     enum machine_mode mto, mfrom;
-     int unsignedp;
+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
@@ -4354,30 +4420,41 @@ gen_extend_insn (x, y, mto, mfrom, unsignedp)
    an explicit FTRUNC insn before the fix insn; otherwise 0.  */
 
 static enum insn_code
-can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
-     enum machine_mode fltmode, fixmode;
-     int unsignedp;
-     int *truncp_ptr;
+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;
 
-  if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
+  tab = unsignedp ? ufixtrunc_optab : sfixtrunc_optab;
+  icode = tab->handlers[fixmode][fltmode].insn_code;
+  if (icode != CODE_FOR_nothing)
+    {
+      *truncp_ptr = 0;
+      return icode;
+    }
+
+  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;
 }
 
 static enum insn_code
-can_float_p (fltmode, fixmode, unsignedp)
-     enum machine_mode fixmode, fltmode;
-     int unsignedp;
+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
@@ -4387,9 +4464,7 @@ can_float_p (fltmode, fixmode, unsignedp)
    if it is negative.  */
 
 void
-expand_float (to, from, unsignedp)
-     rtx to, from;
-     int unsignedp;
+expand_float (rtx to, rtx from, int unsignedp)
 {
   enum insn_code icode;
   rtx target = to;
@@ -4404,10 +4479,10 @@ expand_float (to, from, unsignedp)
      wider mode.  If the integer mode is wider than the mode of FROM,
      we can do the conversion signed even if the input is unsigned.  */
 
-  for (imode = GET_MODE (from); imode != VOIDmode;
-       imode = GET_MODE_WIDER_MODE (imode))
-    for (fmode = GET_MODE (to); fmode != VOIDmode;
-        fmode = GET_MODE_WIDER_MODE (fmode))
+  for (fmode = GET_MODE (to); fmode != VOIDmode;
+       fmode = GET_MODE_WIDER_MODE (fmode))
+    for (imode = GET_MODE (from); imode != VOIDmode;
+        imode = GET_MODE_WIDER_MODE (imode))
       {
        int doing_unsigned = unsignedp;
 
@@ -4437,7 +4512,7 @@ expand_float (to, from, unsignedp)
              convert_move (to, target, 0);
            return;
          }
-    }
+      }
 
   /* Unsigned integer, and no way to convert directly.
      Convert as signed, then conditionally adjust the result.  */
@@ -4477,7 +4552,7 @@ expand_float (to, from, unsignedp)
              rtx temp1;
              rtx neglabel = gen_label_rtx ();
 
-             /* Don't use TARGET if it isn't a register, is a hard register, 
+             /* Don't use TARGET if it isn't a register, is a hard register,
                 or is the wrong mode.  */
              if (GET_CODE (target) != REG
                  || REGNO (target) < FIRST_PSEUDO_REGISTER
@@ -4506,13 +4581,13 @@ expand_float (to, from, unsignedp)
                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
              temp1 = expand_shift (RSHIFT_EXPR, imode, from, integer_one_node,
                                    NULL_RTX, 1);
-             temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1, 
+             temp = expand_binop (imode, ior_optab, temp, temp1, temp, 1,
                                   OPTAB_LIB_WIDEN);
              expand_float (target, temp, 0);
 
              /* Multiply by 2 to undo the shift above.  */
              temp = expand_binop (fmode, add_optab, target, target,
-                                    target, 0, OPTAB_LIB_WIDEN);
+                                  target, 0, OPTAB_LIB_WIDEN);
              if (temp != target)
                emit_move_insn (target, temp);
 
@@ -4539,10 +4614,8 @@ expand_float (to, from, unsignedp)
       emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
                               0, label);
 
-      /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1).
-        Rather than setting up a dconst_dot_5, let's hope SCO
-        fixes the bug.  */
-      offset = REAL_VALUE_LDEXP (dconst1, GET_MODE_BITSIZE (GET_MODE (from)));
+
+      real_2expN (&offset, GET_MODE_BITSIZE (GET_MODE (from)));
       temp = expand_binop (fmode, add_optab, target,
                           CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
                           target, 0, OPTAB_LIB_WIDEN);
@@ -4554,12 +4627,12 @@ expand_float (to, from, 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);
@@ -4570,56 +4643,13 @@ expand_float (to, from, 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 ();
@@ -4647,23 +4677,19 @@ expand_float (to, from, unsignedp)
    and store in TO.  FROM must be floating point.  */
 
 static rtx
-ftruncify (x)
-     rtx x;
+ftruncify (rtx x)
 {
   rtx temp = gen_reg_rtx (GET_MODE (x));
   return expand_unop (GET_MODE (x), ftrunc_optab, x, temp, 0);
 }
 
 void
-expand_fix (to, from, unsignedp)
-     rtx to, from;
-     int unsignedp;
+expand_fix (rtx to, rtx from, int unsignedp)
 {
   enum insn_code icode;
   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
@@ -4710,22 +4736,33 @@ expand_fix (to, from, unsignedp)
      one plus the highest signed number, convert, and add it back.
 
      We only need to check all real modes, since we know we didn't find
-     anything with a wider integer mode.  */
+     anything with a wider integer mode.
+
+     This code used to extend FP value into mode wider than the destination.
+     This is not needed.  Consider, for instance conversion from SFmode
+     into DImode.
+
+     The hot path trought the code is dealing with inputs smaller than 2^63
+     and doing just the conversion, so there is no bits to lose.
+
+     In the other path we know the value is positive in the range 2^63..2^64-1
+     inclusive.  (as for other imput overflow happens and result is undefined)
+     So we know that the most important bit set in mantissa corresponds to
+     2^63.  The subtraction of 2^63 should not generate any rounding as it
+     simply clears out that bit.  The rest is trivial.  */
 
   if (unsignedp && GET_MODE_BITSIZE (GET_MODE (to)) <= HOST_BITS_PER_WIDE_INT)
     for (fmode = GET_MODE (from); fmode != VOIDmode;
         fmode = GET_MODE_WIDER_MODE (fmode))
-      /* Make sure we won't lose significant bits doing this.  */
-      if (GET_MODE_BITSIZE (fmode) > GET_MODE_BITSIZE (GET_MODE (to))
-         && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
-                                           &must_trunc))
+      if (CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
+                                        &must_trunc))
        {
          int bitsize;
          REAL_VALUE_TYPE offset;
          rtx limit, lab1, lab2, insn;
 
          bitsize = GET_MODE_BITSIZE (GET_MODE (to));
-         offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1);
+         real_2expN (&offset, bitsize - 1);
          limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
          lab1 = gen_label_rtx ();
          lab2 = gen_label_rtx ();
@@ -4793,57 +4830,16 @@ expand_fix (to, from, 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);
@@ -4853,7 +4849,7 @@ expand_fix (to, from, 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 ();
@@ -4863,7 +4859,7 @@ expand_fix (to, from, unsignedp)
                          gen_rtx_fmt_e (unsignedp ? UNSIGNED_FIX : FIX,
                                         GET_MODE (to), from));
     }
-      
+
   if (target != to)
     {
       if (GET_MODE (to) == GET_MODE (target))
@@ -4876,9 +4872,7 @@ expand_fix (to, from, unsignedp)
 /* Report whether we have an instruction to perform the operation
    specified by CODE on operands of mode MODE.  */
 int
-have_insn_for (code, mode)
-     enum rtx_code code;
-     enum machine_mode mode;
+have_insn_for (enum rtx_code code, enum machine_mode mode)
 {
   return (code_to_optab[(int) code] != 0
          && (code_to_optab[(int) code]->handlers[(int) mode].insn_code
@@ -4887,10 +4881,10 @@ have_insn_for (code, mode)
 
 /* Create a blank optab.  */
 static optab
-new_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;
@@ -4900,11 +4894,24 @@ new_optab ()
   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
-init_optab (code)
-     enum rtx_code code;
+init_optab (enum rtx_code code)
 {
   optab op = new_optab ();
   op->code = code;
@@ -4915,18 +4922,26 @@ init_optab (code)
 /* Same, but fill in its code as CODE, and do _not_ write it into
    the code_to_optab table.  */
 static inline optab
-init_optabv (code)
-     enum rtx_code code;
+init_optabv (enum rtx_code code)
 {
   optab op = new_optab ();
   op->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').
 
@@ -4941,12 +4956,8 @@ init_optabv (code)
 */
 
 static void
-init_libfuncs (optable, first_mode, last_mode, opname, suffix)
-    optab optable;
-    int first_mode;
-    int last_mode;
-    const char *opname;
-    int suffix;
+init_libfuncs (optab optable, int first_mode, int last_mode,
+              const char *opname, int suffix)
 {
   int mode;
   unsigned opname_len = strlen (opname);
@@ -4954,7 +4965,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
   for (mode = first_mode; (int) mode <= (int) last_mode;
        mode = (enum machine_mode) ((int) mode + 1))
     {
-      const char *mname = GET_MODE_NAME(mode);
+      const char *mname = GET_MODE_NAME (mode);
       unsigned mname_len = strlen (mname);
       char *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
       char *p;
@@ -4971,8 +4982,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
       *p = '\0';
 
       optable->handlers[(int) mode].libfunc
-       = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
-                                                      p - libfunc_name));
+       = init_one_libfunc (ggc_alloc_string (libfunc_name, p - libfunc_name));
     }
 }
 
@@ -4982,12 +4992,14 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
    routine.  (See above).  */
 
 static void
-init_integral_libfuncs (optable, opname, suffix)
-    optab optable;
-    const char *opname;
-    int suffix;
+init_integral_libfuncs (optab optable, const char *opname, int suffix)
 {
-  init_libfuncs (optable, SImode, TImode, opname, suffix);
+  int maxsize = 2*BITS_PER_WORD;
+  if (maxsize < LONG_LONG_TYPE_SIZE)
+    maxsize = LONG_LONG_TYPE_SIZE;
+  init_libfuncs (optable, word_mode,
+                mode_for_size (maxsize, MODE_INT, 0),
+                opname, suffix);
 }
 
 /* Initialize the libfunc fields of an entire group of entries in some
@@ -4996,18 +5008,129 @@ init_integral_libfuncs (optable, opname, suffix)
    routine.  (See above).  */
 
 static void
-init_floating_libfuncs (optable, opname, suffix)
-    optab optable;
-    const char *opname;
-    int suffix;
+init_floating_libfuncs (optab optable, const char *opname, int suffix)
 {
-  init_libfuncs (optable, SFmode, TFmode, 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 (name)
-     const char *name;
+init_one_libfunc (const char *name)
 {
+  rtx symbol;
+
   /* Create a FUNCTION_DECL that can be passed to
      targetm.encode_section_info.  */
   /* ??? We don't have any type information except for this is
@@ -5018,40 +5141,49 @@ init_one_libfunc (name)
   DECL_EXTERNAL (decl) = 1;
   TREE_PUBLIC (decl) = 1;
 
-  /* Return the symbol_ref from the mem rtx.  */
-  return XEXP (DECL_RTL (decl), 0);
+  symbol = XEXP (DECL_RTL (decl), 0);
+
+  /* Zap the nonsensical SYMBOL_REF_DECL for this.  What we're left with
+     are the flags assigned by targetm.encode_section_info.  */
+  SYMBOL_REF_DECL (symbol) = 0;
+
+  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 ()
+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;
 
@@ -5090,6 +5222,8 @@ init_optabs ()
   smax_optab = init_optab (SMAX);
   umin_optab = init_optab (UMIN);
   umax_optab = init_optab (UMAX);
+  pow_optab = init_optab (UNKNOWN);
+  atan2_optab = init_optab (UNKNOWN);
 
   /* These three have codes assigned exclusively for the sake of
      have_insn_for.  */
@@ -5099,25 +5233,64 @@ init_optabs ()
 
   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);
   absv_optab = init_optabv (ABS);
+  addcc_optab = init_optab (UNKNOWN);
   one_cmpl_optab = init_optab (NOT);
   ffs_optab = init_optab (FFS);
+  clz_optab = init_optab (CLZ);
+  ctz_optab = init_optab (CTZ);
+  popcount_optab = init_optab (POPCOUNT);
+  parity_optab = init_optab (PARITY);
   sqrt_optab = init_optab (SQRT);
+  floor_optab = init_optab (UNKNOWN);
+  ceil_optab = init_optab (UNKNOWN);
+  round_optab = init_optab (UNKNOWN);
+  btrunc_optab = init_optab (UNKNOWN);
+  nearbyint_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
+  exp_optab = init_optab (UNKNOWN);
+  log_optab = init_optab (UNKNOWN);
+  tan_optab = init_optab (UNKNOWN);
+  atan_optab = init_optab (UNKNOWN);
   strlen_optab = init_optab (UNKNOWN);
   cbranch_optab = init_optab (UNKNOWN);
   cmov_optab = init_optab (UNKNOWN);
   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;
@@ -5127,14 +5300,6 @@ init_optabs ()
   /* 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');
@@ -5175,78 +5340,44 @@ init_optabs ()
   init_floating_libfuncs (negv_optab, "neg", '2');
   init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
   init_integral_libfuncs (ffs_optab, "ffs", '2');
+  init_integral_libfuncs (clz_optab, "clz", '2');
+  init_integral_libfuncs (ctz_optab, "ctz", '2');
+  init_integral_libfuncs (popcount_optab, "popcount", '2');
+  init_integral_libfuncs (parity_optab, "parity", '2');
 
   /* Comparison libcalls for integers MUST come in pairs, signed/unsigned.  */
   init_integral_libfuncs (cmp_optab, "cmp", '2');
   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");
@@ -5255,6 +5386,7 @@ init_optabs ()
   bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
   memset_libfunc = init_one_libfunc ("memset");
   bzero_libfunc = init_one_libfunc ("bzero");
+  setbits_libfunc = init_one_libfunc ("__setbits");
 
   unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
                                            ? "_Unwind_SjLj_Resume"
@@ -5270,161 +5402,63 @@ init_optabs ()
   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");
   profile_function_exit_libfunc
     = init_one_libfunc ("__cyg_profile_func_exit");
 
-#ifdef HAVE_conditional_trap
-  init_traps ();
-#endif
+  gcov_flush_libfunc = init_one_libfunc ("__gcov_flush");
+  gcov_init_libfunc = init_one_libfunc ("__gcov_init");
+
+  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
-static GTY(()) rtx trap_rtx;
-
-#ifdef HAVE_conditional_trap
-/* The insn generating function can not take an rtx_code argument.
-   TRAP_RTX is used as an rtx argument.  Its code is replaced with
-   the code to be used in the trap insn and all other fields are
-   ignored.  */
-
-static void
-init_traps ()
-{
-  if (HAVE_conditional_trap)
-    {
-      trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
-    }
-}
-#endif
-
 /* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
    CODE.  Return 0 on failure.  */
 
 rtx
-gen_cond_trap (code, op1, op2, tcode)
-  enum rtx_code code ATTRIBUTE_UNUSED;
-  rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
+gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
+              rtx op2 ATTRIBUTE_UNUSED, rtx tcode ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = GET_MODE (op1);
+  enum insn_code icode;
+  rtx insn;
+
+  if (!HAVE_conditional_trap)
+    return 0;
 
   if (mode == VOIDmode)
     return 0;
 
-#ifdef HAVE_conditional_trap
-  if (HAVE_conditional_trap
-      && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  icode = cmp_optab->handlers[(int) mode].insn_code;
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  start_sequence ();
+  op1 = prepare_operand (icode, op1, 0, mode, mode, 0);
+  op2 = prepare_operand (icode, op2, 1, mode, mode, 0);
+  if (!op1 || !op2)
     {
-      rtx insn;
-      start_sequence();
-      emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
-      PUT_CODE (trap_rtx, code);
-      insn = gen_conditional_trap (trap_rtx, tcode);
-      if (insn)
-       {
-         emit_insn (insn);
-         insn = get_insns ();
-       }
-      end_sequence();
-      return insn;
+      end_sequence ();
+      return 0;
     }
-#endif
+  emit_insn (GEN_FCN (icode) (op1, op2));
 
-  return 0;
+  PUT_CODE (trap_rtx, code);
+  insn = gen_conditional_trap (trap_rtx, tcode);
+  if (insn)
+    {
+      emit_insn (insn);
+      insn = get_insns ();
+    }
+  end_sequence ();
+
+  return insn;
 }
 
 #include "gt-optabs.h"