OSDN Git Service

install EH code
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 1dd2e26..ba4b72f 100644 (file)
@@ -1,5 +1,5 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
-   Copyright (C) 1987, 1988, 1992 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include "config.h"
@@ -27,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "expr.h"
 #include "insn-config.h"
 #include "recog.h"
+#include "reload.h"
 #include <ctype.h>
 
 /* Each optab contains info on how this target machine
@@ -41,6 +43,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 optab add_optab;
 optab sub_optab;
 optab smul_optab;
+optab smul_highpart_optab;
+optab umul_highpart_optab;
 optab smul_widen_optab;
 optab umul_widen_optab;
 optab sdiv_optab;
@@ -56,7 +60,6 @@ optab ior_optab;
 optab xor_optab;
 optab ashl_optab;
 optab lshr_optab;
-optab lshl_optab;
 optab ashr_optab;
 optab rotl_optab;
 optab rotr_optab;
@@ -82,6 +85,17 @@ optab tst_optab;
 
 optab strlen_optab;
 
+/* 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];
+
+/* Contains the optab used for each rtx code.  */
+optab code_to_optab[NUM_RTX_CODE + 1];
+
 /* SYMBOL_REF rtx's for the library functions that are called
    implicitly and not via optabs.  */
 
@@ -104,6 +118,15 @@ rtx bcmp_libfunc;
 rtx memset_libfunc;
 rtx bzero_libfunc;
 
+rtx throw_libfunc;
+
+rtx eqhf2_libfunc;
+rtx nehf2_libfunc;
+rtx gthf2_libfunc;
+rtx gehf2_libfunc;
+rtx lthf2_libfunc;
+rtx lehf2_libfunc;
+
 rtx eqsf2_libfunc;
 rtx nesf2_libfunc;
 rtx gtsf2_libfunc;
@@ -180,9 +203,6 @@ rtx fixunstfsi_libfunc;
 rtx fixunstfdi_libfunc;
 rtx fixunstfti_libfunc;
 
-/* from emit-rtl.c */
-extern rtx gen_highpart ();
-
 /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
    gives the gen_function to make a branch to test that condition.  */
 
@@ -194,7 +214,28 @@ rtxfun bcc_gen_fctn[NUM_RTX_CODE];
 
 enum insn_code setcc_gen_code[NUM_RTX_CODE];
 
-static void emit_float_lib_cmp ();
+#ifdef HAVE_conditional_move
+/* Indexed by the machine mode, gives the insn code to make a conditional
+   move insn.  This is not indexed by the rtx-code like bcc_gen_fctn and
+   setcc_gen_code to cut down on the number of named patterns.  Consider a day
+   when a lot more rtx codes are conditional (eg: for the ARM).  */
+
+enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
+#endif
+
+static int add_equal_note      PROTO((rtx, rtx, enum rtx_code, rtx, rtx));
+static rtx widen_operand       PROTO((rtx, enum machine_mode,
+                                      enum machine_mode, int, int));
+static enum insn_code can_fix_p        PROTO((enum machine_mode, enum machine_mode,
+                                      int, int *));
+static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,
+                                        int));
+static rtx ftruncify   PROTO((rtx));
+static optab init_optab        PROTO((enum rtx_code));
+static void init_libfuncs PROTO((optab, int, int, char *, int));
+static void init_integral_libfuncs PROTO((optab, char *, int));
+static void init_floating_libfuncs PROTO((optab, char *, int));
+static void init_complex_libfuncs PROTO((optab, char *, int));
 \f
 /* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -239,9 +280,9 @@ add_equal_note (seq, target, code, op0, op1)
        return 0;
 
   if (GET_RTX_CLASS (code) == '1')
-    note = gen_rtx (code, GET_MODE (target), op0);
+    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0));
   else
-    note = gen_rtx (code, GET_MODE (target), op0, op1);
+    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
 
   REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1))
     = gen_rtx (EXPR_LIST, REG_EQUAL, note,
@@ -250,6 +291,43 @@ add_equal_note (seq, target, code, op0, op1)
   return 1;
 }
 \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 
+   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;
+{
+  rtx result;
+
+  /* If we must extend do so.  If OP is either a constant or a SUBREG
+     for a promoted object, also extend since it will be more efficient to
+     do so.  */
+  if (! no_extend
+      || GET_MODE (op) == VOIDmode
+      || (GET_CODE (op) == SUBREG && SUBREG_PROMOTED_VAR_P (op)))
+    return convert_modes (mode, oldmode, op, unsignedp);
+
+  /* If MODE is no wider than a single word, we return a paradoxical
+     SUBREG.  */
+  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+    return gen_rtx (SUBREG, mode, force_reg (GET_MODE (op), op), 0);
+
+  /* Otherwise, get an object of MODE, clobber it, and set the low-order
+     part to OP.  */
+
+  result = gen_reg_rtx (mode);
+  emit_insn (gen_rtx (CLOBBER, VOIDmode, result));
+  emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
+  return result;
+}
+\f
 /* Generate code to perform an operation specified by BINOPTAB
    on operands OP0 and OP1, with result having machine-mode MODE.
 
@@ -270,13 +348,15 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
      int unsignedp;
      enum optab_methods methods;
 {
+  enum optab_methods next_methods
+    = (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN
+       ? OPTAB_WIDEN : methods);
   enum mode_class class;
   enum machine_mode wider_mode;
   register rtx temp;
   int commutative_op = 0;
   int shift_op = (binoptab->code ==  ASHIFT
                  || binoptab->code == ASHIFTRT
-                 || binoptab->code == LSHIFT
                  || binoptab->code == LSHIFTRT
                  || binoptab->code == ROTATE
                  || binoptab->code == ROTATERT);
@@ -312,8 +392,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
     op0 = force_reg (mode, op0);
 
   if (CONSTANT_P (op1) && preserve_subexpressions_p ()
-      && rtx_cost (op1, binoptab->code) > 2)
-    op1 = force_reg (shift_op ? word_mode : mode, op1);
+      && ! shift_op && rtx_cost (op1, binoptab->code) > 2)
+    op1 = force_reg (mode, op1);
 
   /* Record where to delete back to if we backtrack.  */
   last = get_last_insn ();
@@ -324,7 +404,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
      Also try to make the last operand a constant.  */
   if (GET_RTX_CLASS (binoptab->code) == 'c'
       || binoptab == smul_widen_optab
-      || binoptab == umul_widen_optab)
+      || binoptab == umul_widen_optab
+      || binoptab == smul_highpart_optab
+      || binoptab == umul_highpart_optab)
     {
       commutative_op = 1;
 
@@ -358,7 +440,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
        temp = gen_reg_rtx (mode);
 
       /* If it is a commutative operator and the modes would match
-        if we would swap the operands, we can save the conversions. */
+        if we would swap the operands, we can save the conversions.  */
       if (commutative_op)
        {
          if (GET_MODE (op0) != mode0 && GET_MODE (op1) != mode1
@@ -375,20 +457,24 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
         the result, convert the operands.  */
 
       if (GET_MODE (op0) != VOIDmode
-         && GET_MODE (op0) != mode0)
+         && GET_MODE (op0) != mode0
+         && mode0 != VOIDmode)
        xop0 = convert_to_mode (mode0, xop0, unsignedp);
 
       if (GET_MODE (xop1) != VOIDmode
-         && GET_MODE (xop1) != mode1)
+         && GET_MODE (xop1) != mode1
+         && mode1 != VOIDmode)
        xop1 = convert_to_mode (mode1, xop1, unsignedp);
 
       /* Now, if insn's predicates don't allow our operands, put them into
         pseudo regs.  */
 
-      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0)
+         && mode0 != VOIDmode)
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1))
+      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)
+         && mode1 != VOIDmode)
        xop1 = copy_to_mode_reg (mode1, xop1);
 
       if (! (*insn_operand_predicate[icode][0]) (temp, mode))
@@ -425,12 +511,15 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
     {
       temp = expand_binop (GET_MODE_WIDER_MODE (mode),
                           unsignedp ? umul_widen_optab : smul_widen_optab,
-                          op0, op1, 0, unsignedp, OPTAB_DIRECT);
+                          op0, op1, NULL_RTX, unsignedp, OPTAB_DIRECT);
 
-      if (GET_MODE_CLASS (mode) == MODE_INT)
-       return gen_lowpart (mode, temp);
-      else
-       return convert_to_mode (mode, temp, unsignedp);
+      if (temp != 0)
+       {
+         if (GET_MODE_CLASS (mode) == MODE_INT)
+           return gen_lowpart (mode, temp);
+         else
+           return convert_to_mode (mode, temp, unsignedp);
+       }
     }
 
   /* Look for a wider mode of the same class for which we think we
@@ -454,39 +543,20 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
            /* For certain integer operations, we need not actually extend
               the narrow operands, as long as we will truncate
-              the results to the same narrowness.  Don't do this when
-              WIDER_MODE is wider than a word since a paradoxical SUBREG
-              isn't valid for such modes.  */
+              the results to the same narrowness.   */
 
            if ((binoptab == ior_optab || binoptab == and_optab
                 || binoptab == xor_optab
                 || binoptab == add_optab || binoptab == sub_optab
-                || binoptab == smul_optab
-                || binoptab == ashl_optab || binoptab == lshl_optab)
-               && class == MODE_INT
-               && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD)
+                || binoptab == smul_optab || binoptab == ashl_optab)
+               && class == MODE_INT)
              no_extend = 1;
 
-           /* If an operand is a constant integer, we might as well
-              convert it since that is more efficient than using a SUBREG,
-              unlike the case for other operands.  Similarly for
-              SUBREGs that were made due to promoted objects.  */
-
-           if (no_extend && GET_MODE (xop0) != VOIDmode
-               && ! (GET_CODE (xop0) == SUBREG
-                     && SUBREG_PROMOTED_VAR_P (xop0)))
-             xop0 = gen_rtx (SUBREG, wider_mode,
-                             force_reg (GET_MODE (xop0), xop0), 0);
-           else
-             xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+           xop0 = widen_operand (xop0, wider_mode, mode, unsignedp, no_extend);
 
-           if (no_extend && GET_MODE (xop1) != VOIDmode
-               && ! (GET_CODE (xop1) == SUBREG
-                     && SUBREG_PROMOTED_VAR_P (xop1)))
-             xop1 = gen_rtx (SUBREG, wider_mode,
-                               force_reg (GET_MODE (xop1), xop1), 0);
-           else
-             xop1 = convert_to_mode (wider_mode, xop1, unsignedp);
+           /* The second operand of a shift must always be extended.  */
+           xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
+                                 no_extend && binoptab != ashl_optab);
 
            temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
                                 unsignedp, OPTAB_DIRECT);
@@ -531,7 +601,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          rtx x = expand_binop (word_mode, binoptab,
                                operand_subword_force (op0, i, mode),
                                operand_subword_force (op1, i, mode),
-                               target_piece, unsignedp, methods);
+                               target_piece, unsignedp, next_methods);
+
+         if (x == 0)
+           break;
+
          if (target_piece != x)
            emit_move_insn (target_piece, x);
        }
@@ -539,13 +613,258 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       insns = get_insns ();
       end_sequence ();
 
-      if (binoptab->code != UNKNOWN)
-       equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
+      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value
+             = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));
+         else
+           equiv_value = 0;
+
+         emit_no_conflict_block (insns, target, op0, op1, equiv_value);
+         return target;
+       }
+    }
+
+  /* Synthesize double word shifts from single word shifts.  */
+  if ((binoptab == lshr_optab || binoptab == ashl_optab
+       || binoptab == ashr_optab)
+      && class == MODE_INT
+      && GET_CODE (op1) == CONST_INT
+      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
+      && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
+      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
+      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
+    {
+      rtx insns, inter, equiv_value;
+      rtx into_target, outof_target;
+      rtx into_input, outof_input;
+      int shift_count, left_shift, outof_word;
+
+      /* If TARGET is the same as one of the operands, the REG_EQUAL note
+        won't be accurate, so use a new target.  */
+      if (target == 0 || target == op0 || target == op1)
+       target = gen_reg_rtx (mode);
+
+      start_sequence ();
+
+      shift_count = INTVAL (op1);
+
+      /* OUTOF_* is the word we are shifting bits away from, and
+        INTO_* is the word that we are shifting bits towards, thus
+        they differ depending on the direction of the shift and
+        WORDS_BIG_ENDIAN.  */
+
+      left_shift = binoptab == ashl_optab;
+      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
+
+      outof_target = operand_subword (target, outof_word, 1, mode);
+      into_target = operand_subword (target, 1 - outof_word, 1, mode);
+
+      outof_input = operand_subword_force (op0, outof_word, mode);
+      into_input = operand_subword_force (op0, 1 - outof_word, mode);
+
+      if (shift_count >= BITS_PER_WORD)
+       {
+         inter = expand_binop (word_mode, binoptab,
+                              outof_input,
+                              GEN_INT (shift_count - BITS_PER_WORD),
+                              into_target, unsignedp, next_methods);
+
+         if (inter != 0 && inter != into_target)
+           emit_move_insn (into_target, inter);
+
+         /* For a signed right shift, we must fill the word we are shifting
+            out of with copies of the sign bit.  Otherwise it is zeroed.  */
+         if (inter != 0 && binoptab != ashr_optab)
+           inter = CONST0_RTX (word_mode);
+         else if (inter != 0)
+           inter = expand_binop (word_mode, binoptab,
+                                 outof_input,
+                                 GEN_INT (BITS_PER_WORD - 1),
+                                 outof_target, unsignedp, next_methods);
+
+         if (inter != 0 && inter != outof_target)
+           emit_move_insn (outof_target, inter);
+       }
       else
-       equiv_value = 0;
+       {
+         rtx carries;
+         optab reverse_unsigned_shift, unsigned_shift;
 
-      emit_no_conflict_block (insns, target, op0, op1, equiv_value);
-      return target;
+         /* For a shift of less then BITS_PER_WORD, to compute the carry,
+            we must do a logical shift in the opposite direction of the
+            desired shift.  */
+
+         reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
+
+         /* For a shift of less than BITS_PER_WORD, to compute the word
+            shifted towards, we need to unsigned shift the orig value of
+            that word.  */
+
+         unsigned_shift = (left_shift ? ashl_optab : lshr_optab);
+
+         carries = expand_binop (word_mode, reverse_unsigned_shift,
+                                 outof_input,
+                                 GEN_INT (BITS_PER_WORD - shift_count),
+                                 0, unsignedp, next_methods);
+
+         if (carries == 0)
+           inter = 0;
+         else
+           inter = expand_binop (word_mode, unsigned_shift, into_input,
+                                 op1, 0, unsignedp, next_methods);
+
+         if (inter != 0)
+           inter = expand_binop (word_mode, ior_optab, carries, inter,
+                                 into_target, unsignedp, next_methods);
+
+         if (inter != 0 && inter != into_target)
+           emit_move_insn (into_target, inter);
+
+         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);
+       }
+
+      insns = get_insns ();
+      end_sequence ();
+
+      if (inter != 0)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
+         else
+           equiv_value = 0;
+
+         emit_no_conflict_block (insns, target, op0, op1, equiv_value);
+         return target;
+       }
+    }
+
+  /* Synthesize double word rotates from single word shifts.  */
+  if ((binoptab == rotl_optab || binoptab == rotr_optab)
+      && class == MODE_INT
+      && GET_CODE (op1) == CONST_INT
+      && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
+      && ashl_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
+      && lshr_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
+    {
+      rtx insns, equiv_value;
+      rtx into_target, outof_target;
+      rtx into_input, outof_input;
+      rtx inter;
+      int shift_count, left_shift, outof_word;
+
+      /* If TARGET is the same as one of the operands, the REG_EQUAL note
+        won't be accurate, so use a new target.  */
+      if (target == 0 || target == op0 || target == op1)
+       target = gen_reg_rtx (mode);
+
+      start_sequence ();
+
+      shift_count = INTVAL (op1);
+
+      /* OUTOF_* is the word we are shifting bits away from, and
+        INTO_* is the word that we are shifting bits towards, thus
+        they differ depending on the direction of the shift and
+        WORDS_BIG_ENDIAN.  */
+
+      left_shift = (binoptab == rotl_optab);
+      outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
+
+      outof_target = operand_subword (target, outof_word, 1, mode);
+      into_target = operand_subword (target, 1 - outof_word, 1, mode);
+
+      outof_input = operand_subword_force (op0, outof_word, mode);
+      into_input = operand_subword_force (op0, 1 - outof_word, mode);
+
+      if (shift_count == BITS_PER_WORD)
+       {
+         /* This is just a word swap.  */
+         emit_move_insn (outof_target, into_input);
+         emit_move_insn (into_target, outof_input);
+         inter = const0_rtx;
+       }
+      else
+       {
+         rtx into_temp1, into_temp2, outof_temp1, outof_temp2;
+         rtx first_shift_count, second_shift_count;
+         optab reverse_unsigned_shift, unsigned_shift;
+
+         reverse_unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
+                                   ? lshr_optab : ashl_optab);
+
+         unsigned_shift = (left_shift ^ (shift_count < BITS_PER_WORD)
+                           ? ashl_optab : lshr_optab);
+
+         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);
+           }
+         else
+           {
+             first_shift_count = GEN_INT (BITS_PER_WORD - shift_count);
+             second_shift_count = GEN_INT (shift_count);
+           }
+
+         into_temp1 = expand_binop (word_mode, unsigned_shift,
+                                    outof_input, first_shift_count,
+                                    NULL_RTX, unsignedp, next_methods);
+         into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
+                                    into_input, second_shift_count,
+                                    into_target, unsignedp, next_methods);
+
+         if (into_temp1 != 0 && into_temp2 != 0)
+           inter = expand_binop (word_mode, ior_optab, into_temp1, into_temp2,
+                                 into_target, unsignedp, next_methods);
+         else
+           inter = 0;
+
+         if (inter != 0 && inter != into_target)
+           emit_move_insn (into_target, inter);
+
+         outof_temp1 = expand_binop (word_mode, unsigned_shift,
+                                     into_input, first_shift_count,
+                                     NULL_RTX, unsignedp, next_methods);
+         outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
+                                     outof_input, second_shift_count,
+                                     outof_target, unsignedp, next_methods);
+
+         if (inter != 0 && outof_temp1 != 0 && outof_temp2 != 0)
+           inter = expand_binop (word_mode, ior_optab,
+                                 outof_temp1, outof_temp2,
+                                 outof_target, unsignedp, next_methods);
+
+         if (inter != 0 && inter != outof_target)
+           emit_move_insn (outof_target, inter);
+       }
+
+      insns = get_insns ();
+      end_sequence ();
+
+      if (inter != 0)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
+         else
+           equiv_value = 0;
+
+         /* We can't make this a no conflict block if this is a word swap,
+            because the word swap case fails if the input and output values
+            are in the same register.  */
+         if (shift_count != BITS_PER_WORD)
+           emit_no_conflict_block (insns, target, op0, op1, equiv_value);
+         else
+           emit_insns (insns);
+
+
+         return target;
+       }
     }
 
   /* These can be done a word at a time by propagating carries.  */
@@ -578,6 +897,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          || target == xop0 || target == xop1)
        target = gen_reg_rtx (mode);
 
+      /* Indicate for flow that the entire target reg is being set.  */
+      if (GET_CODE (target) == REG)
+       emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+
       /* Do the actual arithmetic.  */
       for (i = 0; i < nwords; i++)
        {
@@ -590,7 +913,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          /* Main add/subtract of the input operands.  */
          x = expand_binop (word_mode, binoptab,
                            op0_piece, op1_piece,
-                           target_piece, unsignedp, methods);
+                           target_piece, unsignedp, next_methods);
          if (x == 0)
            break;
 
@@ -602,7 +925,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                           binoptab == add_optab ? LTU : GTU,
                                           x, op0_piece,
                                           word_mode, 1, normalizep);
-             if (!carry_out)
+             if (carry_out == 0)
                break;
            }
 
@@ -612,8 +935,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              x = expand_binop (word_mode,
                                normalizep == 1 ? binoptab : otheroptab,
                                x, carry_in,
-                               target_piece, 1, methods);
-             if (target_piece != x)
+                               target_piece, 1, next_methods);
+             if (x == 0)
+               break;
+             else if (target_piece != x)
                emit_move_insn (target_piece, x);
 
              if (i + 1 < nwords)
@@ -625,11 +950,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                                 ? LTU : GTU,
                                               x, carry_in,
                                               word_mode, 1, normalizep);
+
                  /* Logical-ior the two poss. carry together.  */
                  carry_out = expand_binop (word_mode, ior_optab,
                                            carry_out, carry_tmp,
-                                           carry_out, 0, methods);
-                 if (!carry_out)
+                                           carry_out, 0, next_methods);
+                 if (carry_out == 0)
                    break;
                }
            }
@@ -639,11 +965,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
        {
-         rtx temp;
-         
-         temp = emit_move_insn (target, target);
+         rtx temp = emit_move_insn (target, target);
+
          REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
-                                     gen_rtx (binoptab->code, mode, xop0, xop1),
+                                     gen_rtx (binoptab->code, mode,
+                                              copy_rtx (xop0),
+                                              copy_rtx (xop1)),
                                      REG_NOTES (temp));
          return target;
        }
@@ -660,14 +987,14 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                 _______________________
                                [__op0_high_|__op0_low__]
                                 _______________________
-        *                          [__op1_high_|__op1_low__]
+        *                      [__op1_high_|__op1_low__]
         _______________________________________________
                                 _______________________
-    (1)                            [__op0_low__*__op1_low__]
+    (1)                                [__op0_low__*__op1_low__]
                     _______________________
-    (2a)               [__op0_low__*__op1_high_]
+    (2a)           [__op0_low__*__op1_high_]
                     _______________________
-    (2b)               [__op0_high_*__op1_low__]
+    (2b)           [__op0_high_*__op1_low__]
          _______________________
     (3) [__op0_high_*__op1_high_]
 
@@ -723,7 +1050,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       /* If the target is the same as one of the inputs, don't use it.  This
         prevents problems with the REG_EQUAL note.  */
-      if (target == op0 || target == op1)
+      if (target == op0 || target == op1
+         || (target != 0 && GET_CODE (target) != REG))
        target = 0;
 
       /* Multiply the two lower words to get a double-word product.
@@ -750,33 +1078,33 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
                                  target, 1, OPTAB_DIRECT);
          op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
-                                   NULL_RTX, 1, OPTAB_DIRECT);
+                                   NULL_RTX, 1, next_methods);
          if (op0_xhigh)
            op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
-                                     op0_xhigh, op0_xhigh, 0, OPTAB_DIRECT);
+                                     op0_xhigh, op0_xhigh, 0, next_methods);
          else
            {
              op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
-                                       NULL_RTX, 0, OPTAB_DIRECT);
+                                       NULL_RTX, 0, next_methods);
              if (op0_xhigh)
                op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
                                          op0_xhigh, op0_xhigh, 0,
-                                         OPTAB_DIRECT);
+                                         next_methods);
            }
 
          op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
-                                   NULL_RTX, 1, OPTAB_DIRECT);
+                                   NULL_RTX, 1, next_methods);
          if (op1_xhigh)
            op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
-                                     op1_xhigh, op1_xhigh, 0, OPTAB_DIRECT);
+                                     op1_xhigh, op1_xhigh, 0, next_methods);
          else
            {
              op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
-                                       NULL_RTX, 0, OPTAB_DIRECT);
+                                       NULL_RTX, 0, next_methods);
              if (op1_xhigh)
                op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
                                          op1_xhigh, op1_xhigh, 0,
-                                         OPTAB_DIRECT);
+                                         next_methods);
            }
        }
 
@@ -792,31 +1120,35 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       if (product && op0_xhigh && op1_xhigh)
        {
-         rtx product_piece;
          rtx product_high = operand_subword (product, high, 1, mode);
          rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
                                   NULL_RTX, 0, OPTAB_DIRECT);
 
-         if (temp)
-           {
-             product_piece = expand_binop (word_mode, add_optab, temp,
-                                           product_high, product_high,
-                                           0, OPTAB_LIB_WIDEN);
-             if (product_piece != product_high)
-               emit_move_insn (product_high, product_piece);
+         if (temp != 0)
+           temp = expand_binop (word_mode, add_optab, temp, product_high,
+                                product_high, 0, next_methods);
 
-             temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 
-                                  NULL_RTX, 0, OPTAB_DIRECT);
+         if (temp != 0 && temp != product_high)
+           emit_move_insn (product_high, temp);
+
+         if (temp != 0)
+           temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh, 
+                                NULL_RTX, 0, OPTAB_DIRECT);
+
+         if (temp != 0)
+           temp = expand_binop (word_mode, add_optab, temp,
+                                product_high, product_high,
+                                0, next_methods);
 
-             product_piece = expand_binop (word_mode, add_optab, temp,
-                                           product_high, product_high,
-                                           0, OPTAB_LIB_WIDEN);
-             if (product_piece != product_high)
-               emit_move_insn (product_high, product_piece);
+         if (temp != 0 && temp != product_high)
+           emit_move_insn (product_high, temp);
 
+         if (temp != 0)
+           {
              temp = emit_move_insn (product, product);
              REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
-                                         gen_rtx (MULT, mode, op0, op1),
+                                         gen_rtx (MULT, mode, copy_rtx (op0),
+                                                  copy_rtx (op1)),
                                          REG_NOTES (temp));
 
              return product;
@@ -840,15 +1172,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
   if (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT)
     {
-      rtx real0 = (rtx) 0;
-      rtx imag0 = (rtx) 0;
-      rtx real1 = (rtx) 0;
-      rtx imag1 = (rtx) 0;
-      rtx realr;
-      rtx imagr;
-      rtx res;
+      rtx real0 = 0, imag0 = 0;
+      rtx real1 = 0, imag1 = 0;
+      rtx realr, imagr, res;
       rtx seq;
       rtx equiv_value;
+      int ok = 0;
 
       /* Find the correct mode for the real and imaginary parts */
       enum machine_mode submode
@@ -883,16 +1212,21 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       else
        real1 = op1;
 
-      if (! real0 || ! real1 || ! (imag0 || imag1))
+      if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
        abort ();
 
       switch (binoptab->code)
        {
        case PLUS:
+         /* (a+ib) + (c+id) = (a+c) + i(b+d) */
        case MINUS:
+         /* (a+ib) - (c+id) = (a-c) + i(b-d) */
          res = expand_binop (submode, binoptab, real0, real1,
                              realr, unsignedp, methods);
-         if (res != realr)
+
+         if (res == 0)
+           break;
+         else if (res != realr)
            emit_move_insn (realr, res);
 
          if (imag0 && imag1)
@@ -905,133 +1239,237 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else
            res = imag1;
 
-         if (res != imagr)
+         if (res == 0)
+           break;
+         else if (res != imagr)
            emit_move_insn (imagr, res);
+
+         ok = 1;
          break;
 
        case MULT:
          /* (a+ib) * (c+id) = (ac-bd) + i(ad+cb) */
 
-         res = expand_binop (submode, binoptab, real0, real1,
-                             realr, unsignedp, methods);
-
          if (imag0 && imag1)
            {
-             rtx temp =
-               expand_binop (submode, sub_optab, res,
-                             expand_binop (submode, binoptab, imag0, imag1,
-                                           0, unsignedp, methods),
-                             realr, unsignedp, methods);
+             rtx temp1, temp2;
+
+             /* Don't fetch these from memory more than once.  */
+             real0 = force_reg (submode, real0);
+             real1 = force_reg (submode, real1);
+             imag0 = force_reg (submode, imag0);
+             imag1 = force_reg (submode, imag1);
+
+             temp1 = expand_binop (submode, binoptab, real0, real1, NULL_RTX,
+                                   unsignedp, methods);
+
+             temp2 = expand_binop (submode, binoptab, imag0, imag1, NULL_RTX,
+                                   unsignedp, methods);
+
+             if (temp1 == 0 || temp2 == 0)
+               break;
+
+             res = expand_binop (submode, sub_optab, temp1, temp2,
+                                 realr, unsignedp, methods);
 
-             if (temp != realr)
-               emit_move_insn (realr, temp);
+             if (res == 0)
+               break;
+             else if (res != realr)
+               emit_move_insn (realr, res);
+
+             temp1 = expand_binop (submode, binoptab, real0, imag1,
+                                   NULL_RTX, unsignedp, methods);
+
+             temp2 = expand_binop (submode, binoptab, real1, imag0,
+                                   NULL_RTX, unsignedp, methods);
 
-             res = expand_binop (submode, add_optab,
-                                 expand_binop (submode, binoptab,
-                                               real0, imag1,
-                                               0, unsignedp, methods),
-                                 expand_binop (submode, binoptab,
-                                               real1, imag0,
-                                               0, unsignedp, methods),
+             if (temp1 == 0 || temp2 == 0)
+                 break;
+
+             res = expand_binop (submode, add_optab, temp1, temp2,
                                  imagr, unsignedp, methods);
-             if (res != imagr)
+
+             if (res == 0)
+               break;
+             else if (res != imagr)
                emit_move_insn (imagr, res);
+
+             ok = 1;
            }
          else
            {
-             if (res != realr)
+             /* Don't fetch these from memory more than once.  */
+             real0 = force_reg (submode, real0);
+             real1 = force_reg (submode, real1);
+
+             res = expand_binop (submode, binoptab, real0, real1,
+                                 realr, unsignedp, methods);
+             if (res == 0)
+               break;
+             else if (res != realr)
                emit_move_insn (realr, res);
 
-             if (imag0)
+             if (imag0 != 0)
                res = expand_binop (submode, binoptab,
                                    real1, imag0, imagr, unsignedp, methods);
              else
                res = expand_binop (submode, binoptab,
                                    real0, imag1, imagr, unsignedp, methods);
-             if (res != imagr)
+
+             if (res == 0)
+               break;
+             else if (res != imagr)
                emit_move_insn (imagr, res);
+
+             ok = 1;
            }
          break;
 
        case DIV:
-         /* (c+id)/(a+ib) == ((c+id)*(a-ib))/(a*a+b*b) */
+         /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
          
-         if (! imag1)
+         if (imag1 == 0)
            {
-             /* Simply divide the real and imaginary parts by `a' */
-             res = expand_binop (submode, binoptab, real0, real1,
-                                 realr, unsignedp, methods);
-             if (res != realr)
+             /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
+
+             /* Don't fetch these from memory more than once.  */
+             real1 = force_reg (submode, real1);
+
+             /* Simply divide the real and imaginary parts by `c' */
+             if (class == MODE_COMPLEX_FLOAT)
+               res = expand_binop (submode, binoptab, real0, real1,
+                                   realr, unsignedp, methods);
+             else
+               res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                                    real0, real1, realr, unsignedp);
+
+             if (res == 0)
+               break;
+             else if (res != realr)
                emit_move_insn (realr, res);
 
-             res = expand_binop (submode, binoptab, imag0, real1,
-                                 imagr, unsignedp, methods);
-             if (res != imagr)
+             if (class == MODE_COMPLEX_FLOAT)
+               res = expand_binop (submode, binoptab, imag0, real1,
+                                   imagr, unsignedp, methods);
+             else
+               res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                                    imag0, real1, imagr, unsignedp);
+
+             if (res == 0)
+               break;
+             else if (res != imagr)
                emit_move_insn (imagr, res);
-           }
-         else                  /* Divider is of complex type */
-           {                   /* X/(a+ib) */
 
-             rtx divider;
-             rtx real_t;
-             rtx imag_t;
+             ok = 1;
+           }
+         else
+           {
+             /* Divisor is of complex type:
+                X/(a+ib) */
+             rtx divisor;
+             rtx real_t, imag_t;
+             rtx lhs, rhs;
+             rtx temp1, temp2;
              
-             optab mulopt = unsignedp ? umul_widen_optab : smul_optab;
-
-             /* Divider: a*a + b*b */
-             divider = expand_binop (submode, add_optab,
-                                     expand_binop (submode, mulopt,
-                                                   real1, real1,
-                                                   0, unsignedp, methods),
-                                     expand_binop (submode, mulopt,
-                                                   imag1, imag1,
-                                                   0, unsignedp, methods),
-                                     0, unsignedp, methods);
-
-             if (! imag0)      /* ((c)(a-ib))/divider */
+             /* Don't fetch these from memory more than once.  */
+             real0 = force_reg (submode, real0);
+             real1 = force_reg (submode, real1);
+
+             if (imag0 != 0)
+               imag0 = force_reg (submode, imag0);
+
+             imag1 = force_reg (submode, imag1);
+
+             /* Divisor: c*c + d*d */
+             temp1 = expand_binop (submode, smul_optab, real1, real1,
+                                   NULL_RTX, unsignedp, methods);
+
+             temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+                                   NULL_RTX, unsignedp, methods);
+
+             if (temp1 == 0 || temp2 == 0)
+               break;
+
+             divisor = expand_binop (submode, add_optab, temp1, temp2,
+                                     NULL_RTX, unsignedp, methods);
+             if (divisor == 0)
+               break;
+
+             if (imag0 == 0)
                {
-                 /* Calculate the divident */
-                 real_t = expand_binop (submode, mulopt, real0, real1,
-                                        0, unsignedp, methods);
+                 /* ((a)(c-id))/divisor */
+                 /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */
+
+                 /* Calculate the dividend */
+                 real_t = expand_binop (submode, smul_optab, real0, real1,
+                                        NULL_RTX, unsignedp, methods);
                  
-                 imag_t
-                   = expand_unop (submode, neg_optab,
-                                  expand_binop (submode, mulopt, real0, imag1,
-                                                0, unsignedp, methods),
-                                  0, unsignedp);
+                 imag_t = expand_binop (submode, smul_optab, real0, imag1,
+                                        NULL_RTX, unsignedp, methods);
+
+                 if (real_t == 0 || imag_t == 0)
+                   break;
+
+                 imag_t = expand_unop (submode, neg_optab, imag_t,
+                                       NULL_RTX, unsignedp);
                }
-             else              /* ((c+id)(a-ib))/divider */
+             else
                {
-                 /* Calculate the divident */
-                 real_t = expand_binop (submode, add_optab,
-                                        expand_binop (submode, mulopt,
-                                                      real0, real1,
-                                                      0, unsignedp, methods),
-                                        expand_binop (submode, mulopt,
-                                                      imag0, imag1,
-                                                      0, unsignedp, methods),
-                                        0, unsignedp, methods);
+                 /* ((a+ib)(c-id))/divider */
+                 /* Calculate the dividend */
+                 temp1 = expand_binop (submode, smul_optab, real0, real1,
+                                       NULL_RTX, unsignedp, methods);
+
+                 temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+                                       NULL_RTX, unsignedp, methods);
+
+                 if (temp1 == 0 || temp2 == 0)
+                   break;
+
+                 real_t = expand_binop (submode, add_optab, temp1, temp2,
+                                        NULL_RTX, unsignedp, methods);
                  
-                 imag_t = expand_binop (submode, sub_optab,
-                                        expand_binop (submode, mulopt,
-                                                      real0, imag1,
-                                                      0, unsignedp, methods),
-                                        expand_binop (submode, mulopt,
-                                                      real1, imag0,
-                                                      0, unsignedp, methods),
-                                        0, unsignedp, methods);
+                 temp1 = expand_binop (submode, smul_optab, imag0, real1,
+                                       NULL_RTX, unsignedp, methods);
 
+                 temp2 = expand_binop (submode, smul_optab, real0, imag1,
+                                       NULL_RTX, unsignedp, methods);
+
+                 if (temp1 == 0 || temp2 == 0)
+                   break;
+
+                 imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+                                        NULL_RTX, unsignedp, methods);
+
+                 if (real_t == 0 || imag_t == 0)
+                   break;
                }
 
-             res = expand_binop (submode, binoptab, real_t, divider,
-                                 realr, unsignedp, methods);
-             if (res != realr)
+             if (class == MODE_COMPLEX_FLOAT)
+               res = expand_binop (submode, binoptab, real_t, divisor,
+                                   realr, unsignedp, methods);
+             else
+               res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                                    real_t, divisor, realr, unsignedp);
+
+             if (res == 0)
+               break;
+             else if (res != realr)
                emit_move_insn (realr, res);
 
-             res = expand_binop (submode, binoptab, imag_t, divider,
-                                 imagr, unsignedp, methods);
-             if (res != imagr)
+             if (class == MODE_COMPLEX_FLOAT)
+               res = expand_binop (submode, binoptab, imag_t, divisor,
+                                   imagr, unsignedp, methods);
+             else
+               res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                                    imag_t, divisor, imagr, unsignedp);
+
+             if (res == 0)
+               break;
+             else if (res != imagr)
                emit_move_insn (imagr, res);
+
+             ok = 1;
            }
          break;
          
@@ -1042,14 +1480,18 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       seq = get_insns ();
       end_sequence ();
 
-      if (binoptab->code != UNKNOWN)
-       equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
-      else
-       equiv_value = 0;
+      if (ok)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value
+             = gen_rtx (binoptab->code, mode, copy_rtx (op0), copy_rtx (op1));
+         else
+           equiv_value = 0;
          
-      emit_no_conflict_block (seq, target, op0, op1, equiv_value);
+         emit_no_conflict_block (seq, target, op0, op1, equiv_value);
       
-      return target;
+         return target;
+       }
     }
 
   /* It can't be open-coded in this mode.
@@ -1062,6 +1504,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       rtx funexp = binoptab->handlers[(int) mode].libfunc;
       rtx op1x = op1;
       enum machine_mode op1_mode = mode;
+      rtx value;
 
       start_sequence ();
 
@@ -1073,16 +1516,21 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          op1x = convert_to_mode (word_mode, op1, 1);
        }
 
+      if (GET_MODE (op0) != VOIDmode
+         && GET_MODE (op0) != mode)
+       op0 = convert_to_mode (mode, op0, unsignedp);
+
       /* Pass 1 for NO_QUEUE so we don't lose any increments
         if the libcall is cse'd or moved.  */
-      emit_library_call (binoptab->handlers[(int) mode].libfunc,
-                        1, mode, 2, op0, mode, op1x, op1_mode);
+      value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
+                                      NULL_RTX, 1, mode, 2,
+                                      op0, mode, op1x, op1_mode);
 
       insns = get_insns ();
       end_sequence ();
 
       target = gen_reg_rtx (mode);
-      emit_libcall_block (insns, target, hard_libcall_value (mode),
+      emit_libcall_block (insns, target, value,
                          gen_rtx (binoptab->code, mode, op0, op1));
 
       return target;
@@ -1123,39 +1571,21 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
              /* For certain integer operations, we need not actually extend
                 the narrow operands, as long as we will truncate
-                the results to the same narrowness.  Don't do this when
-                WIDER_MODE is wider than a word since a paradoxical SUBREG
-                isn't valid for such modes.  */
+                the results to the same narrowness.  */
 
              if ((binoptab == ior_optab || binoptab == and_optab
                   || binoptab == xor_optab
                   || binoptab == add_optab || binoptab == sub_optab
-                  || binoptab == smul_optab
-                  || binoptab == ashl_optab || binoptab == lshl_optab)
-                 && class == MODE_INT
-                 && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD)
+                  || binoptab == smul_optab || binoptab == ashl_optab)
+                 && class == MODE_INT)
                no_extend = 1;
 
-             /* If an operand is a constant integer, we might as well
-                convert it since that is more efficient than using a SUBREG,
-                unlike the case for other operands.  Similarly for
-                SUBREGs that were made due to promoted objects.*/
-
-             if (no_extend && GET_MODE (xop0) != VOIDmode
-               && ! (GET_CODE (xop0) == SUBREG
-                     && SUBREG_PROMOTED_VAR_P (xop0)))
-               xop0 = gen_rtx (SUBREG, wider_mode,
-                               force_reg (GET_MODE (xop0), xop0), 0);
-             else
-               xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+             xop0 = widen_operand (xop0, wider_mode, mode,
+                                   unsignedp, no_extend);
 
-             if (no_extend && GET_MODE (xop1) != VOIDmode
-               && ! (GET_CODE (xop1) == SUBREG
-                     && SUBREG_PROMOTED_VAR_P (xop1)))
-               xop1 = gen_rtx (SUBREG, wider_mode,
-                               force_reg (GET_MODE (xop1), xop1), 0);
-             else
-               xop1 = convert_to_mode (wider_mode, xop1, unsignedp);
+             /* The second operand of a shift must always be extended.  */
+             xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
+                                   no_extend && binoptab != ashl_optab);
 
              temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
                                   unsignedp, methods);
@@ -1349,10 +1779,10 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
              register rtx t1 = gen_reg_rtx (wider_mode);
 
              if (expand_twoval_binop (binoptab,
-                                      convert_to_mode (wider_mode, op0,
-                                                       unsignedp),
-                                      convert_to_mode (wider_mode, op1,
-                                                       unsignedp),
+                                      convert_modes (wider_mode, mode, op0,
+                                                     unsignedp),
+                                      convert_modes (wider_mode, mode, op1,
+                                                     unsignedp),
                                       t0, t1, unsignedp))
                {
                  convert_move (targ0, t0, unsignedp);
@@ -1459,17 +1889,12 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
            /* For certain operations, we need not actually extend
               the narrow operand, as long as we will truncate the
-              results to the same narrowness.  But it is faster to
-              convert a SUBREG due to mode promotion.  */
-
-           if ((unoptab == neg_optab || unoptab == one_cmpl_optab)
-               && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD
-               && class == MODE_INT
-               && ! (GET_CODE (xop0) == SUBREG
-                     && SUBREG_PROMOTED_VAR_P (xop0)))
-             xop0 = gen_rtx (SUBREG, wider_mode, force_reg (mode, xop0), 0);
-           else
-             xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+              results to the same narrowness.  */
+
+           xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
+                                 (unoptab == neg_optab
+                                  || unoptab == one_cmpl_optab)
+                                 && class == MODE_INT);
              
            temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                unsignedp);
@@ -1520,7 +1945,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       end_sequence ();
 
       emit_no_conflict_block (insns, target, op0, NULL_RTX,
-                             gen_rtx (unoptab->code, mode, op0));
+                             gen_rtx (unoptab->code, mode, copy_rtx (op0)));
       return target;
     }
 
@@ -1564,7 +1989,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       end_sequence ();
 
       emit_no_conflict_block (seq, target, op0, 0,
-                             gen_rtx (unoptab->code, mode, op0));
+                             gen_rtx (unoptab->code, mode, copy_rtx (op0)));
       return target;
     }
 
@@ -1573,18 +1998,19 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
     {
       rtx insns;
       rtx funexp = unoptab->handlers[(int) mode].libfunc;
+      rtx value;
 
       start_sequence ();
 
       /* Pass 1 for NO_QUEUE so we don't lose any increments
         if the libcall is cse'd or moved.  */
-      emit_library_call (unoptab->handlers[(int) mode].libfunc,
-                        1, mode, 1, op0, mode);
+      value = emit_library_call_value (unoptab->handlers[(int) mode].libfunc,
+                                      NULL_RTX, 1, mode, 1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
       target = gen_reg_rtx (mode);
-      emit_libcall_block (insns, target, hard_libcall_value (mode),
+      emit_libcall_block (insns, target, value,
                          gen_rtx (unoptab->code, mode, op0));
 
       return target;
@@ -1607,14 +2033,10 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
                 the narrow operand, as long as we will truncate the
                 results to the same narrowness.  */
 
-             if ((unoptab == neg_optab || unoptab == one_cmpl_optab)
-                 && GET_MODE_SIZE (wider_mode) <= UNITS_PER_WORD
-                 && class == MODE_INT
-                 && ! (GET_CODE (xop0) == SUBREG
-                       && SUBREG_PROMOTED_VAR_P (xop0)))
-               xop0 = gen_rtx (SUBREG, wider_mode, force_reg (mode, xop0), 0);
-             else
-               xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+             xop0 = widen_operand (xop0, wider_mode, mode, unsignedp,
+                                   (unoptab == neg_optab
+                                    || unoptab == one_cmpl_optab)
+                                   && class == MODE_INT);
              
              temp = expand_unop (wider_mode, unoptab, xop0, NULL_RTX,
                                  unsignedp);
@@ -1637,6 +2059,17 @@ 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 == neg_optab)
+    {    
+      rtx temp;
+      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
+                          target, unsignedp, OPTAB_LIB_WIDEN);
+      if (temp)
+       return temp;
+    }
+      
   return 0;
 }
 \f
@@ -1647,42 +2080,126 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
    MODE is the mode of the operand; the mode of the result is
    different but can be deduced from MODE.
 
-   UNSIGNEDP is relevant for complex integer modes.  */
+   UNSIGNEDP is relevant if extension is needed.  */
 
 rtx
-expand_complex_abs (mode, op0, target, unsignedp)
+expand_abs (mode, op0, target, unsignedp, safe)
      enum machine_mode mode;
      rtx op0;
      rtx target;
      int unsignedp;
+     int safe;
 {
-  enum mode_class class = GET_MODE_CLASS (mode);
-  enum machine_mode wider_mode;
-  register rtx temp;
-  rtx entry_last = get_last_insn ();
-  rtx last;
-  rtx pat;
-
-  /* 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);
+  rtx temp, op1;
 
-  if (submode == BLKmode)
-    abort ();
+  /* First try to do it with a special abs instruction.  */
+  temp = expand_unop (mode, abs_optab, op0, target, 0);
+  if (temp != 0)
+    return temp;
 
-  op0 = protect_from_queue (op0, 0);
+  /* If this machine has expensive jumps, we can do integer absolute
+     value of X as (((signed) x >> (W-1)) ^ x) - ((signed) x >> (W-1)),
+     where W is the width of MODE.  */
 
-  if (flag_force_mem)
+  if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
     {
-      op0 = force_not_mem (op0);
+      rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
+                                  size_int (GET_MODE_BITSIZE (mode) - 1),
+                                  NULL_RTX, 0);
+
+      temp = expand_binop (mode, xor_optab, extended, op0, target, 0,
+                          OPTAB_LIB_WIDEN);
+      if (temp != 0)
+       temp = expand_binop (mode, sub_optab, temp, extended, target, 0,
+                            OPTAB_LIB_WIDEN);
+
+      if (temp != 0)
+       return temp;
     }
 
-  last = get_last_insn ();
-
-  if (target)
-    target = protect_from_queue (target, 1);
+  /* If that does not win, use conditional jump and negate.  */
+  op1 = gen_label_rtx ();
+  if (target == 0 || ! safe
+      || GET_MODE (target) != mode
+      || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))
+      || (GET_CODE (target) == REG
+         && REGNO (target) < FIRST_PSEUDO_REGISTER))
+    target = gen_reg_rtx (mode);
+
+  emit_move_insn (target, op0);
+  NO_DEFER_POP;
+
+  /* If this mode is an integer too wide to compare properly,
+     compare word by word.  Rely on CSE to optimize constant cases.  */
+  if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (mode))
+    do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 
+                                 NULL_RTX, op1);
+  else
+    {
+      temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
+                              NULL_RTX, 0);
+      if (temp == const1_rtx)
+       return target;
+      else if (temp != const0_rtx)
+       {
+         if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
+           emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
+         else
+           abort ();
+       }
+    }
+
+  op0 = expand_unop (mode, neg_optab, target, target, 0);
+  if (op0 != target)
+    emit_move_insn (target, op0);
+  emit_label (op1);
+  OK_DEFER_POP;
+  return target;
+}
+\f
+/* Emit code to compute the absolute value of OP0, with result to
+   TARGET if convenient.  (TARGET may be 0.)  The return value says
+   where the result actually is to be found.
+
+   MODE is the mode of the operand; the mode of the result is
+   different but can be deduced from MODE.
+
+   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;
+{
+  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode wider_mode;
+  register rtx temp;
+  rtx entry_last = get_last_insn ();
+  rtx last;
+  rtx pat;
+
+  /* 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);
+
+  if (submode == BLKmode)
+    abort ();
+
+  op0 = protect_from_queue (op0, 0);
+
+  if (flag_force_mem)
+    {
+      op0 = force_not_mem (op0);
+    }
+
+  last = get_last_insn ();
+
+  if (target)
+    target = protect_from_queue (target, 1);
 
   if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
@@ -1734,7 +2251,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
        {
          rtx xop0 = op0;
 
-         xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+         xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
          temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
 
          if (temp)
@@ -1762,12 +2279,15 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
       real = gen_realpart (submode, op0);
       imag = gen_imagpart (submode, op0);
+
       /* Square both parts.  */
-      real = expand_mult (mode, real, real, NULL_RTX, 0);
-      imag = expand_mult (mode, imag, imag, NULL_RTX, 0);
+      real = expand_mult (submode, real, real, NULL_RTX, 0);
+      imag = expand_mult (submode, imag, imag, NULL_RTX, 0);
+
       /* Sum the parts.  */
-      total = expand_binop (submode, add_optab, real, imag, 0,
+      total = expand_binop (submode, add_optab, real, imag, NULL_RTX,
                            0, OPTAB_LIB_WIDEN);
+
       /* Get sqrt in TARGET.  Set TARGET to where the result is.  */
       target = expand_unop (submode, sqrt_optab, total, target, 0);
       if (target == 0)
@@ -1781,18 +2301,19 @@ expand_complex_abs (mode, op0, target, unsignedp)
     {
       rtx insns;
       rtx funexp = abs_optab->handlers[(int) mode].libfunc;
+      rtx value;
 
       start_sequence ();
 
       /* Pass 1 for NO_QUEUE so we don't lose any increments
         if the libcall is cse'd or moved.  */
-      emit_library_call (abs_optab->handlers[(int) mode].libfunc,
-                        1, mode, 1, op0, mode);
+      value = emit_library_call_value (abs_optab->handlers[(int) mode].libfunc,
+                                      NULL_RTX, 1, submode, 1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
       target = gen_reg_rtx (submode);
-      emit_libcall_block (insns, target, hard_libcall_value (submode),
+      emit_libcall_block (insns, target, value,
                          gen_rtx (abs_optab->code, mode, op0));
 
       return target;
@@ -1809,7 +2330,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
        {
          rtx xop0 = op0;
 
-         xop0 = convert_to_mode (wider_mode, xop0, unsignedp);
+         xop0 = convert_modes (wider_mode, mode, xop0, unsignedp);
 
          temp = expand_complex_abs (wider_mode, xop0, NULL_RTX, unsignedp);
 
@@ -1855,7 +2376,9 @@ emit_unop_insn (icode, target, op0, code)
 
   op0 = protect_from_queue (op0, 0);
 
-  if (flag_force_mem)
+  /* Sign extension from memory is often done specially on RISC
+     machines, so forcing into a register here can pessimize code.  */
+  if (flag_force_mem && code != SIGN_EXTEND)
     op0 = force_not_mem (op0);
 
   /* Now, if insn does not accept our operands, put them into pseudos.  */
@@ -1892,9 +2415,7 @@ 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.  Only
-   INSNs are allowed in the block; no library calls or jumps may be
-   present.
+   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.
@@ -1903,7 +2424,8 @@ emit_unop_insn (icode, target, op0, code)
    on the last insn.
 
    If TARGET is not a register, INSNS is simply emitted with no special
-   processing.
+   processing.  Likewise if anything in INSNS is not an INSN or if
+   there is a libcall block inside INSNS.
 
    The final insn emitted is returned.  */
 
@@ -1918,6 +2440,11 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
 
   if (GET_CODE (target) != REG || reload_in_progress)
     return emit_insns (insns);
+  else
+    for (insn = insns; insn; insn = NEXT_INSN (insn))
+      if (GET_CODE (insn) != INSN
+         || find_reg_note (insn, REG_LIBCALL, NULL_RTX))
+       return emit_insns (insns);
 
   /* First emit all insns that do not store into words of the output and remove
      these from the list.  */
@@ -1928,9 +2455,6 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
 
       next = NEXT_INSN (insn);
 
-      if (GET_CODE (insn) != INSN)
-       abort ();
-
       if (GET_CODE (PATTERN (insn)) == SET)
        set = PATTERN (insn);
       else if (GET_CODE (PATTERN (insn)) == PARALLEL)
@@ -1981,9 +2505,16 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
                                    REG_NOTES (insn));
     }
 
-  last = emit_move_insn (target, target);
-  if (equiv)
-    REG_NOTES (last) = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last));
+  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
+      != CODE_FOR_nothing)
+    {
+      last = emit_move_insn (target, target);
+      if (equiv)
+       REG_NOTES (last)
+         = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last));
+    }
+  else
+    last = get_last_insn ();
 
   if (prev == 0)
     first = get_insns ();
@@ -2033,9 +2564,10 @@ emit_libcall_block (insns, target, result, equiv)
   rtx prev, next, first, last, insn;
 
   /* First emit all insns that set pseudos.  Remove them from the list as
-     we go.  Avoid insns that set pseudo which were referenced in previous
+     we go.  Avoid insns that set pseudos which were referenced in previous
      insns.  These can be generated by move_by_pieces, for example,
-     to update an address.  */
+     to update an address.  Similarly, avoid insns that reference things
+     set in previous insns.  */
 
   for (insn = insns; insn; insn = next)
     {
@@ -2047,7 +2579,9 @@ emit_libcall_block (insns, target, result, equiv)
          && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
          && (insn == insns
              || (! reg_mentioned_p (SET_DEST (set), PATTERN (insns))
-                 && ! reg_used_between_p (SET_DEST (set), insns, insn))))
+                 && ! reg_used_between_p (SET_DEST (set), insns, insn)
+                 && ! modified_in_p (SET_SRC (set), insns)
+                 && ! modified_between_p (SET_SRC (set), insns, insn))))
        {
          if (PREV_INSN (insn))
            NEXT_INSN (PREV_INSN (insn)) = next;
@@ -2073,7 +2607,8 @@ emit_libcall_block (insns, target, result, equiv)
     }
 
   last = emit_move_insn (target, result);
-  REG_NOTES (last) = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last));
+  REG_NOTES (last) = gen_rtx (EXPR_LIST,
+                             REG_EQUAL, copy_rtx (equiv), REG_NOTES (last));
 
   if (prev == 0)
     first = get_insns ();
@@ -2210,18 +2745,32 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
       else
 #endif
        {
+         rtx result;
+
 #ifdef TARGET_MEM_FUNCTIONS
          emit_library_call (memcmp_libfunc, 0,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
-                            size, Pmode);
+                            convert_to_mode (TYPE_MODE (sizetype), size,
+                                             TREE_UNSIGNED (sizetype)),
+                            TYPE_MODE (sizetype));
 #else
          emit_library_call (bcmp_libfunc, 0,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
-                            size, Pmode);
-#endif
-         emit_cmp_insn (hard_libcall_value (TYPE_MODE (integer_type_node)),
+                            convert_to_mode (TYPE_MODE (integer_type_node),
+                                             size,
+                                             TREE_UNSIGNED (integer_type_node)),
+                            TYPE_MODE (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));
+         emit_move_insn (result,
+                         hard_libcall_value (TYPE_MODE (integer_type_node)));
+         emit_cmp_insn (result,
                         const0_rtx, comparison, NULL_RTX,
                         TYPE_MODE (integer_type_node), 0, 0);
        }
@@ -2283,8 +2832,8 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
            {
              x = protect_from_queue (x, 0);
              y = protect_from_queue (y, 0);
-             x = convert_to_mode (wider_mode, x, unsignedp);
-             y = convert_to_mode (wider_mode, y, unsignedp);
+             x = convert_modes (wider_mode, mode, x, unsignedp);
+             y = convert_modes (wider_mode, mode, y, unsignedp);
              emit_cmp_insn (x, y, comparison, NULL_RTX,
                             wider_mode, unsignedp, align);
              return;
@@ -2298,20 +2847,27 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
       && class != MODE_FLOAT)
     {
       rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
+      rtx result;
+
       /* If we want unsigned, and this mode has a distinct unsigned
         comparison routine, use that.  */
       if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
        libfunc = ucmp_optab->handlers[(int) mode].libfunc;
 
       emit_library_call (libfunc, 1,
-                        SImode, 2, x, mode, y, mode);
+                        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));
 
       /* Integer comparison returns a result that must be compared against 1,
         so that even if we do an unsigned compare afterward,
         there is still a value that can represent the result "less than".  */
-
-      emit_cmp_insn (hard_libcall_value (SImode), const1_rtx,
-                    comparison, NULL_RTX, SImode, unsignedp, 0);
+      emit_cmp_insn (result, const1_rtx,
+                    comparison, NULL_RTX, word_mode, unsignedp, 0);
       return;
     }
 
@@ -2342,15 +2898,43 @@ can_compare_p (mode)
 /* Emit a library call comparison between floating point X and Y.
    COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  */
 
-static void
+void
 emit_float_lib_cmp (x, y, comparison)
      rtx x, y;
      enum rtx_code comparison;
 {
   enum machine_mode mode = GET_MODE (x);
-  rtx libfunc;
+  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;
+       break;
+
+      case GE:
+       libfunc = gehf2_libfunc;
+       break;
+
+      case LT:
+       libfunc = lthf2_libfunc;
+       break;
 
-  if (mode == SFmode)
+      case LE:
+       libfunc = lehf2_libfunc;
+       break;
+      }
+  else if (mode == SFmode)
     switch (comparison)
       {
       case EQ:
@@ -2480,11 +3064,20 @@ emit_float_lib_cmp (x, y, comparison)
       abort ();
     }
 
+  if (libfunc == 0)
+    abort ();
+
   emit_library_call (libfunc, 1,
-                    SImode, 2, x, mode, y, mode);
+                    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));
 
-  emit_cmp_insn (hard_libcall_value (SImode), const0_rtx, comparison,
-                NULL_RTX, SImode, 0, 0);
+  emit_cmp_insn (result, const0_rtx, comparison,
+                NULL_RTX, word_mode, 0, 0);
 }
 \f
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
@@ -2494,14 +3087,155 @@ emit_indirect_jump (loc)
      rtx loc;
 {
   if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0])
-        (loc, VOIDmode)))
-    loc = copy_to_mode_reg (insn_operand_mode[(int)CODE_FOR_indirect_jump][0],
-                           loc);
+        (loc, Pmode)))
+    loc = copy_to_mode_reg (Pmode, loc);
 
   emit_jump_insn (gen_indirect_jump (loc));
   emit_barrier ();
 }
 \f
+#ifdef HAVE_conditional_move
+
+/* Emit a conditional move 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 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_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;
+{
+  rtx tem, subtarget, comparison, insn;
+  enum insn_code icode;
+
+  /* If one operand is constant, make it the second one.  Only do this
+     if the other operand is not constant as well.  */
+
+  if ((CONSTANT_P (op0) && ! CONSTANT_P (op1))
+      || (GET_CODE (op0) == CONST_INT && GET_CODE (op1) != CONST_INT))
+    {
+      tem = op0;
+      op0 = op1;
+      op1 = tem;
+      code = swap_condition (code);
+    }
+
+  if (cmode == VOIDmode)
+    cmode = GET_MODE (op0);
+
+  if ((CONSTANT_P (op2) && ! CONSTANT_P (op3))
+      || (GET_CODE (op2) == CONST_INT && GET_CODE (op3) != CONST_INT))
+    {
+      tem = op2;
+      op2 = op3;
+      op3 = tem;
+      /* ??? This may not be appropriate (consider IEEE).  Perhaps we should
+        call can_reverse_comparison_p here and bail out if necessary.
+        It's not clear whether we need to do this canonicalization though.  */
+      code = reverse_condition (code);
+    }
+
+  if (mode == VOIDmode)
+    mode = GET_MODE (op2);
+
+  icode = movcc_gen_code[mode];
+
+  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_operand_predicate[icode][0])
+      (subtarget, insn_operand_mode[icode][0]))
+    subtarget = gen_reg_rtx (insn_operand_mode[icode][0]);
+
+  if (! (*insn_operand_predicate[icode][2])
+      (op2, insn_operand_mode[icode][2]))
+    op2 = copy_to_mode_reg (insn_operand_mode[icode][2], op2);
+
+  if (! (*insn_operand_predicate[icode][3])
+      (op3, insn_operand_mode[icode][3]))
+    op3 = copy_to_mode_reg (insn_operand_mode[icode][3], 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, 0);
+
+  /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
+  if (GET_CODE (comparison) != code)
+    /* This shouldn't happen.  */
+    abort ();
+  
+  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;
+}
+
+/* Return non-zero 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
+   guess wrong we lose a bit on optimization, but that's it.  */
+/* ??? sparc64 supports conditionally moving integers values based on fp
+   comparisons, and vice versa.  How do we handle them?  */
+
+int
+can_conditionally_move_p (mode)
+     enum machine_mode mode;
+{
+  if (movcc_gen_code[mode] != CODE_FOR_nothing)
+    return 1;
+
+  return 0;
+}
+
+#endif /* HAVE_conditional_move */
+\f
 /* These three functions generate an insn body and return it
    rather than emitting the insn.
 
@@ -2555,7 +3289,8 @@ have_sub2_insn (mode)
   return sub_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing;
 }
 
-/* Generate the body of an instruction to copy Y into X.  */
+/* Generate the body of an instruction to copy Y into X.
+   It may be a SEQUENCE, if one insn isn't enough.  */
 
 rtx
 gen_move_insn (x, y)
@@ -2563,6 +3298,7 @@ gen_move_insn (x, y)
 {
   register enum machine_mode mode = GET_MODE (x);
   enum insn_code insn_code;
+  rtx seq;
 
   if (mode == VOIDmode)
     mode = GET_MODE (y); 
@@ -2573,15 +3309,15 @@ gen_move_insn (x, y)
      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 (insn_code == CODE_FOR_nothing)
+  if (GET_MODE_CLASS (mode) == MODE_CC && insn_code == CODE_FOR_nothing)
     {
       enum machine_mode tmode = VOIDmode;
       rtx x1 = x, y1 = y;
 
-      if (GET_MODE_CLASS (mode) == MODE_CC && mode != CCmode
+      if (mode != CCmode
          && mov_optab->handlers[(int) CCmode].insn_code != CODE_FOR_nothing)
        tmode = CCmode;
-      else if (GET_MODE_CLASS (mode) == MODE_CC)
+      else
        for (tmode = QImode; tmode != VOIDmode;
             tmode = GET_MODE_WIDER_MODE (tmode))
          if (GET_MODE_SIZE (tmode) == GET_MODE_SIZE (mode))
@@ -2626,14 +3362,16 @@ gen_move_insn (x, y)
        }
          
       insn_code = mov_optab->handlers[(int) tmode].insn_code;
+      return (GEN_FCN (insn_code) (x, y));
     }
 
-  return (GEN_FCN (insn_code) (x, y));
+  start_sequence ();
+  emit_move_insn_1 (x, y);
+  seq = gen_sequence ();
+  end_sequence ();
+  return seq;
 }
 \f
-/* Tables of patterns for extending one integer mode to another.  */
-static enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
-
 /* Return the insn code used to extend FROM_MODE to TO_MODE.
    UNSIGNEDP specifies zero-extension instead of sign-extension.  If
    no such operation exists, CODE_FOR_nothing will be returned.  */
@@ -2657,111 +3395,14 @@ gen_extend_insn (x, y, mto, mfrom, unsignedp)
 {
   return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp]) (x, y));
 }
-
-static void
-init_extends ()
-{
-  enum insn_code *p;
-
-  for (p = extendtab[0][0];
-       p < extendtab[0][0] + sizeof extendtab / sizeof extendtab[0][0][0];
-       p++)
-    *p = CODE_FOR_nothing;
-
-#ifdef HAVE_extendditi2
-  if (HAVE_extendditi2)
-    extendtab[(int) TImode][(int) DImode][0] = CODE_FOR_extendditi2;
-#endif
-#ifdef HAVE_extendsiti2
-  if (HAVE_extendsiti2)
-    extendtab[(int) TImode][(int) SImode][0] = CODE_FOR_extendsiti2;
-#endif
-#ifdef HAVE_extendhiti2
-  if (HAVE_extendhiti2)
-    extendtab[(int) TImode][(int) HImode][0] = CODE_FOR_extendhiti2;
-#endif
-#ifdef HAVE_extendqiti2
-  if (HAVE_extendqiti2)
-    extendtab[(int) TImode][(int) QImode][0] = CODE_FOR_extendqiti2;
-#endif
-#ifdef HAVE_extendsidi2
-  if (HAVE_extendsidi2)
-    extendtab[(int) DImode][(int) SImode][0] = CODE_FOR_extendsidi2;
-#endif
-#ifdef HAVE_extendhidi2
-  if (HAVE_extendhidi2)
-    extendtab[(int) DImode][(int) HImode][0] = CODE_FOR_extendhidi2;
-#endif
-#ifdef HAVE_extendqidi2
-  if (HAVE_extendqidi2)
-    extendtab[(int) DImode][(int) QImode][0] = CODE_FOR_extendqidi2;
-#endif
-#ifdef HAVE_extendhisi2
-  if (HAVE_extendhisi2)
-    extendtab[(int) SImode][(int) HImode][0] = CODE_FOR_extendhisi2;
-#endif
-#ifdef HAVE_extendqisi2
-  if (HAVE_extendqisi2)
-    extendtab[(int) SImode][(int) QImode][0] = CODE_FOR_extendqisi2;
-#endif
-#ifdef HAVE_extendqihi2
-  if (HAVE_extendqihi2)
-    extendtab[(int) HImode][(int) QImode][0] = CODE_FOR_extendqihi2;
-#endif
-
-#ifdef HAVE_zero_extendditi2
-  if (HAVE_zero_extendsiti2)
-    extendtab[(int) TImode][(int) DImode][1] = CODE_FOR_zero_extendditi2;
-#endif
-#ifdef HAVE_zero_extendsiti2
-  if (HAVE_zero_extendsiti2)
-    extendtab[(int) TImode][(int) SImode][1] = CODE_FOR_zero_extendsiti2;
-#endif
-#ifdef HAVE_zero_extendhiti2
-  if (HAVE_zero_extendhiti2)
-    extendtab[(int) TImode][(int) HImode][1] = CODE_FOR_zero_extendhiti2;
-#endif
-#ifdef HAVE_zero_extendqiti2
-  if (HAVE_zero_extendqiti2)
-    extendtab[(int) TImode][(int) QImode][1] = CODE_FOR_zero_extendqiti2;
-#endif
-#ifdef HAVE_zero_extendsidi2
-  if (HAVE_zero_extendsidi2)
-    extendtab[(int) DImode][(int) SImode][1] = CODE_FOR_zero_extendsidi2;
-#endif
-#ifdef HAVE_zero_extendhidi2
-  if (HAVE_zero_extendhidi2)
-    extendtab[(int) DImode][(int) HImode][1] = CODE_FOR_zero_extendhidi2;
-#endif
-#ifdef HAVE_zero_extendqidi2
-  if (HAVE_zero_extendqidi2)
-    extendtab[(int) DImode][(int) QImode][1] = CODE_FOR_zero_extendqidi2;
-#endif
-#ifdef HAVE_zero_extendhisi2
-  if (HAVE_zero_extendhisi2)
-    extendtab[(int) SImode][(int) HImode][1] = CODE_FOR_zero_extendhisi2;
-#endif
-#ifdef HAVE_zero_extendqisi2
-  if (HAVE_zero_extendqisi2)
-    extendtab[(int) SImode][(int) QImode][1] = CODE_FOR_zero_extendqisi2;
-#endif
-#ifdef HAVE_zero_extendqihi2
-  if (HAVE_zero_extendqihi2)
-    extendtab[(int) HImode][(int) QImode][1] = CODE_FOR_zero_extendqihi2;
-#endif
-}
 \f
 /* can_fix_p and can_float_p say whether the target machine
    can directly convert a given fixed point type to
    a given floating point type, or vice versa.
    The returned value is the CODE_FOR_... value to use,
-   or CODE_FOR_nothing if these modes cannot be directly converted.  */
-
-static enum insn_code fixtab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-static enum insn_code fixtrunctab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
-static enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
+   or CODE_FOR_nothing if these modes cannot be directly converted.
 
-/* *TRUNCP_PTR is set to 1 if it is necessary to output
+   *TRUNCP_PTR is set to 1 if it is necessary to output
    an explicit FTRUNC insn before the fix insn; otherwise 0.  */
 
 static enum insn_code
@@ -2789,570 +3430,46 @@ can_float_p (fltmode, fixmode, unsignedp)
 {
   return floattab[(int) fltmode][(int) fixmode][unsignedp];
 }
+\f
+/* Generate code to convert FROM to floating point
+   and store in TO.  FROM must be fixed point and not VOIDmode.
+   UNSIGNEDP nonzero means regard FROM as unsigned.
+   Normally this is done by correcting the final value
+   if it is negative.  */
 
 void
-init_fixtab ()
+expand_float (to, from, unsignedp)
+     rtx to, from;
+     int unsignedp;
 {
-  enum insn_code *p;
-  for (p = fixtab[0][0];
-       p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
-  for (p = fixtrunctab[0][0];
-       p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
+  enum insn_code icode;
+  register rtx target = to;
+  enum machine_mode fmode, imode;
 
-#ifdef HAVE_fixsfqi2
-  if (HAVE_fixsfqi2)
-    fixtab[(int) SFmode][(int) QImode][0] = CODE_FOR_fixsfqi2;
-#endif
-#ifdef HAVE_fixsfhi2
-  if (HAVE_fixsfhi2)
-    fixtab[(int) SFmode][(int) HImode][0] = CODE_FOR_fixsfhi2;
-#endif
-#ifdef HAVE_fixsfsi2
-  if (HAVE_fixsfsi2)
-    fixtab[(int) SFmode][(int) SImode][0] = CODE_FOR_fixsfsi2;
-#endif
-#ifdef HAVE_fixsfdi2
-  if (HAVE_fixsfdi2)
-    fixtab[(int) SFmode][(int) DImode][0] = CODE_FOR_fixsfdi2;
-#endif
+  /* Crash now, because we won't be able to decide which mode to use.  */
+  if (GET_MODE (from) == VOIDmode)
+    abort ();
 
-#ifdef HAVE_fixdfqi2
-  if (HAVE_fixdfqi2)
-    fixtab[(int) DFmode][(int) QImode][0] = CODE_FOR_fixdfqi2;
-#endif
-#ifdef HAVE_fixdfhi2
-  if (HAVE_fixdfhi2)
-    fixtab[(int) DFmode][(int) HImode][0] = CODE_FOR_fixdfhi2;
-#endif
-#ifdef HAVE_fixdfsi2
-  if (HAVE_fixdfsi2)
-    fixtab[(int) DFmode][(int) SImode][0] = CODE_FOR_fixdfsi2;
-#endif
-#ifdef HAVE_fixdfdi2
-  if (HAVE_fixdfdi2)
-    fixtab[(int) DFmode][(int) DImode][0] = CODE_FOR_fixdfdi2;
-#endif
-#ifdef HAVE_fixdfti2
-  if (HAVE_fixdfti2)
-    fixtab[(int) DFmode][(int) TImode][0] = CODE_FOR_fixdfti2;
-#endif
+  /* Look for an insn to do the conversion.  Do it in the specified
+     modes if possible; otherwise convert either input, output or both to
+     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.  */
 
-#ifdef HAVE_fixxfqi2
-  if (HAVE_fixxfqi2)
-    fixtab[(int) XFmode][(int) QImode][0] = CODE_FOR_fixxfqi2;
-#endif
-#ifdef HAVE_fixxfhi2
-  if (HAVE_fixxfhi2)
-    fixtab[(int) XFmode][(int) HImode][0] = CODE_FOR_fixxfhi2;
-#endif
-#ifdef HAVE_fixxfsi2
-  if (HAVE_fixxfsi2)
-    fixtab[(int) XFmode][(int) SImode][0] = CODE_FOR_fixxfsi2;
-#endif
-#ifdef HAVE_fixxfdi2
-  if (HAVE_fixxfdi2)
-    fixtab[(int) XFmode][(int) DImode][0] = CODE_FOR_fixxfdi2;
-#endif
-#ifdef HAVE_fixxfti2
-  if (HAVE_fixxfti2)
-    fixtab[(int) XFmode][(int) TImode][0] = CODE_FOR_fixxfti2;
-#endif
+  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))
+      {
+       int doing_unsigned = unsignedp;
 
-#ifdef HAVE_fixtfqi2
-  if (HAVE_fixtfqi2)
-    fixtab[(int) TFmode][(int) QImode][0] = CODE_FOR_fixtfqi2;
-#endif
-#ifdef HAVE_fixtfhi2
-  if (HAVE_fixtfhi2)
-    fixtab[(int) TFmode][(int) HImode][0] = CODE_FOR_fixtfhi2;
-#endif
-#ifdef HAVE_fixtfsi2
-  if (HAVE_fixtfsi2)
-    fixtab[(int) TFmode][(int) SImode][0] = CODE_FOR_fixtfsi2;
-#endif
-#ifdef HAVE_fixtfdi2
-  if (HAVE_fixtfdi2)
-    fixtab[(int) TFmode][(int) DImode][0] = CODE_FOR_fixtfdi2;
-#endif
-#ifdef HAVE_fixtfti2
-  if (HAVE_fixtfti2)
-    fixtab[(int) TFmode][(int) TImode][0] = CODE_FOR_fixtfti2;
-#endif
+       icode = can_float_p (fmode, imode, unsignedp);
+       if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
+         icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
 
-#ifdef HAVE_fixunssfqi2
-  if (HAVE_fixunssfqi2)
-    fixtab[(int) SFmode][(int) QImode][1] = CODE_FOR_fixunssfqi2;
-#endif
-#ifdef HAVE_fixunssfhi2
-  if (HAVE_fixunssfhi2)
-    fixtab[(int) SFmode][(int) HImode][1] = CODE_FOR_fixunssfhi2;
-#endif
-#ifdef HAVE_fixunssfsi2
-  if (HAVE_fixunssfsi2)
-    fixtab[(int) SFmode][(int) SImode][1] = CODE_FOR_fixunssfsi2;
-#endif
-#ifdef HAVE_fixunssfdi2
-  if (HAVE_fixunssfdi2)
-    fixtab[(int) SFmode][(int) DImode][1] = CODE_FOR_fixunssfdi2;
-#endif
-
-#ifdef HAVE_fixunsdfqi2
-  if (HAVE_fixunsdfqi2)
-    fixtab[(int) DFmode][(int) QImode][1] = CODE_FOR_fixunsdfqi2;
-#endif
-#ifdef HAVE_fixunsdfhi2
-  if (HAVE_fixunsdfhi2)
-    fixtab[(int) DFmode][(int) HImode][1] = CODE_FOR_fixunsdfhi2;
-#endif
-#ifdef HAVE_fixunsdfsi2
-  if (HAVE_fixunsdfsi2)
-    fixtab[(int) DFmode][(int) SImode][1] = CODE_FOR_fixunsdfsi2;
-#endif
-#ifdef HAVE_fixunsdfdi2
-  if (HAVE_fixunsdfdi2)
-    fixtab[(int) DFmode][(int) DImode][1] = CODE_FOR_fixunsdfdi2;
-#endif
-#ifdef HAVE_fixunsdfti2
-  if (HAVE_fixunsdfti2)
-    fixtab[(int) DFmode][(int) TImode][1] = CODE_FOR_fixunsdfti2;
-#endif
-
-#ifdef HAVE_fixunsxfqi2
-  if (HAVE_fixunsxfqi2)
-    fixtab[(int) XFmode][(int) QImode][1] = CODE_FOR_fixunsxfqi2;
-#endif
-#ifdef HAVE_fixunsxfhi2
-  if (HAVE_fixunsxfhi2)
-    fixtab[(int) XFmode][(int) HImode][1] = CODE_FOR_fixunsxfhi2;
-#endif
-#ifdef HAVE_fixunsxfsi2
-  if (HAVE_fixunsxfsi2)
-    fixtab[(int) XFmode][(int) SImode][1] = CODE_FOR_fixunsxfsi2;
-#endif
-#ifdef HAVE_fixunsxfdi2
-  if (HAVE_fixunsxfdi2)
-    fixtab[(int) XFmode][(int) DImode][1] = CODE_FOR_fixunsxfdi2;
-#endif
-#ifdef HAVE_fixunsxfti2
-  if (HAVE_fixunsxfti2)
-    fixtab[(int) XFmode][(int) TImode][1] = CODE_FOR_fixunsxfti2;
-#endif
-
-#ifdef HAVE_fixunstfqi2
-  if (HAVE_fixunstfqi2)
-    fixtab[(int) TFmode][(int) QImode][1] = CODE_FOR_fixunstfqi2;
-#endif
-#ifdef HAVE_fixunstfhi2
-  if (HAVE_fixunstfhi2)
-    fixtab[(int) TFmode][(int) HImode][1] = CODE_FOR_fixunstfhi2;
-#endif
-#ifdef HAVE_fixunstfsi2
-  if (HAVE_fixunstfsi2)
-    fixtab[(int) TFmode][(int) SImode][1] = CODE_FOR_fixunstfsi2;
-#endif
-#ifdef HAVE_fixunstfdi2
-  if (HAVE_fixunstfdi2)
-    fixtab[(int) TFmode][(int) DImode][1] = CODE_FOR_fixunstfdi2;
-#endif
-#ifdef HAVE_fixunstfti2
-  if (HAVE_fixunstfti2)
-    fixtab[(int) TFmode][(int) TImode][1] = CODE_FOR_fixunstfti2;
-#endif
-
-#ifdef HAVE_fix_truncsfqi2
-  if (HAVE_fix_truncsfqi2)
-    fixtrunctab[(int) SFmode][(int) QImode][0] = CODE_FOR_fix_truncsfqi2;
-#endif
-#ifdef HAVE_fix_truncsfhi2
-  if (HAVE_fix_truncsfhi2)
-    fixtrunctab[(int) SFmode][(int) HImode][0] = CODE_FOR_fix_truncsfhi2;
-#endif
-#ifdef HAVE_fix_truncsfsi2
-  if (HAVE_fix_truncsfsi2)
-    fixtrunctab[(int) SFmode][(int) SImode][0] = CODE_FOR_fix_truncsfsi2;
-#endif
-#ifdef HAVE_fix_truncsfdi2
-  if (HAVE_fix_truncsfdi2)
-    fixtrunctab[(int) SFmode][(int) DImode][0] = CODE_FOR_fix_truncsfdi2;
-#endif
-
-#ifdef HAVE_fix_truncdfqi2
-  if (HAVE_fix_truncdfqi2)
-    fixtrunctab[(int) DFmode][(int) QImode][0] = CODE_FOR_fix_truncdfqi2;
-#endif
-#ifdef HAVE_fix_truncdfhi2
-  if (HAVE_fix_truncdfhi2)
-    fixtrunctab[(int) DFmode][(int) HImode][0] = CODE_FOR_fix_truncdfhi2;
-#endif
-#ifdef HAVE_fix_truncdfsi2
-  if (HAVE_fix_truncdfsi2)
-    fixtrunctab[(int) DFmode][(int) SImode][0] = CODE_FOR_fix_truncdfsi2;
-#endif
-#ifdef HAVE_fix_truncdfdi2
-  if (HAVE_fix_truncdfdi2)
-    fixtrunctab[(int) DFmode][(int) DImode][0] = CODE_FOR_fix_truncdfdi2;
-#endif
-#ifdef HAVE_fix_truncdfti2
-  if (HAVE_fix_truncdfti2)
-    fixtrunctab[(int) DFmode][(int) TImode][0] = CODE_FOR_fix_truncdfti2;
-#endif
-
-#ifdef HAVE_fix_truncxfqi2
-  if (HAVE_fix_truncxfqi2)
-    fixtrunctab[(int) XFmode][(int) QImode][0] = CODE_FOR_fix_truncxfqi2;
-#endif
-#ifdef HAVE_fix_truncxfhi2
-  if (HAVE_fix_truncxfhi2)
-    fixtrunctab[(int) XFmode][(int) HImode][0] = CODE_FOR_fix_truncxfhi2;
-#endif
-#ifdef HAVE_fix_truncxfsi2
-  if (HAVE_fix_truncxfsi2)
-    fixtrunctab[(int) XFmode][(int) SImode][0] = CODE_FOR_fix_truncxfsi2;
-#endif
-#ifdef HAVE_fix_truncxfdi2
-  if (HAVE_fix_truncxfdi2)
-    fixtrunctab[(int) XFmode][(int) DImode][0] = CODE_FOR_fix_truncxfdi2;
-#endif
-#ifdef HAVE_fix_truncxfti2
-  if (HAVE_fix_truncxfti2)
-    fixtrunctab[(int) XFmode][(int) TImode][0] = CODE_FOR_fix_truncxfti2;
-#endif
-
-#ifdef HAVE_fix_trunctfqi2
-  if (HAVE_fix_trunctfqi2)
-    fixtrunctab[(int) TFmode][(int) QImode][0] = CODE_FOR_fix_trunctfqi2;
-#endif
-#ifdef HAVE_fix_trunctfhi2
-  if (HAVE_fix_trunctfhi2)
-    fixtrunctab[(int) TFmode][(int) HImode][0] = CODE_FOR_fix_trunctfhi2;
-#endif
-#ifdef HAVE_fix_trunctfsi2
-  if (HAVE_fix_trunctfsi2)
-    fixtrunctab[(int) TFmode][(int) SImode][0] = CODE_FOR_fix_trunctfsi2;
-#endif
-#ifdef HAVE_fix_trunctfdi2
-  if (HAVE_fix_trunctfdi2)
-    fixtrunctab[(int) TFmode][(int) DImode][0] = CODE_FOR_fix_trunctfdi2;
-#endif
-#ifdef HAVE_fix_trunctfti2
-  if (HAVE_fix_trunctfti2)
-    fixtrunctab[(int) TFmode][(int) TImode][0] = CODE_FOR_fix_trunctfti2;
-#endif
-
-#ifdef HAVE_fixuns_truncsfqi2
-  if (HAVE_fixuns_truncsfqi2)
-    fixtrunctab[(int) SFmode][(int) QImode][1] = CODE_FOR_fixuns_truncsfqi2;
-#endif
-#ifdef HAVE_fixuns_truncsfhi2
-  if (HAVE_fixuns_truncsfhi2)
-    fixtrunctab[(int) SFmode][(int) HImode][1] = CODE_FOR_fixuns_truncsfhi2;
-#endif
-#ifdef HAVE_fixuns_truncsfsi2
-  if (HAVE_fixuns_truncsfsi2)
-    fixtrunctab[(int) SFmode][(int) SImode][1] = CODE_FOR_fixuns_truncsfsi2;
-#endif
-#ifdef HAVE_fixuns_truncsfdi2
-  if (HAVE_fixuns_truncsfdi2)
-    fixtrunctab[(int) SFmode][(int) DImode][1] = CODE_FOR_fixuns_truncsfdi2;
-#endif
-
-#ifdef HAVE_fixuns_truncdfqi2
-  if (HAVE_fixuns_truncdfqi2)
-    fixtrunctab[(int) DFmode][(int) QImode][1] = CODE_FOR_fixuns_truncdfqi2;
-#endif
-#ifdef HAVE_fixuns_truncdfhi2
-  if (HAVE_fixuns_truncdfhi2)
-    fixtrunctab[(int) DFmode][(int) HImode][1] = CODE_FOR_fixuns_truncdfhi2;
-#endif
-#ifdef HAVE_fixuns_truncdfsi2
-  if (HAVE_fixuns_truncdfsi2)
-    fixtrunctab[(int) DFmode][(int) SImode][1] = CODE_FOR_fixuns_truncdfsi2;
-#endif
-#ifdef HAVE_fixuns_truncdfdi2
-  if (HAVE_fixuns_truncdfdi2)
-    fixtrunctab[(int) DFmode][(int) DImode][1] = CODE_FOR_fixuns_truncdfdi2;
-#endif
-#ifdef HAVE_fixuns_truncdfti2
-  if (HAVE_fixuns_truncdfti2)
-    fixtrunctab[(int) DFmode][(int) TImode][1] = CODE_FOR_fixuns_truncdfti2;
-#endif
-
-#ifdef HAVE_fixuns_truncxfqi2
-  if (HAVE_fixuns_truncxfqi2)
-    fixtrunctab[(int) XFmode][(int) QImode][1] = CODE_FOR_fixuns_truncxfqi2;
-#endif
-#ifdef HAVE_fixuns_truncxfhi2
-  if (HAVE_fixuns_truncxfhi2)
-    fixtrunctab[(int) XFmode][(int) HImode][1] = CODE_FOR_fixuns_truncxfhi2;
-#endif
-#ifdef HAVE_fixuns_truncxfsi2
-  if (HAVE_fixuns_truncxfsi2)
-    fixtrunctab[(int) XFmode][(int) SImode][1] = CODE_FOR_fixuns_truncxfsi2;
-#endif
-#ifdef HAVE_fixuns_truncxfdi2
-  if (HAVE_fixuns_truncxfdi2)
-    fixtrunctab[(int) XFmode][(int) DImode][1] = CODE_FOR_fixuns_truncxfdi2;
-#endif
-#ifdef HAVE_fixuns_truncxfti2
-  if (HAVE_fixuns_truncxfti2)
-    fixtrunctab[(int) XFmode][(int) TImode][1] = CODE_FOR_fixuns_truncxfti2;
-#endif
-
-#ifdef HAVE_fixuns_trunctfqi2
-  if (HAVE_fixuns_trunctfqi2)
-    fixtrunctab[(int) TFmode][(int) QImode][1] = CODE_FOR_fixuns_trunctfqi2;
-#endif
-#ifdef HAVE_fixuns_trunctfhi2
-  if (HAVE_fixuns_trunctfhi2)
-    fixtrunctab[(int) TFmode][(int) HImode][1] = CODE_FOR_fixuns_trunctfhi2;
-#endif
-#ifdef HAVE_fixuns_trunctfsi2
-  if (HAVE_fixuns_trunctfsi2)
-    fixtrunctab[(int) TFmode][(int) SImode][1] = CODE_FOR_fixuns_trunctfsi2;
-#endif
-#ifdef HAVE_fixuns_trunctfdi2
-  if (HAVE_fixuns_trunctfdi2)
-    fixtrunctab[(int) TFmode][(int) DImode][1] = CODE_FOR_fixuns_trunctfdi2;
-#endif
-#ifdef HAVE_fixuns_trunctfti2
-  if (HAVE_fixuns_trunctfti2)
-    fixtrunctab[(int) TFmode][(int) TImode][1] = CODE_FOR_fixuns_trunctfti2;
-#endif
-
-#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.  */
-  {
-    int i;
-    int j;
-    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
-}
-
-void
-init_floattab ()
-{
-  enum insn_code *p;
-  for (p = floattab[0][0];
-       p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
-
-#ifdef HAVE_floatqisf2
-  if (HAVE_floatqisf2)
-    floattab[(int) SFmode][(int) QImode][0] = CODE_FOR_floatqisf2;
-#endif
-#ifdef HAVE_floathisf2
-  if (HAVE_floathisf2)
-    floattab[(int) SFmode][(int) HImode][0] = CODE_FOR_floathisf2;
-#endif
-#ifdef HAVE_floatsisf2
-  if (HAVE_floatsisf2)
-    floattab[(int) SFmode][(int) SImode][0] = CODE_FOR_floatsisf2;
-#endif
-#ifdef HAVE_floatdisf2
-  if (HAVE_floatdisf2)
-    floattab[(int) SFmode][(int) DImode][0] = CODE_FOR_floatdisf2;
-#endif
-#ifdef HAVE_floattisf2
-  if (HAVE_floattisf2)
-    floattab[(int) SFmode][(int) TImode][0] = CODE_FOR_floattisf2;
-#endif
-
-#ifdef HAVE_floatqidf2
-  if (HAVE_floatqidf2)
-    floattab[(int) DFmode][(int) QImode][0] = CODE_FOR_floatqidf2;
-#endif
-#ifdef HAVE_floathidf2
-  if (HAVE_floathidf2)
-    floattab[(int) DFmode][(int) HImode][0] = CODE_FOR_floathidf2;
-#endif
-#ifdef HAVE_floatsidf2
-  if (HAVE_floatsidf2)
-    floattab[(int) DFmode][(int) SImode][0] = CODE_FOR_floatsidf2;
-#endif
-#ifdef HAVE_floatdidf2
-  if (HAVE_floatdidf2)
-    floattab[(int) DFmode][(int) DImode][0] = CODE_FOR_floatdidf2;
-#endif
-#ifdef HAVE_floattidf2
-  if (HAVE_floattidf2)
-    floattab[(int) DFmode][(int) TImode][0] = CODE_FOR_floattidf2;
-#endif
-
-#ifdef HAVE_floatqixf2
-  if (HAVE_floatqixf2)
-    floattab[(int) XFmode][(int) QImode][0] = CODE_FOR_floatqixf2;
-#endif
-#ifdef HAVE_floathixf2
-  if (HAVE_floathixf2)
-    floattab[(int) XFmode][(int) HImode][0] = CODE_FOR_floathixf2;
-#endif
-#ifdef HAVE_floatsixf2
-  if (HAVE_floatsixf2)
-    floattab[(int) XFmode][(int) SImode][0] = CODE_FOR_floatsixf2;
-#endif
-#ifdef HAVE_floatdixf2
-  if (HAVE_floatdixf2)
-    floattab[(int) XFmode][(int) DImode][0] = CODE_FOR_floatdixf2;
-#endif
-#ifdef HAVE_floattixf2
-  if (HAVE_floattixf2)
-    floattab[(int) XFmode][(int) TImode][0] = CODE_FOR_floattixf2;
-#endif
-
-#ifdef HAVE_floatqitf2
-  if (HAVE_floatqitf2)
-    floattab[(int) TFmode][(int) QImode][0] = CODE_FOR_floatqitf2;
-#endif
-#ifdef HAVE_floathitf2
-  if (HAVE_floathitf2)
-    floattab[(int) TFmode][(int) HImode][0] = CODE_FOR_floathitf2;
-#endif
-#ifdef HAVE_floatsitf2
-  if (HAVE_floatsitf2)
-    floattab[(int) TFmode][(int) SImode][0] = CODE_FOR_floatsitf2;
-#endif
-#ifdef HAVE_floatditf2
-  if (HAVE_floatditf2)
-    floattab[(int) TFmode][(int) DImode][0] = CODE_FOR_floatditf2;
-#endif
-#ifdef HAVE_floattitf2
-  if (HAVE_floattitf2)
-    floattab[(int) TFmode][(int) TImode][0] = CODE_FOR_floattitf2;
-#endif
-
-#ifdef HAVE_floatunsqisf2
-  if (HAVE_floatunsqisf2)
-    floattab[(int) SFmode][(int) QImode][1] = CODE_FOR_floatunsqisf2;
-#endif
-#ifdef HAVE_floatunshisf2
-  if (HAVE_floatunshisf2)
-    floattab[(int) SFmode][(int) HImode][1] = CODE_FOR_floatunshisf2;
-#endif
-#ifdef HAVE_floatunssisf2
-  if (HAVE_floatunssisf2)
-    floattab[(int) SFmode][(int) SImode][1] = CODE_FOR_floatunssisf2;
-#endif
-#ifdef HAVE_floatunsdisf2
-  if (HAVE_floatunsdisf2)
-    floattab[(int) SFmode][(int) DImode][1] = CODE_FOR_floatunsdisf2;
-#endif
-#ifdef HAVE_floatunstisf2
-  if (HAVE_floatunstisf2)
-    floattab[(int) SFmode][(int) TImode][1] = CODE_FOR_floatunstisf2;
-#endif
-
-#ifdef HAVE_floatunsqidf2
-  if (HAVE_floatunsqidf2)
-    floattab[(int) DFmode][(int) QImode][1] = CODE_FOR_floatunsqidf2;
-#endif
-#ifdef HAVE_floatunshidf2
-  if (HAVE_floatunshidf2)
-    floattab[(int) DFmode][(int) HImode][1] = CODE_FOR_floatunshidf2;
-#endif
-#ifdef HAVE_floatunssidf2
-  if (HAVE_floatunssidf2)
-    floattab[(int) DFmode][(int) SImode][1] = CODE_FOR_floatunssidf2;
-#endif
-#ifdef HAVE_floatunsdidf2
-  if (HAVE_floatunsdidf2)
-    floattab[(int) DFmode][(int) DImode][1] = CODE_FOR_floatunsdidf2;
-#endif
-#ifdef HAVE_floatunstidf2
-  if (HAVE_floatunstidf2)
-    floattab[(int) DFmode][(int) TImode][1] = CODE_FOR_floatunstidf2;
-#endif
-
-#ifdef HAVE_floatunsqixf2
-  if (HAVE_floatunsqixf2)
-    floattab[(int) XFmode][(int) QImode][1] = CODE_FOR_floatunsqixf2;
-#endif
-#ifdef HAVE_floatunshixf2
-  if (HAVE_floatunshixf2)
-    floattab[(int) XFmode][(int) HImode][1] = CODE_FOR_floatunshixf2;
-#endif
-#ifdef HAVE_floatunssixf2
-  if (HAVE_floatunssixf2)
-    floattab[(int) XFmode][(int) SImode][1] = CODE_FOR_floatunssixf2;
-#endif
-#ifdef HAVE_floatunsdixf2
-  if (HAVE_floatunsdixf2)
-    floattab[(int) XFmode][(int) DImode][1] = CODE_FOR_floatunsdixf2;
-#endif
-#ifdef HAVE_floatunstixf2
-  if (HAVE_floatunstixf2)
-    floattab[(int) XFmode][(int) TImode][1] = CODE_FOR_floatunstixf2;
-#endif
-
-#ifdef HAVE_floatunsqitf2
-  if (HAVE_floatunsqitf2)
-    floattab[(int) TFmode][(int) QImode][1] = CODE_FOR_floatunsqitf2;
-#endif
-#ifdef HAVE_floatunshitf2
-  if (HAVE_floatunshitf2)
-    floattab[(int) TFmode][(int) HImode][1] = CODE_FOR_floatunshitf2;
-#endif
-#ifdef HAVE_floatunssitf2
-  if (HAVE_floatunssitf2)
-    floattab[(int) TFmode][(int) SImode][1] = CODE_FOR_floatunssitf2;
-#endif
-#ifdef HAVE_floatunsditf2
-  if (HAVE_floatunsditf2)
-    floattab[(int) TFmode][(int) DImode][1] = CODE_FOR_floatunsditf2;
-#endif
-#ifdef HAVE_floatunstitf2
-  if (HAVE_floatunstitf2)
-    floattab[(int) TFmode][(int) TImode][1] = CODE_FOR_floatunstitf2;
-#endif
-}
-\f
-/* Generate code to convert FROM to floating point
-   and store in TO.  FROM must be fixed point and not VOIDmode.
-   UNSIGNEDP nonzero means regard FROM as unsigned.
-   Normally this is done by correcting the final value
-   if it is negative.  */
-
-void
-expand_float (to, from, unsignedp)
-     rtx to, from;
-     int unsignedp;
-{
-  enum insn_code icode;
-  register rtx target = to;
-  enum machine_mode fmode, imode;
-
-  /* Crash now, because we won't be able to decide which mode to use.  */
-  if (GET_MODE (from) == VOIDmode)
-    abort ();
-
-  /* Look for an insn to do the conversion.  Do it in the specified
-     modes if possible; otherwise convert either input, output or both to
-     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))
-      {
-       int doing_unsigned = unsignedp;
-
-       icode = can_float_p (fmode, imode, unsignedp);
-       if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
-         icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
-
-       if (icode != CODE_FOR_nothing)
-         {
-           to = protect_from_queue (to, 1);
-           from = protect_from_queue (from, 0);
+       if (icode != CODE_FOR_nothing)
+         {
+           to = protect_from_queue (to, 1);
+           from = protect_from_queue (from, 0);
 
            if (imode != GET_MODE (from))
              from = convert_to_mode (imode, from, unsignedp);
@@ -3387,11 +3504,79 @@ expand_float (to, from, unsignedp)
       if (flag_force_mem)
        from = force_not_mem (from);
 
+      /* Look for a usable floating mode FMODE wider than the source and at
+        least as wide as the target.  Using FMODE will avoid rounding woes
+        with unsigned values greater than the signed maximum value.  */
+
+      for (fmode = GET_MODE (to);  fmode != VOIDmode;
+          fmode = GET_MODE_WIDER_MODE (fmode))
+       if (GET_MODE_BITSIZE (GET_MODE (from)) < GET_MODE_BITSIZE (fmode)
+           && can_float_p (fmode, GET_MODE (from), 0) != CODE_FOR_nothing)
+         break;
+
+      if (fmode == VOIDmode)
+       {
+         /* There is no such mode.  Pretend the target is wide enough.  */
+         fmode = GET_MODE (to);
+
+         /* Avoid double-rounding when TO is narrower than FROM.  */
+         if ((significand_size (fmode) + 1)
+             < GET_MODE_BITSIZE (GET_MODE (from)))
+           {
+             rtx temp1;
+             rtx neglabel = gen_label_rtx ();
+
+             /* 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
+                 || GET_MODE (target) != fmode)
+               target = gen_reg_rtx (fmode);
+
+             imode = GET_MODE (from);
+             do_pending_stack_adjust ();
+
+             /* Test whether the sign bit is set.  */
+             emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, imode, 0, 0);
+             emit_jump_insn (gen_blt (neglabel));
+
+             /* The sign bit is not set.  Convert as signed.  */
+             expand_float (target, from, 0);
+             emit_jump_insn (gen_jump (label));
+             emit_barrier ();
+
+             /* The sign bit is set.
+                Convert to a usable (positive signed) value by shifting right
+                one bit, while remembering if a nonzero bit was shifted
+                out; i.e., compute  (from & 1) | (from >> 1).  */
+
+             emit_label (neglabel);
+             temp = expand_binop (imode, and_optab, from, const1_rtx,
+                                  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, 
+                                  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);
+             if (temp != target)
+               emit_move_insn (target, temp);
+
+             do_pending_stack_adjust ();
+             emit_label (label);
+             goto done;
+           }
+       }
+
       /* If we are about to do some arithmetic to correct for an
         unsigned operand, do it in a pseudo-register.  */
 
-      if (GET_CODE (to) != REG || REGNO (to) <= LAST_VIRTUAL_REGISTER)
-       target = gen_reg_rtx (GET_MODE (to));
+      if (GET_MODE (to) != fmode
+         || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
+       target = gen_reg_rtx (fmode);
 
       /* Convert as signed integer to floating.  */
       expand_float (target, from, 0);
@@ -3402,26 +3587,29 @@ expand_float (to, from, unsignedp)
       do_pending_stack_adjust ();
       emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 0, 0);
       emit_jump_insn (gen_bge (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)));
-      temp = expand_binop (GET_MODE (to), add_optab, target,
-                          immed_real_const_1 (offset, GET_MODE (to)),
+      temp = expand_binop (fmode, add_optab, target,
+                          CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode),
                           target, 0, OPTAB_LIB_WIDEN);
       if (temp != target)
        emit_move_insn (target, temp);
+
       do_pending_stack_adjust ();
       emit_label (label);
+      goto done;
     }
-  else
 #endif
 
-  /* No hardware instruction available; call a library rotine to convert from
+  /* No hardware instruction available; call a library routine to convert from
      SImode, DImode, or TImode into SFmode, DFmode, XFmode, or TFmode.  */
     {
       rtx libfcn;
       rtx insns;
+      rtx value;
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -3481,14 +3669,18 @@ expand_float (to, from, unsignedp)
 
       start_sequence ();
 
-      emit_library_call (libfcn, 1, GET_MODE (to), 1, from, GET_MODE (from));
+      value = emit_library_call_value (libfcn, NULL_RTX, 1,
+                                      GET_MODE (to),
+                                      1, from, GET_MODE (from));
       insns = get_insns ();
       end_sequence ();
 
-      emit_libcall_block (insns, target, hard_libcall_value (GET_MODE (to)),
+      emit_libcall_block (insns, target, value,
                          gen_rtx (FLOAT, GET_MODE (to), from));
     }
 
+ done:
+
   /* Copy result to requested destination
      if we have been computing in a temp location.  */
 
@@ -3579,12 +3771,15 @@ expand_fix (to, from, unsignedp)
          && CODE_FOR_nothing != can_fix_p (GET_MODE (to), fmode, 0,
                                            &must_trunc))
        {
-         int bitsize = GET_MODE_BITSIZE (GET_MODE (to));
-         REAL_VALUE_TYPE offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1);
-         rtx limit = immed_real_const_1 (offset, fmode);
-         rtx lab1 = gen_label_rtx ();
-         rtx lab2 = gen_label_rtx ();
-         rtx insn;
+         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);
+         limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
+         lab1 = gen_label_rtx ();
+         lab2 = gen_label_rtx ();
 
          emit_queue ();
          to = protect_from_queue (to, 1);
@@ -3626,7 +3821,8 @@ expand_fix (to, from, unsignedp)
          insn = emit_move_insn (to, to);
          REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL,
                                      gen_rtx (UNSIGNED_FIX, GET_MODE (to),
-                                              from), REG_NOTES (insn));
+                                              copy_rtx (from)),
+                                     REG_NOTES (insn));
 
          return;
        }
@@ -3692,6 +3888,7 @@ expand_fix (to, from, unsignedp)
   if (libfcn)
     {
       rtx insns;
+      rtx value;
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -3701,19 +3898,24 @@ expand_fix (to, from, unsignedp)
 
       start_sequence ();
 
-      emit_library_call (libfcn, 1, GET_MODE (to), 1, from, GET_MODE (from));
+      value = emit_library_call_value (libfcn, NULL_RTX, 1, GET_MODE (to),
+
+                                      1, from, GET_MODE (from));
       insns = get_insns ();
       end_sequence ();
 
-      emit_libcall_block (insns, target, hard_libcall_value (GET_MODE (to)),
-                         gen_rtx (unsignedp ? FIX : UNSIGNED_FIX,
+      emit_libcall_block (insns, target, value,
+                         gen_rtx (unsignedp ? UNSIGNED_FIX : FIX,
                                   GET_MODE (to), from));
     }
       
-  if (GET_MODE (to) == GET_MODE (target))
-    emit_move_insn (to, target);
-  else
-    convert_move (to, target, 0);
+  if (target != to)
+    {
+      if (GET_MODE (to) == GET_MODE (target))
+        emit_move_insn (to, target);
+      else
+        convert_move (to, target, 0);
+    }
 }
 \f
 static optab
@@ -3728,6 +3930,10 @@ init_optab (code)
       op->handlers[i].insn_code = CODE_FOR_nothing;
       op->handlers[i].libfunc = 0;
     }
+
+  if (code != UNKNOWN)
+    code_to_optab[(int) code] = op;
+
   return op;
 }
 
@@ -3751,12 +3957,12 @@ init_optab (code)
 static void
 init_libfuncs (optable, first_mode, last_mode, opname, suffix)
     register optab optable;
+    register int first_mode;
+    register int last_mode;
     register char *opname;
-    register enum machine_mode first_mode;
-    register enum machine_mode last_mode;
-    register char suffix;
+    register int suffix;
 {
-  register enum machine_mode mode;
+  register int mode;
   register unsigned opname_len = strlen (opname);
 
   for (mode = first_mode; (int) mode <= (int) last_mode;
@@ -3792,7 +3998,7 @@ static void
 init_integral_libfuncs (optable, opname, suffix)
     register optab optable;
     register char *opname;
-    register char suffix;
+    register int suffix;
 {
   init_libfuncs (optable, SImode, TImode, opname, suffix);
 }
@@ -3806,7 +4012,7 @@ static void
 init_floating_libfuncs (optable, opname, suffix)
     register optab optable;
     register char *opname;
-    register char suffix;
+    register int suffix;
 {
   init_libfuncs (optable, SFmode, TFmode, opname, suffix);
 }
@@ -3820,7 +4026,7 @@ static void
 init_complex_libfuncs (optable, opname, suffix)
     register optab optable;
     register char *opname;
-    register char suffix;
+    register int suffix;
 {
   init_libfuncs (optable, SCmode, TCmode, opname, suffix);
 }
@@ -3831,15 +4037,44 @@ init_complex_libfuncs (optable, opname, suffix)
 void
 init_optabs ()
 {
-  int i;
+  int i, j;
+  enum insn_code *p;
+
+  /* Start by initializing all tables to contain CODE_FOR_nothing.  */
 
-  init_fixtab ();
-  init_floattab ();
-  init_extends ();
+  for (p = fixtab[0][0];
+       p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); 
+       p++)
+    *p = CODE_FOR_nothing;
+
+  for (p = fixtrunctab[0][0];
+       p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); 
+       p++)
+    *p = CODE_FOR_nothing;
+
+  for (p = floattab[0][0];
+       p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]); 
+       p++)
+    *p = CODE_FOR_nothing;
+
+  for (p = extendtab[0][0];
+       p < extendtab[0][0] + sizeof extendtab / sizeof extendtab[0][0][0];
+       p++)
+    *p = CODE_FOR_nothing;
+
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    setcc_gen_code[i] = CODE_FOR_nothing;
+
+#ifdef HAVE_conditional_move
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    movcc_gen_code[i] = CODE_FOR_nothing;
+#endif
 
   add_optab = init_optab (PLUS);
   sub_optab = init_optab (MINUS);
   smul_optab = init_optab (MULT);
+  smul_highpart_optab = init_optab (UNKNOWN);
+  umul_highpart_optab = init_optab (UNKNOWN);
   smul_widen_optab = init_optab (UNKNOWN);
   umul_widen_optab = init_optab (UNKNOWN);
   sdiv_optab = init_optab (DIV);
@@ -3855,7 +4090,6 @@ init_optabs ()
   xor_optab = init_optab (XOR);
   ashl_optab = init_optab (ASHIFT);
   ashr_optab = init_optab (ASHIFTRT);
-  lshl_optab = init_optab (LSHIFT);
   lshr_optab = init_optab (LSHIFTRT);
   rotl_optab = init_optab (ROTATE);
   rotr_optab = init_optab (ROTATERT);
@@ -3877,134 +4111,67 @@ init_optabs ()
   cos_optab = init_optab (UNKNOWN);
   strlen_optab = init_optab (UNKNOWN);
 
-#ifdef HAVE_addqi3
-  if (HAVE_addqi3)
-    add_optab->handlers[(int) QImode].insn_code = CODE_FOR_addqi3;
-#endif
-#ifdef HAVE_addhi3
-  if (HAVE_addhi3)
-    add_optab->handlers[(int) HImode].insn_code = CODE_FOR_addhi3;
-#endif
-#ifdef HAVE_addpsi3
-  if (HAVE_addpsi3)
-    add_optab->handlers[(int) PSImode].insn_code = CODE_FOR_addpsi3;
-#endif
-#ifdef HAVE_addsi3
-  if (HAVE_addsi3)
-    add_optab->handlers[(int) SImode].insn_code = CODE_FOR_addsi3;
-#endif
-#ifdef HAVE_adddi3
-  if (HAVE_adddi3)
-    add_optab->handlers[(int) DImode].insn_code = CODE_FOR_adddi3;
-#endif
-#ifdef HAVE_addti3
-  if (HAVE_addti3)
-    add_optab->handlers[(int) TImode].insn_code = CODE_FOR_addti3;
-#endif
-#ifdef HAVE_addsf3
-  if (HAVE_addsf3)
-    add_optab->handlers[(int) SFmode].insn_code = CODE_FOR_addsf3;
-#endif
-#ifdef HAVE_adddf3
-  if (HAVE_adddf3)
-    add_optab->handlers[(int) DFmode].insn_code = CODE_FOR_adddf3;
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    {
+      movstr_optab[i] = CODE_FOR_nothing;
+      clrstr_optab[i] = CODE_FOR_nothing;
+
+#ifdef HAVE_SECONDARY_RELOADS
+      reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
 #endif
-#ifdef HAVE_addxf3
-  if (HAVE_addxf3)
-    add_optab->handlers[(int) XFmode].insn_code = CODE_FOR_addxf3;
+    }
+
+  /* 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
-#ifdef HAVE_addtf3
-  if (HAVE_addtf3)
-    add_optab->handlers[(int) TFmode].insn_code = CODE_FOR_addtf3;
+
+#ifdef EXTRA_CC_MODES
+  init_mov_optab ();
 #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');
-
-#ifdef HAVE_subqi3
-  if (HAVE_subqi3)
-    sub_optab->handlers[(int) QImode].insn_code = CODE_FOR_subqi3;
-#endif
-#ifdef HAVE_subhi3
-  if (HAVE_subhi3)
-    sub_optab->handlers[(int) HImode].insn_code = CODE_FOR_subhi3;
-#endif
-#ifdef HAVE_subpsi3
-  if (HAVE_subpsi3)
-    sub_optab->handlers[(int) PSImode].insn_code = CODE_FOR_subpsi3;
-#endif
-#ifdef HAVE_subsi3
-  if (HAVE_subsi3)
-    sub_optab->handlers[(int) SImode].insn_code = CODE_FOR_subsi3;
-#endif
-#ifdef HAVE_subdi3
-  if (HAVE_subdi3)
-    sub_optab->handlers[(int) DImode].insn_code = CODE_FOR_subdi3;
-#endif
-#ifdef HAVE_subti3
-  if (HAVE_subti3)
-    sub_optab->handlers[(int) TImode].insn_code = CODE_FOR_subti3;
-#endif
-#ifdef HAVE_subsf3
-  if (HAVE_subsf3)
-    sub_optab->handlers[(int) SFmode].insn_code = CODE_FOR_subsf3;
-#endif
-#ifdef HAVE_subdf3
-  if (HAVE_subdf3)
-    sub_optab->handlers[(int) DFmode].insn_code = CODE_FOR_subdf3;
-#endif
-#ifdef HAVE_subxf3
-  if (HAVE_subxf3)
-    sub_optab->handlers[(int) XFmode].insn_code = CODE_FOR_subxf3;
-#endif
-#ifdef HAVE_subtf3
-  if (HAVE_subtf3)
-    sub_optab->handlers[(int) TFmode].insn_code = CODE_FOR_subtf3;
-#endif
   init_integral_libfuncs (sub_optab, "sub", '3');
   init_floating_libfuncs (sub_optab, "sub", '3');
-
-#ifdef HAVE_mulqi3
-  if (HAVE_mulqi3)
-    smul_optab->handlers[(int) QImode].insn_code = CODE_FOR_mulqi3;
-#endif
-#ifdef HAVE_mulhi3
-  if (HAVE_mulhi3)
-    smul_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulhi3;
-#endif
-#ifdef HAVE_mulpsi3
-  if (HAVE_mulpsi3)
-    smul_optab->handlers[(int) PSImode].insn_code = CODE_FOR_mulpsi3;
-#endif
-#ifdef HAVE_mulsi3
-  if (HAVE_mulsi3)
-    smul_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulsi3;
-#endif
-#ifdef HAVE_muldi3
-  if (HAVE_muldi3)
-    smul_optab->handlers[(int) DImode].insn_code = CODE_FOR_muldi3;
-#endif
-#ifdef HAVE_multi3
-  if (HAVE_multi3)
-    smul_optab->handlers[(int) TImode].insn_code = CODE_FOR_multi3;
-#endif
-#ifdef HAVE_mulsf3
-  if (HAVE_mulsf3)
-    smul_optab->handlers[(int) SFmode].insn_code = CODE_FOR_mulsf3;
-#endif
-#ifdef HAVE_muldf3
-  if (HAVE_muldf3)
-    smul_optab->handlers[(int) DFmode].insn_code = CODE_FOR_muldf3;
-#endif
-#ifdef HAVE_mulxf3
-  if (HAVE_mulxf3)
-    smul_optab->handlers[(int) XFmode].insn_code = CODE_FOR_mulxf3;
-#endif
-#ifdef HAVE_multf3
-  if (HAVE_multf3)
-    smul_optab->handlers[(int) TFmode].insn_code = CODE_FOR_multf3;
-#endif
   init_integral_libfuncs (smul_optab, "mul", '3');
   init_floating_libfuncs (smul_optab, "mul", '3');
+  init_integral_libfuncs (sdiv_optab, "div", '3');
+  init_integral_libfuncs (udiv_optab, "udiv", '3');
+  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
+  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
+  init_integral_libfuncs (smod_optab, "mod", '3');
+  init_integral_libfuncs (umod_optab, "umod", '3');
+  init_floating_libfuncs (flodiv_optab, "div", '3');
+  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
+  init_integral_libfuncs (and_optab, "and", '3');
+  init_integral_libfuncs (ior_optab, "ior", '3');
+  init_integral_libfuncs (xor_optab, "xor", '3');
+  init_integral_libfuncs (ashl_optab, "ashl", '3');
+  init_integral_libfuncs (ashr_optab, "ashr", '3');
+  init_integral_libfuncs (lshr_optab, "lshr", '3');
+  init_integral_libfuncs (smin_optab, "min", '3');
+  init_floating_libfuncs (smin_optab, "min", '3');
+  init_integral_libfuncs (smax_optab, "max", '3');
+  init_floating_libfuncs (smax_optab, "max", '3');
+  init_integral_libfuncs (umin_optab, "umin", '3');
+  init_integral_libfuncs (umax_optab, "umax", '3');
+  init_integral_libfuncs (neg_optab, "neg", '2');
+  init_floating_libfuncs (neg_optab, "neg", '2');
+  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
+  init_integral_libfuncs (ffs_optab, "ffs", '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
@@ -4014,70 +4181,6 @@ init_optabs ()
   smul_optab->handlers[(int) DImode].libfunc
     = gen_rtx (SYMBOL_REF, Pmode, MULDI3_LIBCALL);
 #endif
-#ifdef MULTI3_LIBCALL
-  smul_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, MULTI3_LIBCALL);
-#endif
-
-#ifdef HAVE_mulqihi3
-  if (HAVE_mulqihi3)
-    smul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_mulqihi3;
-#endif
-#ifdef HAVE_mulhisi3
-  if (HAVE_mulhisi3)
-    smul_widen_optab->handlers[(int) SImode].insn_code = CODE_FOR_mulhisi3;
-#endif
-#ifdef HAVE_mulsidi3
-  if (HAVE_mulsidi3)
-    smul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_mulsidi3;
-#endif
-#ifdef HAVE_mulditi3
-  if (HAVE_mulditi3)
-    smul_widen_optab->handlers[(int) TImode].insn_code = CODE_FOR_mulditi3;
-#endif
-
-#ifdef HAVE_umulqihi3
-  if (HAVE_umulqihi3)
-    umul_widen_optab->handlers[(int) HImode].insn_code = CODE_FOR_umulqihi3;
-#endif
-#ifdef HAVE_umulhisi3
-  if (HAVE_umulhisi3)
-    umul_widen_optab->handlers[(int) SImode].insn_code = CODE_FOR_umulhisi3;
-#endif
-#ifdef HAVE_umulsidi3
-  if (HAVE_umulsidi3)
-    umul_widen_optab->handlers[(int) DImode].insn_code = CODE_FOR_umulsidi3;
-#endif
-#ifdef HAVE_umulditi3
-  if (HAVE_umulditi3)
-    umul_widen_optab->handlers[(int) TImode].insn_code = CODE_FOR_umulditi3;
-#endif
-
-#ifdef HAVE_divqi3
-  if (HAVE_divqi3)
-    sdiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_divqi3;
-#endif
-#ifdef HAVE_divhi3
-  if (HAVE_divhi3)
-    sdiv_optab->handlers[(int) HImode].insn_code = CODE_FOR_divhi3;
-#endif
-#ifdef HAVE_divpsi3
-  if (HAVE_divpsi3)
-    sdiv_optab->handlers[(int) PSImode].insn_code = CODE_FOR_divpsi3;
-#endif
-#ifdef HAVE_divsi3
-  if (HAVE_divsi3)
-    sdiv_optab->handlers[(int) SImode].insn_code = CODE_FOR_divsi3;
-#endif
-#ifdef HAVE_divdi3
-  if (HAVE_divdi3)
-    sdiv_optab->handlers[(int) DImode].insn_code = CODE_FOR_divdi3;
-#endif
-#ifdef HAVE_divti3
-  if (HAVE_divti3)
-    sdiv_optab->handlers[(int) TImode].insn_code = CODE_FOR_divti3;
-#endif
-  init_integral_libfuncs (sdiv_optab, "div", '3');
 
 #ifdef DIVSI3_LIBCALL
   sdiv_optab->handlers[(int) SImode].libfunc
@@ -4087,36 +4190,6 @@ init_optabs ()
   sdiv_optab->handlers[(int) DImode].libfunc
     = gen_rtx (SYMBOL_REF, Pmode, DIVDI3_LIBCALL);
 #endif
-#ifdef DIVTI3_LIBCALL
-  sdiv_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, DIVTI3_LIBCALL);
-#endif
-
-#ifdef HAVE_udivqi3
-  if (HAVE_udivqi3)
-    udiv_optab->handlers[(int) QImode].insn_code = CODE_FOR_udivqi3;
-#endif
-#ifdef HAVE_udivhi3
-  if (HAVE_udivhi3)
-    udiv_optab->handlers[(int) HImode].insn_code = CODE_FOR_udivhi3;
-#endif
-#ifdef HAVE_udivpsi3
-  if (HAVE_udivpsi3)
-    udiv_optab->handlers[(int) PSImode].insn_code = CODE_FOR_udivpsi3;
-#endif
-#ifdef HAVE_udivsi3
-  if (HAVE_udivsi3)
-    udiv_optab->handlers[(int) SImode].insn_code = CODE_FOR_udivsi3;
-#endif
-#ifdef HAVE_udivdi3
-  if (HAVE_udivdi3)
-    udiv_optab->handlers[(int) DImode].insn_code = CODE_FOR_udivdi3;
-#endif
-#ifdef HAVE_udivti3
-  if (HAVE_udivti3)
-    udiv_optab->handlers[(int) TImode].insn_code = CODE_FOR_udivti3;
-#endif
-  init_integral_libfuncs (udiv_optab, "udiv", '3');
 
 #ifdef UDIVSI3_LIBCALL
   udiv_optab->handlers[(int) SImode].libfunc
@@ -4126,80 +4199,6 @@ init_optabs ()
   udiv_optab->handlers[(int) DImode].libfunc
     = gen_rtx (SYMBOL_REF, Pmode, UDIVDI3_LIBCALL);
 #endif
-#ifdef UDIVTI3_LIBCALL
-  udiv_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UDIVTI3_LIBCALL);
-#endif
-
-#ifdef HAVE_divmodqi4
-  if (HAVE_divmodqi4)
-    sdivmod_optab->handlers[(int) QImode].insn_code = CODE_FOR_divmodqi4;
-#endif
-#ifdef HAVE_divmodhi4
-  if (HAVE_divmodhi4)
-    sdivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_divmodhi4;
-#endif
-#ifdef HAVE_divmodsi4
-  if (HAVE_divmodsi4)
-    sdivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_divmodsi4;
-#endif
-#ifdef HAVE_divmoddi4
-  if (HAVE_divmoddi4)
-    sdivmod_optab->handlers[(int) DImode].insn_code = CODE_FOR_divmoddi4;
-#endif
-#ifdef HAVE_divmodti4
-  if (HAVE_divmodti4)
-    sdivmod_optab->handlers[(int) TImode].insn_code = CODE_FOR_divmodti4;
-#endif
-  init_integral_libfuncs (sdivmod_optab, "divmod", '4');
-
-#ifdef HAVE_udivmodqi4
-  if (HAVE_udivmodqi4)
-    udivmod_optab->handlers[(int) QImode].insn_code = CODE_FOR_udivmodqi4;
-#endif
-#ifdef HAVE_udivmodhi4
-  if (HAVE_udivmodhi4)
-    udivmod_optab->handlers[(int) HImode].insn_code = CODE_FOR_udivmodhi4;
-#endif
-#ifdef HAVE_udivmodsi4
-  if (HAVE_udivmodsi4)
-    udivmod_optab->handlers[(int) SImode].insn_code = CODE_FOR_udivmodsi4;
-#endif
-#ifdef HAVE_udivmoddi4
-  if (HAVE_udivmoddi4)
-    udivmod_optab->handlers[(int) DImode].insn_code = CODE_FOR_udivmoddi4;
-#endif
-#ifdef HAVE_udivmodti4
-  if (HAVE_udivmodti4)
-    udivmod_optab->handlers[(int) TImode].insn_code = CODE_FOR_udivmodti4;
-#endif
-  init_integral_libfuncs (udivmod_optab, "udivmod", '4');
-
-#ifdef HAVE_modqi3
-  if (HAVE_modqi3)
-    smod_optab->handlers[(int) QImode].insn_code = CODE_FOR_modqi3;
-#endif
-#ifdef HAVE_modhi3
-  if (HAVE_modhi3)
-    smod_optab->handlers[(int) HImode].insn_code = CODE_FOR_modhi3;
-#endif
-#ifdef HAVE_modpsi3
-  if (HAVE_modpsi3)
-    smod_optab->handlers[(int) PSImode].insn_code = CODE_FOR_modpsi3;
-#endif
-#ifdef HAVE_modsi3
-  if (HAVE_modsi3)
-    smod_optab->handlers[(int) SImode].insn_code = CODE_FOR_modsi3;
-#endif
-#ifdef HAVE_moddi3
-  if (HAVE_moddi3)
-    smod_optab->handlers[(int) DImode].insn_code = CODE_FOR_moddi3;
-#endif
-#ifdef HAVE_modti3
-  if (HAVE_modti3)
-    smod_optab->handlers[(int) TImode].insn_code = CODE_FOR_modti3;
-#endif
-  init_integral_libfuncs (smod_optab, "mod", '3');
 
 #ifdef MODSI3_LIBCALL
   smod_optab->handlers[(int) SImode].libfunc
@@ -4209,36 +4208,6 @@ init_optabs ()
   smod_optab->handlers[(int) DImode].libfunc
     = gen_rtx (SYMBOL_REF, Pmode, MODDI3_LIBCALL);
 #endif
-#ifdef MODTI3_LIBCALL
-  smod_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, MODTI3_LIBCALL);
-#endif
-
-#ifdef HAVE_umodqi3
-  if (HAVE_umodqi3)
-    umod_optab->handlers[(int) QImode].insn_code = CODE_FOR_umodqi3;
-#endif
-#ifdef HAVE_umodhi3
-  if (HAVE_umodhi3)
-    umod_optab->handlers[(int) HImode].insn_code = CODE_FOR_umodhi3;
-#endif
-#ifdef HAVE_umodpsi3
-  if (HAVE_umodpsi3)
-    umod_optab->handlers[(int) PSImode].insn_code = CODE_FOR_umodpsi3;
-#endif
-#ifdef HAVE_umodsi3
-  if (HAVE_umodsi3)
-    umod_optab->handlers[(int) SImode].insn_code = CODE_FOR_umodsi3;
-#endif
-#ifdef HAVE_umoddi3
-  if (HAVE_umoddi3)
-    umod_optab->handlers[(int) DImode].insn_code = CODE_FOR_umoddi3;
-#endif
-#ifdef HAVE_umodti3
-  if (HAVE_umodti3)
-    umod_optab->handlers[(int) TImode].insn_code = CODE_FOR_umodti3;
-#endif
-  init_integral_libfuncs (umod_optab, "umod", '3');
 
 #ifdef UMODSI3_LIBCALL
   umod_optab->handlers[(int) SImode].libfunc
@@ -4248,884 +4217,18 @@ init_optabs ()
   umod_optab->handlers[(int) DImode].libfunc
     = gen_rtx (SYMBOL_REF, Pmode, UMODDI3_LIBCALL);
 #endif
-#ifdef UMODTI3_LIBCALL
-  umod_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UMODTI3_LIBCALL);
-#endif
-
-#ifdef HAVE_divsf3
-  if (HAVE_divsf3)
-    flodiv_optab->handlers[(int) SFmode].insn_code = CODE_FOR_divsf3;
-#endif
-#ifdef HAVE_divdf3
-  if (HAVE_divdf3)
-    flodiv_optab->handlers[(int) DFmode].insn_code = CODE_FOR_divdf3;
-#endif
-#ifdef HAVE_divxf3
-  if (HAVE_divxf3)
-    flodiv_optab->handlers[(int) XFmode].insn_code = CODE_FOR_divxf3;
-#endif
-#ifdef HAVE_divtf3
-  if (HAVE_divtf3)
-    flodiv_optab->handlers[(int) TFmode].insn_code = CODE_FOR_divtf3;
-#endif
-  init_floating_libfuncs (flodiv_optab, "div", '3');
-
-#ifdef HAVE_ftruncsf2
-  if (HAVE_ftruncsf2)
-    ftrunc_optab->handlers[(int) SFmode].insn_code = CODE_FOR_ftruncsf2;
-#endif
-#ifdef HAVE_ftruncdf2
-  if (HAVE_ftruncdf2)
-    ftrunc_optab->handlers[(int) DFmode].insn_code = CODE_FOR_ftruncdf2;
-#endif
-#ifdef HAVE_ftruncxf2
-  if (HAVE_ftruncxf2)
-    ftrunc_optab->handlers[(int) XFmode].insn_code = CODE_FOR_ftruncxf2;
-#endif
-#ifdef HAVE_ftrunctf2
-  if (HAVE_ftrunctf2)
-    ftrunc_optab->handlers[(int) TFmode].insn_code = CODE_FOR_ftrunctf2;
-#endif
-  init_floating_libfuncs (ftrunc_optab, "ftrunc", '2');
-
-#ifdef HAVE_andqi3
-  if (HAVE_andqi3)
-    and_optab->handlers[(int) QImode].insn_code = CODE_FOR_andqi3;
-#endif
-#ifdef HAVE_andhi3
-  if (HAVE_andhi3)
-    and_optab->handlers[(int) HImode].insn_code = CODE_FOR_andhi3;
-#endif
-#ifdef HAVE_andpsi3
-  if (HAVE_andpsi3)
-    and_optab->handlers[(int) PSImode].insn_code = CODE_FOR_andpsi3;
-#endif
-#ifdef HAVE_andsi3
-  if (HAVE_andsi3)
-    and_optab->handlers[(int) SImode].insn_code = CODE_FOR_andsi3;
-#endif
-#ifdef HAVE_anddi3
-  if (HAVE_anddi3)
-    and_optab->handlers[(int) DImode].insn_code = CODE_FOR_anddi3;
-#endif
-#ifdef HAVE_andti3
-  if (HAVE_andti3)
-    and_optab->handlers[(int) TImode].insn_code = CODE_FOR_andti3;
-#endif
-  init_integral_libfuncs (and_optab, "and", '3');
-
-#ifdef HAVE_iorqi3
-  if (HAVE_iorqi3)
-    ior_optab->handlers[(int) QImode].insn_code = CODE_FOR_iorqi3;
-#endif
-#ifdef HAVE_iorhi3
-  if (HAVE_iorhi3)
-    ior_optab->handlers[(int) HImode].insn_code = CODE_FOR_iorhi3;
-#endif
-#ifdef HAVE_iorpsi3
-  if (HAVE_iorpsi3)
-    ior_optab->handlers[(int) PSImode].insn_code = CODE_FOR_iorpsi3;
-#endif
-#ifdef HAVE_iorsi3
-  if (HAVE_iorsi3)
-    ior_optab->handlers[(int) SImode].insn_code = CODE_FOR_iorsi3;
-#endif
-#ifdef HAVE_iordi3
-  if (HAVE_iordi3)
-    ior_optab->handlers[(int) DImode].insn_code = CODE_FOR_iordi3;
-#endif
-#ifdef HAVE_iorti3
-  if (HAVE_iorti3)
-    ior_optab->handlers[(int) TImode].insn_code = CODE_FOR_iorti3;
-#endif
-  init_integral_libfuncs (ior_optab, "ior", '3');
-
-#ifdef HAVE_xorqi3
-  if (HAVE_xorqi3)
-    xor_optab->handlers[(int) QImode].insn_code = CODE_FOR_xorqi3;
-#endif
-#ifdef HAVE_xorhi3
-  if (HAVE_xorhi3)
-    xor_optab->handlers[(int) HImode].insn_code = CODE_FOR_xorhi3;
-#endif
-#ifdef HAVE_xorpsi3
-  if (HAVE_xorpsi3)
-    xor_optab->handlers[(int) PSImode].insn_code = CODE_FOR_xorpsi3;
-#endif
-#ifdef HAVE_xorsi3
-  if (HAVE_xorsi3)
-    xor_optab->handlers[(int) SImode].insn_code = CODE_FOR_xorsi3;
-#endif
-#ifdef HAVE_xordi3
-  if (HAVE_xordi3)
-    xor_optab->handlers[(int) DImode].insn_code = CODE_FOR_xordi3;
-#endif
-#ifdef HAVE_xorti3
-  if (HAVE_xorti3)
-    xor_optab->handlers[(int) TImode].insn_code = CODE_FOR_xorti3;
-#endif
-  init_integral_libfuncs (xor_optab, "xor", '3');
-
-#ifdef HAVE_ashlqi3
-  if (HAVE_ashlqi3)
-    ashl_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashlqi3;
-#endif
-#ifdef HAVE_ashlhi3
-  if (HAVE_ashlhi3)
-    ashl_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashlhi3;
-#endif
-#ifdef HAVE_ashlpsi3
-  if (HAVE_ashlpsi3)
-    ashl_optab->handlers[(int) PSImode].insn_code = CODE_FOR_ashlpsi3;
-#endif
-#ifdef HAVE_ashlsi3
-  if (HAVE_ashlsi3)
-    ashl_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashlsi3;
-#endif
-#ifdef HAVE_ashldi3
-  if (HAVE_ashldi3)
-    ashl_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashldi3;
-#endif
-#ifdef HAVE_ashlti3
-  if (HAVE_ashlti3)
-    ashl_optab->handlers[(int) TImode].insn_code = CODE_FOR_ashlti3;
-#endif
-  init_integral_libfuncs (ashl_optab, "ashl", '3');
-
-#ifdef HAVE_ashrqi3
-  if (HAVE_ashrqi3)
-    ashr_optab->handlers[(int) QImode].insn_code = CODE_FOR_ashrqi3;
-#endif
-#ifdef HAVE_ashrhi3
-  if (HAVE_ashrhi3)
-    ashr_optab->handlers[(int) HImode].insn_code = CODE_FOR_ashrhi3;
-#endif
-#ifdef HAVE_ashrpsi3
-  if (HAVE_ashrpsi3)
-    ashr_optab->handlers[(int) PSImode].insn_code = CODE_FOR_ashrpsi3;
-#endif
-#ifdef HAVE_ashrsi3
-  if (HAVE_ashrsi3)
-    ashr_optab->handlers[(int) SImode].insn_code = CODE_FOR_ashrsi3;
-#endif
-#ifdef HAVE_ashrdi3
-  if (HAVE_ashrdi3)
-    ashr_optab->handlers[(int) DImode].insn_code = CODE_FOR_ashrdi3;
-#endif
-#ifdef HAVE_ashrti3
-  if (HAVE_ashrti3)
-    ashr_optab->handlers[(int) TImode].insn_code = CODE_FOR_ashrti3;
-#endif
-  init_integral_libfuncs (ashr_optab, "ashr", '3');
-
-#ifdef HAVE_lshlqi3
-  if (HAVE_lshlqi3)
-    lshl_optab->handlers[(int) QImode].insn_code = CODE_FOR_lshlqi3;
-#endif
-#ifdef HAVE_lshlhi3
-  if (HAVE_lshlhi3)
-    lshl_optab->handlers[(int) HImode].insn_code = CODE_FOR_lshlhi3;
-#endif
-#ifdef HAVE_lshlpsi3
-  if (HAVE_lshlpsi3)
-    lshl_optab->handlers[(int) PSImode].insn_code = CODE_FOR_lshlpsi3;
-#endif
-#ifdef HAVE_lshlsi3
-  if (HAVE_lshlsi3)
-    lshl_optab->handlers[(int) SImode].insn_code = CODE_FOR_lshlsi3;
-#endif
-#ifdef HAVE_lshldi3
-  if (HAVE_lshldi3)
-    lshl_optab->handlers[(int) DImode].insn_code = CODE_FOR_lshldi3;
-#endif
-#ifdef HAVE_lshlti3
-  if (HAVE_lshlti3)
-    lshl_optab->handlers[(int) TImode].insn_code = CODE_FOR_lshlti3;
-#endif
-  init_integral_libfuncs (lshl_optab, "lshl", '3');
-
-#ifdef HAVE_lshrqi3
-  if (HAVE_lshrqi3)
-    lshr_optab->handlers[(int) QImode].insn_code = CODE_FOR_lshrqi3;
-#endif
-#ifdef HAVE_lshrhi3
-  if (HAVE_lshrhi3)
-    lshr_optab->handlers[(int) HImode].insn_code = CODE_FOR_lshrhi3;
-#endif
-#ifdef HAVE_lshrpsi3
-  if (HAVE_lshrpsi3)
-    lshr_optab->handlers[(int) PSImode].insn_code = CODE_FOR_lshrpsi3;
-#endif
-#ifdef HAVE_lshrsi3
-  if (HAVE_lshrsi3)
-    lshr_optab->handlers[(int) SImode].insn_code = CODE_FOR_lshrsi3;
-#endif
-#ifdef HAVE_lshrdi3
-  if (HAVE_lshrdi3)
-    lshr_optab->handlers[(int) DImode].insn_code = CODE_FOR_lshrdi3;
-#endif
-#ifdef HAVE_lshrti3
-  if (HAVE_lshrti3)
-    lshr_optab->handlers[(int) TImode].insn_code = CODE_FOR_lshrti3;
-#endif
-  init_integral_libfuncs (lshr_optab, "lshr", '3');
-
-#ifdef HAVE_rotlqi3
-  if (HAVE_rotlqi3)
-    rotl_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotlqi3;
-#endif
-#ifdef HAVE_rotlhi3
-  if (HAVE_rotlhi3)
-    rotl_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotlhi3;
-#endif
-#ifdef HAVE_rotlpsi3
-  if (HAVE_rotlpsi3)
-    rotl_optab->handlers[(int) PSImode].insn_code = CODE_FOR_rotlpsi3;
-#endif
-#ifdef HAVE_rotlsi3
-  if (HAVE_rotlsi3)
-    rotl_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotlsi3;
-#endif
-#ifdef HAVE_rotldi3
-  if (HAVE_rotldi3)
-    rotl_optab->handlers[(int) DImode].insn_code = CODE_FOR_rotldi3;
-#endif
-#ifdef HAVE_rotlti3
-  if (HAVE_rotlti3)
-    rotl_optab->handlers[(int) TImode].insn_code = CODE_FOR_rotlti3;
-#endif
-  init_integral_libfuncs (rotl_optab, "rotl", '3');
-
-#ifdef HAVE_rotrqi3
-  if (HAVE_rotrqi3)
-    rotr_optab->handlers[(int) QImode].insn_code = CODE_FOR_rotrqi3;
-#endif
-#ifdef HAVE_rotrhi3
-  if (HAVE_rotrhi3)
-    rotr_optab->handlers[(int) HImode].insn_code = CODE_FOR_rotrhi3;
-#endif
-#ifdef HAVE_rotrpsi3
-  if (HAVE_rotrpsi3)
-    rotr_optab->handlers[(int) PSImode].insn_code = CODE_FOR_rotrpsi3;
-#endif
-#ifdef HAVE_rotrsi3
-  if (HAVE_rotrsi3)
-    rotr_optab->handlers[(int) SImode].insn_code = CODE_FOR_rotrsi3;
-#endif
-#ifdef HAVE_rotrdi3
-  if (HAVE_rotrdi3)
-    rotr_optab->handlers[(int) DImode].insn_code = CODE_FOR_rotrdi3;
-#endif
-#ifdef HAVE_rotrti3
-  if (HAVE_rotrti3)
-    rotr_optab->handlers[(int) TImode].insn_code = CODE_FOR_rotrti3;
-#endif
-  init_integral_libfuncs (rotr_optab, "rotr", '3');
-
-#ifdef HAVE_sminqi3
-  if (HAVE_sminqi3)
-    smin_optab->handlers[(int) QImode].insn_code = CODE_FOR_sminqi3;
-#endif
-#ifdef HAVE_sminhi3
-  if (HAVE_sminhi3)
-    smin_optab->handlers[(int) HImode].insn_code = CODE_FOR_sminhi3;
-#endif
-#ifdef HAVE_sminsi3
-  if (HAVE_sminsi3)
-    smin_optab->handlers[(int) SImode].insn_code = CODE_FOR_sminsi3;
-#endif
-#ifdef HAVE_smindi3
-  if (HAVE_smindi3)
-    smin_optab->handlers[(int) DImode].insn_code = CODE_FOR_smindi3;
-#endif
-#ifdef HAVE_sminti3
-  if (HAVE_sminti3)
-    smin_optab->handlers[(int) TImode].insn_code = CODE_FOR_sminti3;
-#endif
-#ifdef HAVE_minsf3
-  if (HAVE_minsf3)
-    smin_optab->handlers[(int) SFmode].insn_code = CODE_FOR_minsf3;
-#endif
-#ifdef HAVE_mindf3
-  if (HAVE_mindf3)
-    smin_optab->handlers[(int) DFmode].insn_code = CODE_FOR_mindf3;
-#endif
-#ifdef HAVE_minxf3
-  if (HAVE_minxf3)
-    smin_optab->handlers[(int) XFmode].insn_code = CODE_FOR_minxf3;
-#endif
-#ifdef HAVE_mintf3
-  if (HAVE_mintf3)
-    smin_optab->handlers[(int) TFmode].insn_code = CODE_FOR_mintf3;
-#endif
-  init_integral_libfuncs (smin_optab, "min", '3');
-  init_floating_libfuncs (smin_optab, "min", '3');
-
-#ifdef HAVE_smaxqi3
-  if (HAVE_smaxqi3)
-    smax_optab->handlers[(int) QImode].insn_code = CODE_FOR_smaxqi3;
-#endif
-#ifdef HAVE_smaxhi3
-  if (HAVE_smaxhi3)
-    smax_optab->handlers[(int) HImode].insn_code = CODE_FOR_smaxhi3;
-#endif
-#ifdef HAVE_smaxsi3
-  if (HAVE_smaxsi3)
-    smax_optab->handlers[(int) SImode].insn_code = CODE_FOR_smaxsi3;
-#endif
-#ifdef HAVE_smaxdi3
-  if (HAVE_smaxdi3)
-    smax_optab->handlers[(int) DImode].insn_code = CODE_FOR_smaxdi3;
-#endif
-#ifdef HAVE_smaxti3
-  if (HAVE_smaxti3)
-    smax_optab->handlers[(int) TImode].insn_code = CODE_FOR_smaxti3;
-#endif
-#ifdef HAVE_maxsf3
-  if (HAVE_maxsf3)
-    smax_optab->handlers[(int) SFmode].insn_code = CODE_FOR_maxsf3;
-#endif
-#ifdef HAVE_maxdf3
-  if (HAVE_maxdf3)
-    smax_optab->handlers[(int) DFmode].insn_code = CODE_FOR_maxdf3;
-#endif
-#ifdef HAVE_maxxf3
-  if (HAVE_maxxf3)
-    smax_optab->handlers[(int) XFmode].insn_code = CODE_FOR_maxxf3;
-#endif
-#ifdef HAVE_maxtf3
-  if (HAVE_maxtf3)
-    smax_optab->handlers[(int) TFmode].insn_code = CODE_FOR_maxtf3;
-#endif
-  init_integral_libfuncs (smax_optab, "max", '3');
-  init_floating_libfuncs (smax_optab, "max", '3');
-
-#ifdef HAVE_uminqi3
-  if (HAVE_uminqi3)
-    umin_optab->handlers[(int) QImode].insn_code = CODE_FOR_uminqi3;
-#endif
-#ifdef HAVE_uminhi3
-  if (HAVE_uminhi3)
-    umin_optab->handlers[(int) HImode].insn_code = CODE_FOR_uminhi3;
-#endif
-#ifdef HAVE_uminsi3
-  if (HAVE_uminsi3)
-    umin_optab->handlers[(int) SImode].insn_code = CODE_FOR_uminsi3;
-#endif
-#ifdef HAVE_umindi3
-  if (HAVE_umindi3)
-    umin_optab->handlers[(int) DImode].insn_code = CODE_FOR_umindi3;
-#endif
-#ifdef HAVE_uminti3
-  if (HAVE_uminti3)
-    umin_optab->handlers[(int) TImode].insn_code = CODE_FOR_uminti3;
-#endif
-  init_integral_libfuncs (umin_optab, "umin", '3');
-
-#ifdef HAVE_umaxqi3
-  if (HAVE_umaxqi3)
-    umax_optab->handlers[(int) QImode].insn_code = CODE_FOR_umaxqi3;
-#endif
-#ifdef HAVE_umaxhi3
-  if (HAVE_umaxhi3)
-    umax_optab->handlers[(int) HImode].insn_code = CODE_FOR_umaxhi3;
-#endif
-#ifdef HAVE_umaxsi3
-  if (HAVE_umaxsi3)
-    umax_optab->handlers[(int) SImode].insn_code = CODE_FOR_umaxsi3;
-#endif
-#ifdef HAVE_umaxdi3
-  if (HAVE_umaxdi3)
-    umax_optab->handlers[(int) DImode].insn_code = CODE_FOR_umaxdi3;
-#endif
-#ifdef HAVE_umaxti3
-  if (HAVE_umaxti3)
-    umax_optab->handlers[(int) TImode].insn_code = CODE_FOR_umaxti3;
-#endif
-  init_integral_libfuncs (umax_optab, "umax", '3');
-
-#ifdef HAVE_negqi2
-  if (HAVE_negqi2)
-    neg_optab->handlers[(int) QImode].insn_code = CODE_FOR_negqi2;
-#endif
-#ifdef HAVE_neghi2
-  if (HAVE_neghi2)
-    neg_optab->handlers[(int) HImode].insn_code = CODE_FOR_neghi2;
-#endif
-#ifdef HAVE_negpsi2
-  if (HAVE_negpsi2)
-    neg_optab->handlers[(int) PSImode].insn_code = CODE_FOR_negpsi2;
-#endif
-#ifdef HAVE_negsi2
-  if (HAVE_negsi2)
-    neg_optab->handlers[(int) SImode].insn_code = CODE_FOR_negsi2;
-#endif
-#ifdef HAVE_negdi2
-  if (HAVE_negdi2)
-    neg_optab->handlers[(int) DImode].insn_code = CODE_FOR_negdi2;
-#endif
-#ifdef HAVE_negti2
-  if (HAVE_negti2)
-    neg_optab->handlers[(int) TImode].insn_code = CODE_FOR_negti2;
-#endif
-#ifdef HAVE_negsf2
-  if (HAVE_negsf2)
-    neg_optab->handlers[(int) SFmode].insn_code = CODE_FOR_negsf2;
-#endif
-#ifdef HAVE_negdf2
-  if (HAVE_negdf2)
-    neg_optab->handlers[(int) DFmode].insn_code = CODE_FOR_negdf2;
-#endif
-#ifdef HAVE_negxf2
-  if (HAVE_negxf2)
-    neg_optab->handlers[(int) XFmode].insn_code = CODE_FOR_negxf2;
-#endif
-#ifdef HAVE_negtf2
-  if (HAVE_negtf2)
-    neg_optab->handlers[(int) TFmode].insn_code = CODE_FOR_negtf2;
-#endif
-  init_integral_libfuncs (neg_optab, "neg", '2');
-  init_floating_libfuncs (neg_optab, "neg", '2');
-
-#ifdef HAVE_absqi2
-  if (HAVE_absqi2)
-    abs_optab->handlers[(int) QImode].insn_code = CODE_FOR_absqi2;
-#endif
-#ifdef HAVE_abshi2
-  if (HAVE_abshi2)
-    abs_optab->handlers[(int) HImode].insn_code = CODE_FOR_abshi2;
-#endif
-#ifdef HAVE_abspsi2
-  if (HAVE_abspsi2)
-    abs_optab->handlers[(int) PSImode].insn_code = CODE_FOR_abspsi2;
-#endif
-#ifdef HAVE_abssi2
-  if (HAVE_abssi2)
-    abs_optab->handlers[(int) SImode].insn_code = CODE_FOR_abssi2;
-#endif
-#ifdef HAVE_absdi2
-  if (HAVE_absdi2)
-    abs_optab->handlers[(int) DImode].insn_code = CODE_FOR_absdi2;
-#endif
-#ifdef HAVE_absti2
-  if (HAVE_absti2)
-    abs_optab->handlers[(int) TImode].insn_code = CODE_FOR_absti2;
-#endif
-#ifdef HAVE_abssf2
-  if (HAVE_abssf2)
-    abs_optab->handlers[(int) SFmode].insn_code = CODE_FOR_abssf2;
-#endif
-#ifdef HAVE_absdf2
-  if (HAVE_absdf2)
-    abs_optab->handlers[(int) DFmode].insn_code = CODE_FOR_absdf2;
-#endif
-#ifdef HAVE_absxf2
-  if (HAVE_absxf2)
-    abs_optab->handlers[(int) XFmode].insn_code = CODE_FOR_absxf2;
-#endif
-#ifdef HAVE_abstf2
-  if (HAVE_abstf2)
-    abs_optab->handlers[(int) TFmode].insn_code = CODE_FOR_abstf2;
-#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
     = gen_rtx (SYMBOL_REF, Pmode, "cabs");
 
-#ifdef HAVE_sqrtqi2
-  if (HAVE_sqrtqi2)
-    sqrt_optab->handlers[(int) QImode].insn_code = CODE_FOR_sqrtqi2;
-#endif
-#ifdef HAVE_sqrthi2
-  if (HAVE_sqrthi2)
-    sqrt_optab->handlers[(int) HImode].insn_code = CODE_FOR_sqrthi2;
-#endif
-#ifdef HAVE_sqrtpsi2
-  if (HAVE_sqrtpsi2)
-    sqrt_optab->handlers[(int) PSImode].insn_code = CODE_FOR_sqrtpsi2;
-#endif
-#ifdef HAVE_sqrtsi2
-  if (HAVE_sqrtsi2)
-    sqrt_optab->handlers[(int) SImode].insn_code = CODE_FOR_sqrtsi2;
-#endif
-#ifdef HAVE_sqrtdi2
-  if (HAVE_sqrtdi2)
-    sqrt_optab->handlers[(int) DImode].insn_code = CODE_FOR_sqrtdi2;
-#endif
-#ifdef HAVE_sqrtti2
-  if (HAVE_sqrtti2)
-    sqrt_optab->handlers[(int) TImode].insn_code = CODE_FOR_sqrtti2;
-#endif
-#ifdef HAVE_sqrtsf2
-  if (HAVE_sqrtsf2)
-    sqrt_optab->handlers[(int) SFmode].insn_code = CODE_FOR_sqrtsf2;
-#endif
-#ifdef HAVE_sqrtdf2
-  if (HAVE_sqrtdf2)
-    sqrt_optab->handlers[(int) DFmode].insn_code = CODE_FOR_sqrtdf2;
-#endif
-#ifdef HAVE_sqrttf2
-  if (HAVE_sqrttf2)
-    sqrt_optab->handlers[(int) TFmode].insn_code = CODE_FOR_sqrttf2;
-#endif
-  /* No library calls here!  If there is no sqrt instruction expand_builtin
-     should force the library call.  */
-
-#ifdef HAVE_sinsf2
-  if (HAVE_sinsf2)
-    sin_optab->handlers[(int) SFmode].insn_code = CODE_FOR_sinsf2;
-#endif
-#ifdef HAVE_sindf2
-  if (HAVE_sindf2)
-    sin_optab->handlers[(int) DFmode].insn_code = CODE_FOR_sindf2;
-#endif
-#ifdef HAVE_sintf2
-  if (HAVE_sintf2)
-    sin_optab->handlers[(int) TFmode].insn_code = CODE_FOR_sintf2;
-#endif
-  /* No library calls here!  If there is no sin instruction expand_builtin
-     should force the library call.  */
-
-#ifdef HAVE_cossf2
-  if (HAVE_cossf2)
-    cos_optab->handlers[(int) SFmode].insn_code = CODE_FOR_cossf2;
-#endif
-#ifdef HAVE_cosdf2
-  if (HAVE_cosdf2)
-    cos_optab->handlers[(int) DFmode].insn_code = CODE_FOR_cosdf2;
-#endif
-#ifdef HAVE_costf2
-  if (HAVE_costf2)
-    cos_optab->handlers[(int) TFmode].insn_code = CODE_FOR_costf2;
-#endif
-  /* No library calls here!  If there is no cos instruction expand_builtin
-     should force the library call.  */
-
-#ifdef HAVE_strlenqi
-  if (HAVE_strlenqi)
-    strlen_optab->handlers[(int) QImode].insn_code = CODE_FOR_strlenqi;
-#endif
-#ifdef HAVE_strlenhi
-  if (HAVE_strlenhi)
-    strlen_optab->handlers[(int) HImode].insn_code = CODE_FOR_strlenhi;
-#endif
-#ifdef HAVE_strlenpsi
-  if (HAVE_strlenpsi)
-    strlen_optab->handlers[(int) PSImode].insn_code = CODE_FOR_strlenpsi;
-#endif
-#ifdef HAVE_strlensi
-  if (HAVE_strlensi)
-    strlen_optab->handlers[(int) SImode].insn_code = CODE_FOR_strlensi;
-#endif
-#ifdef HAVE_strlendi
-  if (HAVE_strlendi)
-    strlen_optab->handlers[(int) DImode].insn_code = CODE_FOR_strlendi;
-#endif
-#ifdef HAVE_strlenti
-  if (HAVE_strlenti)
-    strlen_optab->handlers[(int) TImode].insn_code = CODE_FOR_strlenti;
-#endif
-  /* No library calls here!  If there is no strlen instruction expand_builtin
-     should force the library call.  */
-
-#ifdef HAVE_one_cmplqi2
-  if (HAVE_one_cmplqi2)
-    one_cmpl_optab->handlers[(int) QImode].insn_code = CODE_FOR_one_cmplqi2;
-#endif
-#ifdef HAVE_one_cmplhi2
-  if (HAVE_one_cmplhi2)
-    one_cmpl_optab->handlers[(int) HImode].insn_code = CODE_FOR_one_cmplhi2;
-#endif
-#ifdef HAVE_one_cmplpsi2
-  if (HAVE_one_cmplpsi2)
-    one_cmpl_optab->handlers[(int) PSImode].insn_code = CODE_FOR_one_cmplpsi2;
-#endif
-#ifdef HAVE_one_cmplsi2
-  if (HAVE_one_cmplsi2)
-    one_cmpl_optab->handlers[(int) SImode].insn_code = CODE_FOR_one_cmplsi2;
-#endif
-#ifdef HAVE_one_cmpldi2
-  if (HAVE_one_cmpldi2)
-    one_cmpl_optab->handlers[(int) DImode].insn_code = CODE_FOR_one_cmpldi2;
-#endif
-#ifdef HAVE_one_cmplti2
-  if (HAVE_one_cmplti2)
-    one_cmpl_optab->handlers[(int) TImode].insn_code = CODE_FOR_one_cmplti2;
-#endif
-  init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
-
-#ifdef HAVE_ffsqi2
-  if (HAVE_ffsqi2)
-    ffs_optab->handlers[(int) QImode].insn_code = CODE_FOR_ffsqi2;
-#endif
-#ifdef HAVE_ffshi2
-  if (HAVE_ffshi2)
-    ffs_optab->handlers[(int) HImode].insn_code = CODE_FOR_ffshi2;
-#endif
-#ifdef HAVE_ffspsi2
-  if (HAVE_ffspsi2)
-    ffs_optab->handlers[(int) PSImode].insn_code = CODE_FOR_ffspsi2;
-#endif
-#ifdef HAVE_ffssi2
-  if (HAVE_ffssi2)
-    ffs_optab->handlers[(int) SImode].insn_code = CODE_FOR_ffssi2;
-#endif
-#ifdef HAVE_ffsdi2
-  if (HAVE_ffsdi2)
-    ffs_optab->handlers[(int) DImode].insn_code = CODE_FOR_ffsdi2;
-#endif
-#ifdef HAVE_ffsti2
-  if (HAVE_ffsti2)
-    ffs_optab->handlers[(int) TImode].insn_code = CODE_FOR_ffsti2;
-#endif
-  init_integral_libfuncs (ffs_optab, "ffs", '2');
-
-#ifdef HAVE_movqi
-  if (HAVE_movqi)
-    mov_optab->handlers[(int) QImode].insn_code = CODE_FOR_movqi;
-#endif
-#ifdef HAVE_movhi
-  if (HAVE_movhi)
-    mov_optab->handlers[(int) HImode].insn_code = CODE_FOR_movhi;
-#endif
-#ifdef HAVE_movpsi
-  if (HAVE_movpsi)
-    mov_optab->handlers[(int) PSImode].insn_code = CODE_FOR_movpsi;
-#endif
-#ifdef HAVE_movsi
-  if (HAVE_movsi)
-    mov_optab->handlers[(int) SImode].insn_code = CODE_FOR_movsi;
-#endif
-#ifdef HAVE_movdi
-  if (HAVE_movdi)
-    mov_optab->handlers[(int) DImode].insn_code = CODE_FOR_movdi;
-#endif
-#ifdef HAVE_movti
-  if (HAVE_movti)
-    mov_optab->handlers[(int) TImode].insn_code = CODE_FOR_movti;
-#endif
-#ifdef HAVE_movsf
-  if (HAVE_movsf)
-    mov_optab->handlers[(int) SFmode].insn_code = CODE_FOR_movsf;
-#endif
-#ifdef HAVE_movdf
-  if (HAVE_movdf)
-    mov_optab->handlers[(int) DFmode].insn_code = CODE_FOR_movdf;
-#endif
-#ifdef HAVE_movxf
-  if (HAVE_movxf)
-    mov_optab->handlers[(int) XFmode].insn_code = CODE_FOR_movxf;
-#endif
-#ifdef HAVE_movtf
-  if (HAVE_movtf)
-    mov_optab->handlers[(int) TFmode].insn_code = CODE_FOR_movtf;
-#endif
-#ifdef HAVE_movcc
-  if (HAVE_movcc)
-    mov_optab->handlers[(int) CCmode].insn_code = CODE_FOR_movcc;
-#endif
-
-#ifdef EXTRA_CC_MODES
-  init_mov_optab ();
-#endif
-
-#ifdef HAVE_movstrictqi
-  if (HAVE_movstrictqi)
-    movstrict_optab->handlers[(int) QImode].insn_code = CODE_FOR_movstrictqi;
-#endif
-#ifdef HAVE_movstricthi
-  if (HAVE_movstricthi)
-    movstrict_optab->handlers[(int) HImode].insn_code = CODE_FOR_movstricthi;
-#endif
-#ifdef HAVE_movstrictpsi
-  if (HAVE_movstrictpsi)
-    movstrict_optab->handlers[(int) PSImode].insn_code = CODE_FOR_movstrictpsi;
-#endif
-#ifdef HAVE_movstrictsi
-  if (HAVE_movstrictsi)
-    movstrict_optab->handlers[(int) SImode].insn_code = CODE_FOR_movstrictsi;
-#endif
-#ifdef HAVE_movstrictdi
-  if (HAVE_movstrictdi)
-    movstrict_optab->handlers[(int) DImode].insn_code = CODE_FOR_movstrictdi;
-#endif
-#ifdef HAVE_movstrictti
-  if (HAVE_movstrictti)
-    movstrict_optab->handlers[(int) TImode].insn_code = CODE_FOR_movstrictti;
-#endif
-
-#ifdef HAVE_cmpqi
-  if (HAVE_cmpqi)
-    cmp_optab->handlers[(int) QImode].insn_code = CODE_FOR_cmpqi;
-#endif
-#ifdef HAVE_cmphi
-  if (HAVE_cmphi)
-    cmp_optab->handlers[(int) HImode].insn_code = CODE_FOR_cmphi;
-#endif
-#ifdef HAVE_cmppsi
-  if (HAVE_cmppsi)
-    cmp_optab->handlers[(int) PSImode].insn_code = CODE_FOR_cmppsi;
-#endif
-#ifdef HAVE_cmpsi
-  if (HAVE_cmpsi)
-    cmp_optab->handlers[(int) SImode].insn_code = CODE_FOR_cmpsi;
-#endif
-#ifdef HAVE_cmpdi
-  if (HAVE_cmpdi)
-    cmp_optab->handlers[(int) DImode].insn_code = CODE_FOR_cmpdi;
-#endif
-#ifdef HAVE_cmpti
-  if (HAVE_cmpti)
-    cmp_optab->handlers[(int) TImode].insn_code = CODE_FOR_cmpti;
-#endif
-#ifdef HAVE_cmpsf
-  if (HAVE_cmpsf)
-    cmp_optab->handlers[(int) SFmode].insn_code = CODE_FOR_cmpsf;
-#endif
-#ifdef HAVE_cmpdf
-  if (HAVE_cmpdf)
-    cmp_optab->handlers[(int) DFmode].insn_code = CODE_FOR_cmpdf;
-#endif
-#ifdef HAVE_cmpxf
-  if (HAVE_cmpxf)
-    cmp_optab->handlers[(int) XFmode].insn_code = CODE_FOR_cmpxf;
-#endif
-#ifdef HAVE_cmptf
-  if (HAVE_cmptf)
-    cmp_optab->handlers[(int) TFmode].insn_code = CODE_FOR_cmptf;
-#endif
-  /* 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 HAVE_tstqi
-  if (HAVE_tstqi)
-    tst_optab->handlers[(int) QImode].insn_code = CODE_FOR_tstqi;
-#endif
-#ifdef HAVE_tsthi
-  if (HAVE_tsthi)
-    tst_optab->handlers[(int) HImode].insn_code = CODE_FOR_tsthi;
-#endif
-#ifdef HAVE_tstpsi
-  if (HAVE_tstpsi)
-    tst_optab->handlers[(int) PSImode].insn_code = CODE_FOR_tstpsi;
-#endif
-#ifdef HAVE_tstsi
-  if (HAVE_tstsi)
-    tst_optab->handlers[(int) SImode].insn_code = CODE_FOR_tstsi;
-#endif
-#ifdef HAVE_tstdi
-  if (HAVE_tstdi)
-    tst_optab->handlers[(int) DImode].insn_code = CODE_FOR_tstdi;
-#endif
-#ifdef HAVE_tstti
-  if (HAVE_tstti)
-    tst_optab->handlers[(int) TImode].insn_code = CODE_FOR_tstti;
-#endif
-#ifdef HAVE_tstsf
-  if (HAVE_tstsf)
-    tst_optab->handlers[(int) SFmode].insn_code = CODE_FOR_tstsf;
-#endif
-#ifdef HAVE_tstdf
-  if (HAVE_tstdf)
-    tst_optab->handlers[(int) DFmode].insn_code = CODE_FOR_tstdf;
-#endif
-#ifdef HAVE_tstxf
-  if (HAVE_tstxf)
-    tst_optab->handlers[(int) XFmode].insn_code = CODE_FOR_tstxf;
-#endif
-#ifdef HAVE_tsttf
-  if (HAVE_tsttf)
-    tst_optab->handlers[(int) TFmode].insn_code = CODE_FOR_tsttf;
-#endif
-
-#ifdef HAVE_beq
-  if (HAVE_beq)
-    bcc_gen_fctn[(int) EQ] = gen_beq;
-#endif
-#ifdef HAVE_bne
-  if (HAVE_bne)
-    bcc_gen_fctn[(int) NE] = gen_bne;
-#endif
-#ifdef HAVE_bgt
-  if (HAVE_bgt)
-    bcc_gen_fctn[(int) GT] = gen_bgt;
-#endif
-#ifdef HAVE_bge
-  if (HAVE_bge)
-    bcc_gen_fctn[(int) GE] = gen_bge;
-#endif
-#ifdef HAVE_bgtu
-  if (HAVE_bgtu)
-    bcc_gen_fctn[(int) GTU] = gen_bgtu;
-#endif
-#ifdef HAVE_bgeu
-  if (HAVE_bgeu)
-    bcc_gen_fctn[(int) GEU] = gen_bgeu;
-#endif
-#ifdef HAVE_blt
-  if (HAVE_blt)
-    bcc_gen_fctn[(int) LT] = gen_blt;
-#endif
-#ifdef HAVE_ble
-  if (HAVE_ble)
-    bcc_gen_fctn[(int) LE] = gen_ble;
-#endif
-#ifdef HAVE_bltu
-  if (HAVE_bltu)
-    bcc_gen_fctn[(int) LTU] = gen_bltu;
-#endif
-#ifdef HAVE_bleu
-  if (HAVE_bleu)
-    bcc_gen_fctn[(int) LEU] = gen_bleu;
-#endif
-
-  for (i = 0; i < NUM_RTX_CODE; i++)
-    setcc_gen_code[i] = CODE_FOR_nothing;
-
-#ifdef HAVE_seq
-  if (HAVE_seq)
-    setcc_gen_code[(int) EQ] = CODE_FOR_seq;
-#endif
-#ifdef HAVE_sne
-  if (HAVE_sne)
-    setcc_gen_code[(int) NE] = CODE_FOR_sne;
-#endif
-#ifdef HAVE_sgt
-  if (HAVE_sgt)
-    setcc_gen_code[(int) GT] = CODE_FOR_sgt;
-#endif
-#ifdef HAVE_sge
-  if (HAVE_sge)
-    setcc_gen_code[(int) GE] = CODE_FOR_sge;
-#endif
-#ifdef HAVE_sgtu
-  if (HAVE_sgtu)
-    setcc_gen_code[(int) GTU] = CODE_FOR_sgtu;
-#endif
-#ifdef HAVE_sgeu
-  if (HAVE_sgeu)
-    setcc_gen_code[(int) GEU] = CODE_FOR_sgeu;
-#endif
-#ifdef HAVE_slt
-  if (HAVE_slt)
-    setcc_gen_code[(int) LT] = CODE_FOR_slt;
-#endif
-#ifdef HAVE_sle
-  if (HAVE_sle)
-    setcc_gen_code[(int) LE] = CODE_FOR_sle;
-#endif
-#ifdef HAVE_sltu
-  if (HAVE_sltu)
-    setcc_gen_code[(int) LTU] = CODE_FOR_sltu;
-#endif
-#ifdef HAVE_sleu
-  if (HAVE_sleu)
-    setcc_gen_code[(int) LEU] = CODE_FOR_sleu;
+  /* The ffs function operates on `int'.  */
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
 #endif
+  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc
+    = gen_rtx (SYMBOL_REF, Pmode, "ffs");
 
   extendsfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfdf2");
   extendsfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsfxf2");
@@ -5146,6 +4249,15 @@ init_optabs ()
   memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
   bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
 
+  throw_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__throw");
+
+  eqhf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqhf2");
+  nehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nehf2");
+  gthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gthf2");
+  gehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gehf2");
+  lthf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lthf2");
+  lehf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lehf2");
+
   eqsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqsf2");
   nesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nesf2");
   gtsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtsf2");
@@ -5221,11 +4333,16 @@ init_optabs ()
   fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfsi");
   fixunstfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfdi");
   fixunstfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfti");
+
+#ifdef INIT_TARGET_OPTABS
+  /* Allow the target to add more libcalls or rename some, etc.  */
+  INIT_TARGET_OPTABS;
+#endif
 }
 \f
 #ifdef BROKEN_LDEXP
 
-/* SCO 3.2 apparently has a broken ldexp. */
+/* SCO 3.2 apparently has a broken ldexp.  */
 
 double
 ldexp(x,n)