OSDN Git Service

* rtl.h (rtx_def): Update documentation.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 9f14427..83235f7 100644 (file)
@@ -1,5 +1,5 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,10 +15,12 @@ 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"
+#include "system.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
@@ -28,7 +30,6 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
-#include <ctype.h>
 
 /* Each optab contains info on how this target machine
    can perform a particular operation
@@ -42,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;
@@ -57,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;
@@ -86,7 +88,7 @@ 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. */
+/* 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];
@@ -116,6 +118,22 @@ rtx bcmp_libfunc;
 rtx memset_libfunc;
 rtx bzero_libfunc;
 
+rtx throw_libfunc;
+rtx rethrow_libfunc;
+rtx sjthrow_libfunc;
+rtx sjpopnthrow_libfunc;
+rtx terminate_libfunc;
+rtx setjmp_libfunc;
+rtx longjmp_libfunc;
+rtx eh_rtime_match_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;
@@ -192,8 +210,14 @@ rtx fixunstfsi_libfunc;
 rtx fixunstfdi_libfunc;
 rtx fixunstfti_libfunc;
 
-/* from emit-rtl.c */
-extern rtx gen_highpart ();
+rtx chkr_check_addr_libfunc;
+rtx chkr_set_right_libfunc;
+rtx chkr_copy_bitmap_libfunc;
+rtx chkr_check_exec_libfunc;
+rtx chkr_check_str_libfunc;
+
+rtx profile_function_entry_libfunc;
+rtx profile_function_exit_libfunc;
 
 /* Indexed by the rtx-code for a conditional (eg. EQ, LT,...)
    gives the gen_function to make a branch to test that condition.  */
@@ -206,9 +230,18 @@ rtxfun bcc_gen_fctn[NUM_RTX_CODE];
 
 enum insn_code setcc_gen_code[NUM_RTX_CODE];
 
+#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, int, int));
-static void emit_float_lib_cmp PROTO((rtx, rtx, enum rtx_code));
+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,
@@ -218,7 +251,9 @@ 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));
+#ifdef HAVE_conditional_trap
+static void init_traps PROTO((void));
+#endif
 \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
@@ -263,13 +298,13 @@ add_equal_note (seq, target, code, op0, op1)
        return 0;
 
   if (GET_RTX_CLASS (code) == '1')
-    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0));
+    note = gen_rtx_fmt_e (code, GET_MODE (target), copy_rtx (op0));
   else
-    note = gen_rtx (code, GET_MODE (target), copy_rtx (op0), copy_rtx (op1));
+    note = gen_rtx_fmt_ee (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,
-              REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)));
+    = gen_rtx_EXPR_LIST (REG_EQUAL, note,
+                        REG_NOTES (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1)));
 
   return 1;
 }
@@ -300,13 +335,13 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
   /* 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);
+    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_insn (gen_rtx_CLOBBER (VOIDmode, result));
   emit_move_insn (gen_lowpart (GET_MODE (op), result), op);
   return result;
 }
@@ -331,13 +366,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);
@@ -373,8 +410,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 ();
@@ -385,7 +422,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;
 
@@ -419,7 +458,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
@@ -436,20 +475,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))
@@ -486,12 +529,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
@@ -520,8 +566,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
            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)
+                || binoptab == smul_optab || binoptab == ashl_optab)
                && class == MODE_INT)
              no_extend = 1;
 
@@ -529,8 +574,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
            /* The second operand of a shift must always be extended.  */
            xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
-                                 no_extend && binoptab != ashl_optab
-                                 && binoptab != lshl_optab);
+                                 no_extend && binoptab != ashl_optab);
 
            temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
                                 unsignedp, OPTAB_DIRECT);
@@ -575,7 +619,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);
        }
@@ -583,19 +631,23 @@ 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, copy_rtx (op0), copy_rtx (op1));
-      else
-       equiv_value = 0;
+      if (i == GET_MODE_BITSIZE (mode) / BITS_PER_WORD)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value
+             = gen_rtx_fmt_ee (binoptab->code, mode,
+                               copy_rtx (op0), copy_rtx (op1));
+         else
+           equiv_value = 0;
 
-      emit_no_conflict_block (insns, target, op0, op1, equiv_value);
-      return target;
+         emit_no_conflict_block (insns, target, op0, op1, equiv_value);
+         return target;
+       }
     }
 
   /* Synthesize double word shifts from single word shifts.  */
-  if ((binoptab == lshl_optab || binoptab == lshr_optab
-       || binoptab == ashl_optab || binoptab == ashr_optab)
+  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
@@ -603,7 +655,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && 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 insns, inter, equiv_value;
       rtx into_target, outof_target;
       rtx into_input, outof_input;
       int shift_count, left_shift, outof_word;
@@ -622,7 +674,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
         they differ depending on the direction of the shift and
         WORDS_BIG_ENDIAN.  */
 
-      left_shift = (binoptab == ashl_optab || binoptab == lshl_optab);
+      left_shift = binoptab == ashl_optab;
       outof_word = left_shift ^ ! WORDS_BIG_ENDIAN;
 
       outof_target = operand_subword (target, outof_word, 1, mode);
@@ -633,35 +685,36 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       if (shift_count >= BITS_PER_WORD)
        {
-         emit_move_insn (into_target,
-                         expand_binop (word_mode, binoptab,
-                                       outof_input,
-                                       GEN_INT (shift_count - BITS_PER_WORD),
-                                       into_target, unsignedp, methods));
+         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 (binoptab != ashr_optab)
-           emit_move_insn (outof_target, CONST0_RTX (word_mode));
-         else
-           emit_move_insn (outof_target,
-                           expand_binop (word_mode, binoptab,
-                                         outof_input,
-                                         GEN_INT (BITS_PER_WORD - 1),
-                                         outof_target, unsignedp, methods));
+         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
        {
-         rtx carries, into_temp;
+         rtx carries;
          optab reverse_unsigned_shift, unsigned_shift;
 
          /* 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.  */
 
-         /* We use ashl_optab instead of lshl_optab, because ashl is
-            guaranteed to exist, but lshl may or may not exist.  */
-
          reverse_unsigned_shift = (left_shift ? lshr_optab : ashl_optab);
 
          /* For a shift of less than BITS_PER_WORD, to compute the word
@@ -673,32 +726,42 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          carries = expand_binop (word_mode, reverse_unsigned_shift,
                                  outof_input,
                                  GEN_INT (BITS_PER_WORD - shift_count),
-                                 0, unsignedp, methods);
-
-         emit_move_insn (outof_target,
-                         expand_binop (word_mode, binoptab,
-                                       outof_input,
-                                       op1, outof_target, unsignedp, methods));
-         into_temp = expand_binop (word_mode, unsigned_shift,
-                                   into_input,
-                                   op1, 0, unsignedp, methods);
-
-         emit_move_insn (into_target,
-                         expand_binop (word_mode, ior_optab,
-                                       carries, into_temp,
-                                       into_target, unsignedp, methods));
+                                 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 (binoptab->code != UNKNOWN)
-       equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
-      else
-       equiv_value = 0;
+      if (inter != 0)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value = gen_rtx_fmt_ee (binoptab->code, mode, op0, op1);
+         else
+           equiv_value = 0;
 
-      emit_no_conflict_block (insns, target, op0, op1, equiv_value);
-      return target;
+         emit_no_conflict_block (insns, target, op0, op1, equiv_value);
+         return target;
+       }
     }
 
   /* Synthesize double word rotates from single word shifts.  */
@@ -712,6 +775,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       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
@@ -742,6 +806,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          /* This is just a word swap.  */
          emit_move_insn (outof_target, into_input);
          emit_move_insn (into_target, outof_input);
+         inter = const0_rtx;
        }
       else
        {
@@ -768,43 +833,57 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
          into_temp1 = expand_binop (word_mode, unsigned_shift,
                                     outof_input, first_shift_count,
-                                    0, unsignedp, methods);
+                                    NULL_RTX, unsignedp, next_methods);
          into_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
                                     into_input, second_shift_count,
-                                    into_target, unsignedp, methods);
-         emit_move_insn (into_target,
-                         expand_binop (word_mode, ior_optab,
-                                       into_temp1, into_temp2,
-                                       into_target, unsignedp, methods));
+                                    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,
-                                     0, unsignedp, methods);
+                                     NULL_RTX, unsignedp, next_methods);
          outof_temp2 = expand_binop (word_mode, reverse_unsigned_shift,
                                      outof_input, second_shift_count,
-                                     outof_target, unsignedp, methods);
-         emit_move_insn (outof_target,
-                         expand_binop (word_mode, ior_optab,
-                                       outof_temp1, outof_temp2,
-                                       outof_target, unsignedp, methods));
+                                     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 (binoptab->code != UNKNOWN)
-       equiv_value = gen_rtx (binoptab->code, mode, op0, op1);
-      else
-       equiv_value = 0;
+      if (inter != 0)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value = gen_rtx_fmt_ee (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;
+         /* 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.  */
@@ -839,7 +918,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       /* Indicate for flow that the entire target reg is being set.  */
       if (GET_CODE (target) == REG)
-       emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+       emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
       /* Do the actual arithmetic.  */
       for (i = 0; i < nwords; i++)
@@ -853,7 +932,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;
 
@@ -861,12 +940,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
            {
              /* Store carry from main add/subtract.  */
              carry_out = gen_reg_rtx (word_mode);
-             carry_out = emit_store_flag (carry_out,
-                                          binoptab == add_optab ? LTU : GTU,
-                                          x, op0_piece,
-                                          word_mode, 1, normalizep);
-             if (!carry_out)
-               break;
+             carry_out = emit_store_flag_force (carry_out,
+                                                (binoptab == add_optab
+                                                 ? LTU : GTU),
+                                                x, op0_piece,
+                                                word_mode, 1, normalizep);
            }
 
          if (i > 0)
@@ -875,24 +953,27 @@ 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)
                {
                  /* THIS CODE HAS NOT BEEN TESTED.  */
                  /* Get out carry from adding/subtracting carry in.  */
-                 carry_tmp = emit_store_flag (carry_tmp,
-                                              binoptab == add_optab
-                                                ? LTU : GTU,
-                                              x, carry_in,
-                                              word_mode, 1, normalizep);
+                 carry_tmp = emit_store_flag_force (carry_tmp,
+                                                    binoptab == add_optab
+                                                    ? 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;
                }
            }
@@ -902,14 +983,17 @@ 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);
-         REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
-                                     gen_rtx (binoptab->code, mode,
-                                              copy_rtx (xop0),
-                                              copy_rtx (xop1)),
-                                     REG_NOTES (temp));
+         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+           {
+             rtx temp = emit_move_insn (target, target);
+
+             REG_NOTES (temp)
+               = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                    gen_rtx_fmt_ee (binoptab->code, mode,
+                                                    copy_rtx (xop0),
+                                                    copy_rtx (xop1)),
+                                    REG_NOTES (temp));
+           }
          return target;
        }
       else
@@ -988,7 +1072,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.
@@ -1015,33 +1100,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);
            }
        }
 
@@ -1057,34 +1142,41 @@ 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);
 
-             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 = emit_move_insn (product, product);
-             REG_NOTES (temp) = gen_rtx (EXPR_LIST, REG_EQUAL,
-                                         gen_rtx (MULT, mode, copy_rtx (op0),
-                                                  copy_rtx (op1)),
-                                         REG_NOTES (temp));
+         if (temp != 0 && temp != product_high)
+           emit_move_insn (product_high, temp);
 
+         if (temp != 0)
+           {
+             if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+               {
+                 temp = emit_move_insn (product, product);
+                 REG_NOTES (temp)
+                   = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                        gen_rtx_fmt_ee (MULT, mode,
+                                                        copy_rtx (op0),
+                                                        copy_rtx (op1)),
+                                        REG_NOTES (temp));
+               }
              return product;
            }
        }
@@ -1106,15 +1198,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
@@ -1149,7 +1238,7 @@ 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)
@@ -1160,7 +1249,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          /* (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)
@@ -1173,8 +1265,12 @@ 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:
@@ -1182,32 +1278,49 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
          if (imag0 && imag1)
            {
+             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);
 
-             res = expand_binop (submode, sub_optab,
-                                 expand_binop (submode, binoptab, real0,
-                                               real1, 0, unsignedp, methods),
-                                 expand_binop (submode, binoptab, imag0,
-                                               imag1, 0, unsignedp, methods),
+             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 (res != realr)
+             if (res == 0)
+               break;
+             else if (res != realr)
                emit_move_insn (realr, res);
 
-             res = expand_binop (submode, add_optab,
-                                 expand_binop (submode, binoptab,
-                                               real0, imag1,
-                                               0, unsignedp, methods),
-                                 expand_binop (submode, binoptab,
-                                               real1, imag0,
-                                               0, unsignedp, methods),
+             temp1 = expand_binop (submode, binoptab, real0, imag1,
+                                   NULL_RTX, unsignedp, methods);
+
+             temp2 = expand_binop (submode, binoptab, real1, imag0,
+                                   NULL_RTX, 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
            {
@@ -1217,110 +1330,171 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
              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)
+             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:
          /* (a+ib) / (c+id) = ((ac+bd)/(cc+dd)) + i((bc-ad)/(cc+dd)) */
          
-         if (! imag1)
-           {   /* (a+ib) / (c+i0) = (a/c) + i(b/c) */
+         if (imag1 == 0)
+           {
+             /* (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' */
-             res = expand_binop (submode, binoptab, real0, real1,
-                                 realr, unsignedp, methods);
-             if (res != realr)
+             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                  /* Divisor is of complex type */
-           {                   /* X/(a+ib) */
 
+             ok = 1;
+           }
+         else
+           {
+             /* Divisor is of complex type:
+                X/(a+ib) */
              rtx divisor;
-             rtx real_t;
-             rtx imag_t;
+             rtx real_t, imag_t;
+             rtx temp1, temp2;
              
-             optab mulopt = unsignedp ? umul_widen_optab : smul_optab;
-
              /* Don't fetch these from memory more than once.  */
              real0 = force_reg (submode, real0);
              real1 = force_reg (submode, real1);
-             if (imag0)
+
+             if (imag0 != 0)
                imag0 = force_reg (submode, imag0);
+
              imag1 = force_reg (submode, imag1);
 
              /* Divisor: c*c + d*d */
-             divisor = 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)      /* ((a)(c-id))/divisor */
-               {       /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */
+             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)
+               {
+                 /* ((a)(c-id))/divisor */
+                 /* (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)) */
+
                  /* Calculate the dividend */
-                 real_t = expand_binop (submode, mulopt, real0, real1,
-                                        0, unsignedp, methods);
+                 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              /* ((a+ib)(c-id))/divider */
+             else
                {
+                 /* ((a+ib)(c-id))/divider */
                  /* Calculate the dividend */
-                 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);
+                 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,
-                                                      imag0, real1,
-                                                      0, unsignedp, methods),
-                                        expand_binop (submode, mulopt,
-                                                      real0, imag1,
-                                                      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, divisor,
-                                 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, divisor,
-                                 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;
          
@@ -1331,15 +1505,19 @@ 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, copy_rtx (op0), copy_rtx (op1));
-      else
-       equiv_value = 0;
+      if (ok)
+       {
+         if (binoptab->code != UNKNOWN)
+           equiv_value
+             = gen_rtx_fmt_ee (binoptab->code, mode,
+                               copy_rtx (op0), copy_rtx (op1));
+         else
+           equiv_value = 0;
          
-      emit_no_conflict_block (seq, target, op0, op1, equiv_value);
+         emit_no_conflict_block (seq, target, op0, op1, equiv_value);
       
-      return target;
+         return target;
+       }
     }
 
   /* It can't be open-coded in this mode.
@@ -1349,9 +1527,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && (methods == OPTAB_LIB || methods == OPTAB_LIB_WIDEN))
     {
       rtx insns;
-      rtx funexp = binoptab->handlers[(int) mode].libfunc;
       rtx op1x = op1;
       enum machine_mode op1_mode = mode;
+      rtx value;
 
       start_sequence ();
 
@@ -1363,17 +1541,22 @@ 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),
-                         gen_rtx (binoptab->code, mode, op0, op1));
+      emit_libcall_block (insns, target, value,
+                         gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
 
       return target;
     }
@@ -1418,8 +1601,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              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)
+                  || binoptab == smul_optab || binoptab == ashl_optab)
                  && class == MODE_INT)
                no_extend = 1;
 
@@ -1428,8 +1610,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
              /* The second operand of a shift must always be extended.  */
              xop1 = widen_operand (xop1, wider_mode, mode, unsignedp,
-                                   no_extend && binoptab != ashl_optab
-                                   && binoptab != lshl_optab);
+                                   no_extend && binoptab != ashl_optab);
 
              temp = expand_binop (wider_mode, binoptab, xop0, xop1, NULL_RTX,
                                   unsignedp, methods);
@@ -1519,7 +1700,7 @@ sign_expand_binop (mode, uoptab, soptab, op0, op1, target, unsignedp, methods)
    [(set TARG0 (operate OP0 OP1)) (set TARG1 (operate ...))].
 
    Either TARG0 or TARG1 may be zero, but what that means is that
-   that result is not actually wanted.  We will generate it into
+   the result is not actually wanted.  We will generate it into
    a dummy pseudo-reg and discard it.  They may not both be zero.
 
    Returns 1 if this operation can be performed; 0 if not.  */
@@ -1789,7 +1970,8 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       end_sequence ();
 
       emit_no_conflict_block (insns, target, op0, NULL_RTX,
-                             gen_rtx (unoptab->code, mode, copy_rtx (op0)));
+                             gen_rtx_fmt_e (unoptab->code, mode,
+                                            copy_rtx (op0)));
       return target;
     }
 
@@ -1833,7 +2015,8 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       end_sequence ();
 
       emit_no_conflict_block (seq, target, op0, 0,
-                             gen_rtx (unoptab->code, mode, copy_rtx (op0)));
+                             gen_rtx_fmt_e (unoptab->code, mode,
+                                            copy_rtx (op0)));
       return target;
     }
 
@@ -1841,20 +2024,20 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
   if (unoptab->handlers[(int) mode].libfunc)
     {
       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),
-                         gen_rtx (unoptab->code, mode, op0));
+      emit_libcall_block (insns, target, value,
+                         gen_rtx_fmt_e (unoptab->code, mode, op0));
 
       return target;
     }
@@ -1902,6 +2085,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
@@ -1912,6 +2106,97 @@ 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 if extension is needed.  */
+
+rtx
+expand_abs (mode, op0, target, unsignedp, safe)
+     enum machine_mode mode;
+     rtx op0;
+     rtx target;
+     int unsignedp;
+     int safe;
+{
+  rtx temp, op1;
+
+  /* First try to do it with a special abs instruction.  */
+  temp = expand_unop (mode, abs_optab, op0, target, 0);
+  if (temp != 0)
+    return temp;
+
+  /* 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 (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
+    {
+      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;
+    }
+
+  /* If that does not win, use conditional jump and negate.  */
+
+  /* It is safe to use the target if it is the same
+     as the source if this is also a pseudo register */
+  if (op0 == target && GET_CODE (op0) == REG
+      && REGNO (op0) >= FIRST_PSEUDO_REGISTER)
+    safe = 1;
+
+  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
@@ -2027,12 +2312,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)
@@ -2045,20 +2333,20 @@ expand_complex_abs (mode, op0, target, unsignedp)
   if (abs_optab->handlers[(int) mode].libfunc)
     {
       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),
-                         gen_rtx (abs_optab->code, mode, op0));
+      emit_libcall_block (insns, target, value,
+                         gen_rtx_fmt_e (abs_optab->code, mode, op0));
 
       return target;
     }
@@ -2120,7 +2408,10 @@ emit_unop_insn (icode, target, op0, code)
 
   op0 = protect_from_queue (op0, 0);
 
-  if (flag_force_mem)
+  /* Sign and zero 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 && code != ZERO_EXTEND)
     op0 = force_not_mem (op0);
 
   /* Now, if insn does not accept our operands, put them into pseudos.  */
@@ -2157,9 +2448,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.
@@ -2168,7 +2457,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.  */
 
@@ -2183,6 +2473,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.  */
@@ -2193,9 +2488,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)
@@ -2230,7 +2522,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
   /* Now write the CLOBBER of the output, followed by the setting of each
      of the words, followed by the final copy.  */
   if (target != op0 && target != op1)
-    emit_insn (gen_rtx (CLOBBER, VOIDmode, target));
+    emit_insn (gen_rtx_CLOBBER (VOIDmode, target));
 
   for (insn = insns; insn; insn = next)
     {
@@ -2238,12 +2530,12 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
       add_insn (insn);
 
       if (op1 && GET_CODE (op1) == REG)
-       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op1,
-                                   REG_NOTES (insn));
+       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op1,
+                                             REG_NOTES (insn));
 
       if (op0 && GET_CODE (op0) == REG)
-       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_NO_CONFLICT, op0,
-                                   REG_NOTES (insn));
+       REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_NO_CONFLICT, op0,
+                                             REG_NOTES (insn));
     }
 
   if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
@@ -2252,7 +2544,7 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
       last = emit_move_insn (target, target);
       if (equiv)
        REG_NOTES (last)
-         = gen_rtx (EXPR_LIST, REG_EQUAL, equiv, REG_NOTES (last));
+         = gen_rtx_EXPR_LIST (REG_EQUAL, equiv, REG_NOTES (last));
     }
   else
     last = get_last_insn ();
@@ -2263,9 +2555,9 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
     first = NEXT_INSN (prev);
 
   /* Encapsulate the block so it gets manipulated as a unit.  */
-  REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
-                              REG_NOTES (first));
-  REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last));
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+                                        REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
 
   return last;
 }
@@ -2304,6 +2596,21 @@ emit_libcall_block (insns, target, result, equiv)
 {
   rtx prev, next, first, last, insn;
 
+  /* look for any CALL_INSNs in this sequence, and attach a REG_EH_REGION
+     reg note to indicate that this call cannot throw. (Unless there is
+     already a REG_EH_REGION note.) */
+
+  for (insn = insns; insn; insn = NEXT_INSN (insn))
+    {
+      if (GET_CODE (insn) == CALL_INSN)
+        {
+          rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+          if (note == NULL_RTX)
+            REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, GEN_INT (0),
+                                                  REG_NOTES (insn));
+        }
+    }
+
   /* First emit all insns that set pseudos.  Remove them from the list as
      we go.  Avoid insns that set pseudos which were referenced in previous
      insns.  These can be generated by move_by_pieces, for example,
@@ -2348,8 +2655,10 @@ emit_libcall_block (insns, target, result, equiv)
     }
 
   last = emit_move_insn (target, result);
-  REG_NOTES (last) = gen_rtx (EXPR_LIST,
-                             REG_EQUAL, copy_rtx (equiv), REG_NOTES (last));
+  if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
+      != CODE_FOR_nothing)
+    REG_NOTES (last) = gen_rtx_EXPR_LIST (REG_EQUAL, copy_rtx (equiv),
+                                         REG_NOTES (last));
 
   if (prev == 0)
     first = get_insns ();
@@ -2357,9 +2666,9 @@ emit_libcall_block (insns, target, result, equiv)
     first = NEXT_INSN (prev);
 
   /* Encapsulate the block so it gets manipulated as a unit.  */
-  REG_NOTES (first) = gen_rtx (INSN_LIST, REG_LIBCALL, last,
-                              REG_NOTES (first));
-  REG_NOTES (last) = gen_rtx (INSN_LIST, REG_RETVAL, first, REG_NOTES (last));
+  REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+                                        REG_NOTES (first));
+  REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
 }
 \f
 /* Generate code to store zero in X.  */
@@ -2428,6 +2737,14 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
   if (CONSTANT_P (y) && preserve_subexpressions_p () && rtx_cost (y, COMPARE) > 2)
     y = force_reg (mode, y);
 
+#ifdef HAVE_cc0
+  /* Abort if we have a non-canonical comparison.  The RTL documentation
+     states that canonical comparisons are required only for targets which
+     have cc0.  */
+  if (CONSTANT_P (x) && ! CONSTANT_P (y))
+    abort();
+#endif
+
   /* Don't let both operands fail to indicate the mode.  */
   if (GET_MODE (x) == VOIDmode && GET_MODE (y) == VOIDmode)
     x = force_reg (mode, x);
@@ -2486,18 +2803,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);
+                            convert_to_mode (TYPE_MODE (integer_type_node),
+                                             size,
+                                             TREE_UNSIGNED (integer_type_node)),
+                            TYPE_MODE (integer_type_node));
 #endif
-         emit_cmp_insn (hard_libcall_value (TYPE_MODE (integer_type_node)),
+
+         /* 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);
        }
@@ -2574,6 +2905,8 @@ 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)
@@ -2582,11 +2915,16 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
       emit_library_call (libfunc, 1,
                         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 (word_mode), const1_rtx,
+      emit_cmp_insn (result, const1_rtx,
                     comparison, NULL_RTX, word_mode, unsignedp, 0);
       return;
     }
@@ -2598,6 +2936,52 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
     abort ();
 }
 
+/* Generate code to compare X with Y so that the condition codes are
+   set and to jump to LABEL if the condition is true.  If X is a
+   constant and Y is not a constant, then the comparison is swapped to
+   ensure that the comparison RTL has the canonical form.
+
+   MODE is the mode of the inputs (in case they are const_int).
+   UNSIGNEDP nonzero says that X and Y are unsigned;
+   this matters if they need to be widened.
+
+   If they have mode BLKmode, then SIZE specifies the size of both X and Y,
+   and ALIGN specifies the known shared alignment of X and Y.
+
+   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   It is ignored for fixed-point and block comparisons;
+   it is used only for floating-point comparisons.  */
+
+void
+emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
+     rtx x, y;
+     enum rtx_code comparison;
+     rtx size;
+     enum machine_mode mode;
+     int unsignedp;
+     int align;
+     rtx label;
+{
+  rtx op0;
+  rtx op1;
+         
+  if (CONSTANT_P (x))
+    {
+      /* Swap operands and condition to ensure canonical RTL.  */
+      op0 = y;
+      op1 = x;
+      comparison = swap_condition (comparison);
+    }
+  else
+    {
+      op0 = x;
+      op1 = y;
+    }
+  emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align);
+  emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+}
+
+
 /* Nonzero if a compare of mode MODE can be done straightforwardly
    (without splitting it into pieces).  */
 
@@ -2618,15 +3002,46 @@ 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;
+
+      case LE:
+       libfunc = lehf2_libfunc;
+       break;
 
-  if (mode == SFmode)
+      default:
+       break;
+      }
+  else if (mode == SFmode)
     switch (comparison)
       {
       case EQ:
@@ -2652,6 +3067,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = lesf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == DFmode)
     switch (comparison)
@@ -2679,6 +3097,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = ledf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == XFmode)
     switch (comparison)
@@ -2706,6 +3127,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = lexf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == TFmode)
     switch (comparison)
@@ -2733,6 +3157,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = letf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else
     {
@@ -2756,10 +3183,19 @@ emit_float_lib_cmp (x, y, comparison)
       abort ();
     }
 
+  if (libfunc == 0)
+    abort ();
+
   emit_library_call (libfunc, 1,
                     word_mode, 2, x, mode, y, mode);
 
-  emit_cmp_insn (hard_libcall_value (word_mode), const0_rtx, comparison,
+  /* 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 (result, const0_rtx, comparison,
                 NULL_RTX, word_mode, 0, 0);
 }
 \f
@@ -2777,6 +3213,147 @@ emit_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))
+      && (GET_MODE_CLASS (GET_MODE (op1)) != MODE_FLOAT
+         || TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT || flag_fast_math))
+    {
+      tem = op2;
+      op2 = op3;
+      op3 = tem;
+      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.
 
@@ -2879,20 +3456,18 @@ gen_move_insn (x, y)
          x = gen_lowpart_common (tmode, x1);
          if (x == 0 && GET_CODE (x1) == MEM)
            {
-             x = gen_rtx (MEM, tmode, XEXP (x1, 0));
+             x = gen_rtx_MEM (tmode, XEXP (x1, 0));
              RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (x1);
-             MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (x1);
-             MEM_VOLATILE_P (x) = MEM_VOLATILE_P (x1);
+             MEM_COPY_ATTRIBUTES (x, x1);
              copy_replacements (x1, x);
            }
 
          y = gen_lowpart_common (tmode, y1);
          if (y == 0 && GET_CODE (y1) == MEM)
            {
-             y = gen_rtx (MEM, tmode, XEXP (y1, 0));
+             y = gen_rtx_MEM (tmode, XEXP (y1, 0));
              RTX_UNCHANGING_P (y) = RTX_UNCHANGING_P (y1);
-             MEM_IN_STRUCT_P (y) = MEM_IN_STRUCT_P (y1);
-             MEM_VOLATILE_P (y) = MEM_VOLATILE_P (y1);
+             MEM_COPY_ATTRIBUTES (y, y1);
              copy_replacements (y1, y);
            }
        }
@@ -3048,23 +3623,75 @@ expand_float (to, from, unsignedp)
       /* 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.
-            This may cause rounding problems, unfortunately.  */
+         /* 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_MODE (to) != fmode
-         || GET_CODE (to) != REG || REGNO (to) <= LAST_VIRTUAL_REGISTER)
+         || GET_CODE (to) != REG || REGNO (to) < FIRST_PSEUDO_REGISTER)
        target = gen_reg_rtx (fmode);
 
       /* Convert as signed integer to floating.  */
@@ -3076,26 +3703,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 (fmode, add_optab, target,
-                          immed_real_const_1 (offset, fmode),
+                          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);
@@ -3155,14 +3785,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)),
-                         gen_rtx (FLOAT, GET_MODE (to), from));
+      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.  */
 
@@ -3259,7 +3893,7 @@ expand_fix (to, from, unsignedp)
 
          bitsize = GET_MODE_BITSIZE (GET_MODE (to));
          offset = REAL_VALUE_LDEXP (dconst1, bitsize - 1);
-         limit = immed_real_const_1 (offset, fmode);
+         limit = CONST_DOUBLE_FROM_REAL_VALUE (offset, fmode);
          lab1 = gen_label_rtx ();
          lab2 = gen_label_rtx ();
 
@@ -3299,13 +3933,18 @@ expand_fix (to, from, unsignedp)
 
          emit_label (lab2);
 
-         /* Make a place for a REG_NOTE and add it.  */
-         insn = emit_move_insn (to, to);
-         REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL,
-                                     gen_rtx (UNSIGNED_FIX, GET_MODE (to),
-                                              copy_rtx (from)),
-                                     REG_NOTES (insn));
-
+         if (mov_optab->handlers[(int) GET_MODE (to)].insn_code
+             != CODE_FOR_nothing)
+           {
+             /* Make a place for a REG_NOTE and add it.  */
+             insn = emit_move_insn (to, to);
+             REG_NOTES (insn)
+               = gen_rtx_EXPR_LIST (REG_EQUAL,
+                                    gen_rtx_fmt_e (UNSIGNED_FIX,
+                                                   GET_MODE (to),
+                                                   copy_rtx (from)),
+                                    REG_NOTES (insn));
+           }
          return;
        }
 #endif
@@ -3370,6 +4009,7 @@ expand_fix (to, from, unsignedp)
   if (libfcn)
     {
       rtx insns;
+      rtx value;
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -3379,19 +4019,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,
-                                  GET_MODE (to), from));
+      emit_libcall_block (insns, target, value,
+                         gen_rtx_fmt_e (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
@@ -3436,7 +4081,7 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
     register int first_mode;
     register int last_mode;
     register char *opname;
-    register char suffix;
+    register int suffix;
 {
   register int mode;
   register unsigned opname_len = strlen (opname);
@@ -3457,11 +4102,11 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
       for (q = opname; *q; )
        *p++ = *q++;
       for (q = mname; *q; q++)
-       *p++ = tolower (*q);
+       *p++ = tolower ((unsigned char)*q);
       *p++ = suffix;
       *p++ = '\0';
       optable->handlers[(int) mode].libfunc
-       = gen_rtx (SYMBOL_REF, Pmode, libfunc_name);
+       = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
     }
 }
 
@@ -3474,7 +4119,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);
 }
@@ -3488,24 +4133,11 @@ 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);
 }
 
-/* Initialize the libfunc fields of an entire group of entries in some
-   optab which correspond to all complex floating modes.  The parameters
-   have the same meaning as similarly named ones for the `init_libfuncs'
-   routine.  (See above).  */
-
-static void
-init_complex_libfuncs (optable, opname, suffix)
-    register optab optable;
-    register char *opname;
-    register char suffix;
-{
-  init_libfuncs (optable, SCmode, TCmode, opname, suffix);
-}
 
 /* Call this once to initialize the contents of the optabs
    appropriately for the current target machine.  */
@@ -3513,7 +4145,11 @@ init_complex_libfuncs (optable, opname, suffix)
 void
 init_optabs ()
 {
-  int i, j;
+  int i;
+#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
+  int j;
+#endif
+
   enum insn_code *p;
 
   /* Start by initializing all tables to contain CODE_FOR_nothing.  */
@@ -3541,9 +4177,16 @@ init_optabs ()
   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);
@@ -3559,7 +4202,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);
@@ -3584,6 +4226,7 @@ init_optabs ()
   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;
@@ -3625,10 +4268,7 @@ init_optabs ()
   init_integral_libfuncs (xor_optab, "xor", '3');
   init_integral_libfuncs (ashl_optab, "ashl", '3');
   init_integral_libfuncs (ashr_optab, "ashr", '3');
-  init_integral_libfuncs (lshl_optab, "lshl", '3');
   init_integral_libfuncs (lshr_optab, "lshr", '3');
-  init_integral_libfuncs (rotl_optab, "rotl", '3');
-  init_integral_libfuncs (rotr_optab, "rotr", '3');
   init_integral_libfuncs (smin_optab, "min", '3');
   init_floating_libfuncs (smin_optab, "min", '3');
   init_integral_libfuncs (smax_optab, "max", '3');
@@ -3647,178 +4287,203 @@ init_optabs ()
 
 #ifdef MULSI3_LIBCALL
   smul_optab->handlers[(int) SImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, MULSI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, MULSI3_LIBCALL);
 #endif
 #ifdef MULDI3_LIBCALL
   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);
+    = gen_rtx_SYMBOL_REF (Pmode, MULDI3_LIBCALL);
 #endif
 
 #ifdef DIVSI3_LIBCALL
   sdiv_optab->handlers[(int) SImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, DIVSI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, DIVSI3_LIBCALL);
 #endif
 #ifdef DIVDI3_LIBCALL
   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);
+    = gen_rtx_SYMBOL_REF (Pmode, DIVDI3_LIBCALL);
 #endif
 
 #ifdef UDIVSI3_LIBCALL
   udiv_optab->handlers[(int) SImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UDIVSI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, UDIVSI3_LIBCALL);
 #endif
 #ifdef UDIVDI3_LIBCALL
   udiv_optab->handlers[(int) DImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UDIVDI3_LIBCALL);
+    = 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 MODSI3_LIBCALL
   smod_optab->handlers[(int) SImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, MODSI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, MODSI3_LIBCALL);
 #endif
 #ifdef MODDI3_LIBCALL
   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);
+    = gen_rtx_SYMBOL_REF (Pmode, MODDI3_LIBCALL);
 #endif
 
-
 #ifdef UMODSI3_LIBCALL
   umod_optab->handlers[(int) SImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UMODSI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, UMODSI3_LIBCALL);
 #endif
 #ifdef UMODDI3_LIBCALL
   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);
+    = gen_rtx_SYMBOL_REF (Pmode, UMODDI3_LIBCALL);
 #endif
 
   /* Use cabs for DC complex abs, since systems generally have cabs.
      Don't define any libcall for SCmode, so that cabs will be used.  */
   abs_optab->handlers[(int) DCmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, "cabs");
-
-  ffs_optab->handlers[(int) mode_for_size (BITS_PER_WORD, 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");
-  extendsftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extendsftf2");
-  extenddfxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddfxf2");
-  extenddftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__extenddftf2");
-
-  truncdfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncdfsf2");
-  truncxfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfsf2");
-  trunctfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfsf2");
-  truncxfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__truncxfdf2");
-  trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__trunctfdf2");
-
-  memcpy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcpy");
-  bcopy_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bcopy");
-  memcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memcmp");
-  bcmp_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gcc_bcmp");
-  memset_libfunc = gen_rtx (SYMBOL_REF, Pmode, "memset");
-  bzero_libfunc = gen_rtx (SYMBOL_REF, Pmode, "bzero");
-
-  eqsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqsf2");
-  nesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nesf2");
-  gtsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtsf2");
-  gesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gesf2");
-  ltsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltsf2");
-  lesf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lesf2");
-
-  eqdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqdf2");
-  nedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nedf2");
-  gtdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtdf2");
-  gedf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gedf2");
-  ltdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltdf2");
-  ledf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ledf2");
-
-  eqxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqxf2");
-  nexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__nexf2");
-  gtxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gtxf2");
-  gexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gexf2");
-  ltxf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__ltxf2");
-  lexf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lexf2");
-
-  eqtf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__eqtf2");
-  netf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__netf2");
-  gttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__gttf2");
-  getf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__getf2");
-  lttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__lttf2");
-  letf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__letf2");
-
-  floatsisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsisf");
-  floatdisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdisf");
-  floattisf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattisf");
-
-  floatsidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsidf");
-  floatdidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdidf");
-  floattidf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattidf");
-
-  floatsixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsixf");
-  floatdixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatdixf");
-  floattixf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattixf");
-
-  floatsitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatsitf");
-  floatditf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floatditf");
-  floattitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__floattitf");
-
-  fixsfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfsi");
-  fixsfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfdi");
-  fixsfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixsfti");
-
-  fixdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfsi");
-  fixdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfdi");
-  fixdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixdfti");
-
-  fixxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfsi");
-  fixxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfdi");
-  fixxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixxfti");
-
-  fixtfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfsi");
-  fixtfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfdi");
-  fixtfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixtfti");
-
-  fixunssfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfsi");
-  fixunssfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfdi");
-  fixunssfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunssfti");
-
-  fixunsdfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfsi");
-  fixunsdfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfdi");
-  fixunsdfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsdfti");
-
-  fixunsxfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfsi");
-  fixunsxfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfdi");
-  fixunsxfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunsxfti");
-
-  fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfsi");
-  fixunstfdi_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfdi");
-  fixunstfti_libfunc = gen_rtx (SYMBOL_REF, Pmode, "__fixunstfti");
+    = gen_rtx_SYMBOL_REF (Pmode, "cabs");
+
+  /* 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");
+  extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsftf2");
+  extenddfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddfxf2");
+  extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddftf2");
+
+  truncdfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncdfsf2");
+  truncxfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfsf2");
+  trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfsf2");
+  truncxfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfdf2");
+  trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfdf2");
+
+  memcpy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcpy");
+  bcopy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bcopy");
+  memcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcmp");
+  bcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gcc_bcmp");
+  memset_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memset");
+  bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
+
+  throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
+  rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
+  sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
+  sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
+  terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
+  eh_rtime_match_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eh_rtime_match");
+#ifndef DONT_USE_BUILTIN_SETJMP
+  setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_setjmp");
+  longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__builtin_longjmp");
+#else
+  setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "setjmp");
+  longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "longjmp");
+#endif
+
+  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");
+  gesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gesf2");
+  ltsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltsf2");
+  lesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lesf2");
+
+  eqdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqdf2");
+  nedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nedf2");
+  gtdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtdf2");
+  gedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gedf2");
+  ltdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltdf2");
+  ledf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ledf2");
+
+  eqxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqxf2");
+  nexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nexf2");
+  gtxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtxf2");
+  gexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gexf2");
+  ltxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltxf2");
+  lexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lexf2");
+
+  eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqtf2");
+  netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__netf2");
+  gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gttf2");
+  getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__getf2");
+  lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lttf2");
+  letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__letf2");
+
+  floatsisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsisf");
+  floatdisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdisf");
+  floattisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattisf");
+
+  floatsidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsidf");
+  floatdidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdidf");
+  floattidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattidf");
+
+  floatsixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsixf");
+  floatdixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdixf");
+  floattixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattixf");
+
+  floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsitf");
+  floatditf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatditf");
+  floattitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattitf");
+
+  fixsfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfsi");
+  fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfdi");
+  fixsfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfti");
+
+  fixdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfsi");
+  fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfdi");
+  fixdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfti");
+
+  fixxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfsi");
+  fixxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfdi");
+  fixxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfti");
+
+  fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfsi");
+  fixtfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfdi");
+  fixtfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfti");
+
+  fixunssfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfsi");
+  fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfdi");
+  fixunssfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfti");
+
+  fixunsdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfsi");
+  fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfdi");
+  fixunsdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfti");
+
+  fixunsxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfsi");
+  fixunsxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfdi");
+  fixunsxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfti");
+
+  fixunstfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfsi");
+  fixunstfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfdi");
+  fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti");
+
+  /* For check-memory-usage.  */
+  chkr_check_addr_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_addr");
+  chkr_set_right_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_set_right");
+  chkr_copy_bitmap_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_copy_bitmap");
+  chkr_check_exec_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_exec");
+  chkr_check_str_libfunc = gen_rtx_SYMBOL_REF (Pmode, "chkr_check_str");
+
+  /* For function entry/exit instrumentation.  */
+  profile_function_entry_libfunc
+    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_enter");
+  profile_function_exit_libfunc
+    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_exit");
+
+#ifdef HAVE_conditional_trap
+  init_traps ();
+#endif
+
+#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)
@@ -3832,3 +4497,49 @@ ldexp(x,n)
   return x;
 }
 #endif /* BROKEN_LDEXP */
+\f
+#ifdef HAVE_conditional_trap
+/* The insn generating function can not take an rtx_code argument.
+   TRAP_RTX is used as an rtx argument.  Its code is replaced with
+   the code to be used in the trap insn and all other fields are
+   ignored.
+
+   ??? Will need to change to support garbage collection.  */
+static rtx trap_rtx;
+
+static void
+init_traps ()
+{
+  if (HAVE_conditional_trap)
+    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+}
+#endif
+
+/* Generate insns to trap with code TCODE if OP1 and OP2 satisfy condition
+   CODE.  Return 0 on failure.  */
+
+rtx
+gen_cond_trap (code, op1, op2, tcode)
+  enum rtx_code code ATTRIBUTE_UNUSED;
+  rtx op1, op2 ATTRIBUTE_UNUSED, tcode ATTRIBUTE_UNUSED;
+{
+  enum machine_mode mode = GET_MODE (op1);
+
+  if (mode == VOIDmode)
+    return 0;
+
+#ifdef HAVE_conditional_trap
+  if (HAVE_conditional_trap
+      && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      rtx insn;
+      emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
+      PUT_CODE (trap_rtx, code);
+      insn = gen_conditional_trap (trap_rtx, tcode);
+      if (insn)
+       return insn;
+    }
+#endif
+
+  return 0;
+}