]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/optabs.c
rtl.c: Define CONST_DOUBLE_FORMAT to the appropriate format for a CONST_DOUBLE...
[gcc.git] / gcc / optabs.c
index 7b263bcab1e7c54deb72e56475ba06e1e662e64d..82bfc6a4e12c745f4466031ce9fe228c52be49df 100644 (file)
@@ -1,5 +1,5 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,20 +15,26 @@ 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 "toplev.h"
+
+/* Include insn-config.h before expr.h so that HAVE_conditional_move
+   is properly defined. */
+#include "insn-config.h"
 #include "rtl.h"
 #include "tree.h"
 #include "flags.h"
 #include "insn-flags.h"
 #include "insn-codes.h"
+#include "function.h"
 #include "expr.h"
-#include "insn-config.h"
 #include "recog.h"
 #include "reload.h"
-#include <ctype.h>
 
 /* Each optab contains info on how this target machine
    can perform a particular operation
@@ -42,6 +48,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;
@@ -85,7 +93,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];
@@ -115,6 +123,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;
@@ -191,6 +215,15 @@ rtx fixunstfsi_libfunc;
 rtx fixunstfdi_libfunc;
 rtx fixunstfti_libfunc;
 
+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.  */
 
@@ -202,19 +235,47 @@ 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,
                                       enum machine_mode, int, int));
+static int expand_cmplxdiv_straight PROTO((rtx, rtx, rtx, rtx,
+                                          rtx, rtx, enum machine_mode,
+                                          int, enum optab_methods,
+                                          enum mode_class, optab));
+static int expand_cmplxdiv_wide PROTO((rtx, rtx, rtx, rtx,
+                                      rtx, rtx, enum machine_mode,
+                                      int, enum optab_methods,
+                                      enum mode_class, optab));
 static enum insn_code can_fix_p        PROTO((enum machine_mode, enum machine_mode,
                                       int, int *));
 static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,
                                         int));
 static rtx ftruncify   PROTO((rtx));
 static optab init_optab        PROTO((enum rtx_code));
-static void init_libfuncs PROTO((optab, int, int, char *, int));
-static void init_integral_libfuncs PROTO((optab, char *, int));
-static void init_floating_libfuncs PROTO((optab, char *, int));
-static void init_complex_libfuncs PROTO((optab, char *, int));
+static void init_libfuncs PROTO((optab, int, int, const char *, int));
+static void init_integral_libfuncs PROTO((optab, const char *, int));
+static void init_floating_libfuncs PROTO((optab, const char *, int));
+#ifdef HAVE_conditional_trap
+static void init_traps PROTO((void));
+#endif
+static int cmp_available_p PROTO((enum machine_mode, enum rtx_code, int));
+static void emit_cmp_and_jump_insn_1 PROTO((rtx, rtx, enum machine_mode,
+                                           enum rtx_code, int, rtx));
+static void prepare_cmp_insn PROTO((rtx *, rtx *, enum rtx_code *, rtx,
+                                   enum machine_mode *, int *, int));
+static rtx prepare_operand PROTO((int, rtx, int, enum machine_mode,
+                                 enum machine_mode, int));
+static void prepare_float_lib_cmp PROTO((rtx *, rtx *, enum rtx_code *,
+                                        enum machine_mode *, int *));
 \f
 /* Add a REG_EQUAL note to the last insn in SEQ.  TARGET is being set to
    the result of operation CODE applied to OP0 (and OP1 if it is a binary
@@ -259,13 +320,11 @@ 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)));
+  set_unique_reg_note (XVECEXP (seq, 0, XVECLEN (seq, 0) - 1), REG_EQUAL, note);
 
   return 1;
 }
@@ -296,17 +355,390 @@ 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;
 }
 \f
+/* Generate code to perform a straightforward complex divide.  */
+
+static int
+expand_cmplxdiv_straight (real0, real1, imag0, imag1, realr, imagr, submode,
+                         unsignedp, methods, class, binoptab)
+  rtx real0, real1, imag0, imag1, realr, imagr;
+  enum machine_mode submode;
+  int unsignedp;
+  enum optab_methods methods;
+  enum mode_class class;
+  optab binoptab;
+{
+  rtx divisor;
+  rtx real_t, imag_t;
+  rtx temp1, temp2;
+  rtx res;
+             
+  /* Don't fetch these from memory more than once.  */
+  real0 = force_reg (submode, real0);
+  real1 = force_reg (submode, real1);
+
+  if (imag0 != 0)
+    imag0 = force_reg (submode, imag0);
+
+  imag1 = force_reg (submode, imag1);
+
+  /* Divisor: c*c + d*d.  */
+  temp1 = expand_binop (submode, smul_optab, real1, real1,
+                       NULL_RTX, unsignedp, methods);
+
+  temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+                       NULL_RTX, unsignedp, methods);
+
+  if (temp1 == 0 || temp2 == 0)
+    return 0;
+
+  divisor = expand_binop (submode, add_optab, temp1, temp2,
+                         NULL_RTX, unsignedp, methods);
+  if (divisor == 0)
+    return 0;
+
+  if (imag0 == 0)
+    {
+      /* Mathematically, ((a)(c-id))/divisor.  */
+      /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
+
+      /* Calculate the dividend.  */
+      real_t = expand_binop (submode, smul_optab, real0, real1,
+                            NULL_RTX, unsignedp, methods);
+                 
+      imag_t = expand_binop (submode, smul_optab, real0, imag1,
+                            NULL_RTX, unsignedp, methods);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+
+      imag_t = expand_unop (submode, neg_optab, imag_t,
+                           NULL_RTX, unsignedp);
+    }
+  else
+    {
+      /* Mathematically, ((a+ib)(c-id))/divider.  */
+      /* Calculate the dividend.  */
+      temp1 = expand_binop (submode, smul_optab, real0, real1,
+                           NULL_RTX, unsignedp, methods);
+
+      temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+                           NULL_RTX, unsignedp, methods);
+
+      if (temp1 == 0 || temp2 == 0)
+       return 0;
+
+      real_t = expand_binop (submode, add_optab, temp1, temp2,
+                            NULL_RTX, 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)
+       return 0;
+
+      imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+                            NULL_RTX, unsignedp, methods);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+    }
+
+  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)
+    return 0;
+
+  if (res != realr)
+    emit_move_insn (realr, res);
+
+  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)
+    return 0;
+
+  if (res != imagr)
+    emit_move_insn (imagr, res);
+
+  return 1;
+}
+\f
+/* Generate code to perform a wide-input-range-acceptable complex divide.  */
+
+static int
+expand_cmplxdiv_wide (real0, real1, imag0, imag1, realr, imagr, submode,
+                     unsignedp, methods, class, binoptab)
+  rtx real0, real1, imag0, imag1, realr, imagr;
+  enum machine_mode submode;
+  int unsignedp;
+  enum optab_methods methods;
+  enum mode_class class;
+  optab binoptab;
+{
+  rtx ratio, divisor;
+  rtx real_t, imag_t;
+  rtx temp1, temp2, lab1, lab2;
+  enum machine_mode mode;
+  int align;
+  rtx res;
+             
+  /* Don't fetch these from memory more than once.  */
+  real0 = force_reg (submode, real0);
+  real1 = force_reg (submode, real1);
+
+  if (imag0 != 0)
+    imag0 = force_reg (submode, imag0);
+
+  imag1 = force_reg (submode, imag1);
+
+  /* XXX What's an "unsigned" complex number?  */
+  if (unsignedp)
+    {
+      temp1 = real1;
+      temp2 = imag1;
+    }
+  else
+    {
+      temp1 = expand_abs (submode, real1, NULL_RTX, 1);
+      temp2 = expand_abs (submode, imag1, NULL_RTX, 1);
+    }
+
+  if (temp1 == 0 || temp2 == 0)
+    return 0;
+
+  mode = GET_MODE (temp1);
+  align = GET_MODE_ALIGNMENT (mode);
+  lab1 = gen_label_rtx ();
+  emit_cmp_and_jump_insns (temp1, temp2, LT, NULL_RTX,
+                          mode, unsignedp, align, lab1);
+
+  /* |c| >= |d|; use ratio d/c to scale dividend and divisor.  */
+
+  if (class == MODE_COMPLEX_FLOAT)
+    ratio = expand_binop (submode, binoptab, imag1, real1,
+                         NULL_RTX, unsignedp, methods);
+  else
+    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                          imag1, real1, NULL_RTX, unsignedp);
+
+  if (ratio == 0)
+    return 0;
+
+  /* Calculate divisor.  */
+
+  temp1 = expand_binop (submode, smul_optab, imag1, ratio,
+                       NULL_RTX, unsignedp, methods);
+
+  if (temp1 == 0)
+    return 0;
+
+  divisor = expand_binop (submode, add_optab, temp1, real1,
+                         NULL_RTX, unsignedp, methods);
+
+  if (divisor == 0)
+    return 0;
+
+  /* Calculate dividend.  */
+
+  if (imag0 == 0)
+    {
+      real_t = real0;
+
+      /* Compute a / (c+id) as a / (c+d(d/c)) + i (-a(d/c)) / (c+d(d/c)).  */
+
+      imag_t = expand_binop (submode, smul_optab, real0, ratio,
+                            NULL_RTX, unsignedp, methods);
+
+      if (imag_t == 0)
+       return 0;
+
+      imag_t = expand_unop (submode, neg_optab, imag_t,
+                           NULL_RTX, unsignedp);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+    }
+  else
+    {
+      /* Compute (a+ib)/(c+id) as
+        (a+b(d/c))/(c+d(d/c) + i(b-a(d/c))/(c+d(d/c)).  */
+
+      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+                           NULL_RTX, unsignedp, methods);
+
+      if (temp1 == 0)
+       return 0;
+
+      real_t = expand_binop (submode, add_optab, temp1, real0,
+                            NULL_RTX, unsignedp, methods);
+
+      temp1 = expand_binop (submode, smul_optab, real0, ratio,
+                           NULL_RTX, unsignedp, methods);
+
+      if (temp1 == 0)
+       return 0;
+
+      imag_t = expand_binop (submode, sub_optab, imag0, temp1,
+                            NULL_RTX, unsignedp, methods);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+    }
+
+  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)
+    return 0;
+
+  if (res != realr)
+    emit_move_insn (realr, res);
+
+  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)
+    return 0;
+
+  if (res != imagr)
+    emit_move_insn (imagr, res);
+
+  lab2 = gen_label_rtx ();
+  emit_jump_insn (gen_jump (lab2));
+  emit_barrier ();
+
+  emit_label (lab1);
+
+  /* |d| > |c|; use ratio c/d to scale dividend and divisor.  */
+
+  if (class == MODE_COMPLEX_FLOAT)
+    ratio = expand_binop (submode, binoptab, real1, imag1,
+                         NULL_RTX, unsignedp, methods);
+  else
+    ratio = expand_divmod (0, TRUNC_DIV_EXPR, submode,
+                          real1, imag1, NULL_RTX, unsignedp);
+
+  if (ratio == 0)
+    return 0;
+
+  /* Calculate divisor.  */
+
+  temp1 = expand_binop (submode, smul_optab, real1, ratio,
+                       NULL_RTX, unsignedp, methods);
+
+  if (temp1 == 0)
+    return 0;
+
+  divisor = expand_binop (submode, add_optab, temp1, imag1,
+                         NULL_RTX, unsignedp, methods);
+
+  if (divisor == 0)
+    return 0;
+
+  /* Calculate dividend.  */
+
+  if (imag0 == 0)
+    {
+      /* Compute a / (c+id) as a(c/d) / (c(c/d)+d) + i (-a) / (c(c/d)+d).  */
+
+      real_t = expand_binop (submode, smul_optab, real0, ratio,
+                            NULL_RTX, unsignedp, methods);
+
+      imag_t = expand_unop (submode, neg_optab, real0,
+                           NULL_RTX, unsignedp);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+    }
+  else
+    {
+      /* Compute (a+ib)/(c+id) as
+        (a(c/d)+b)/(c(c/d)+d) + i (b(c/d)-a)/(c(c/d)+d).  */
+
+      temp1 = expand_binop (submode, smul_optab, real0, ratio,
+                           NULL_RTX, unsignedp, methods);
+
+      if (temp1 == 0)
+       return 0;
+
+      real_t = expand_binop (submode, add_optab, temp1, imag0,
+                            NULL_RTX, unsignedp, methods);
+
+      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+                           NULL_RTX, unsignedp, methods);
+
+      if (temp1 == 0)
+       return 0;
+
+      imag_t = expand_binop (submode, sub_optab, temp1, real0,
+                            NULL_RTX, unsignedp, methods);
+
+      if (real_t == 0 || imag_t == 0)
+       return 0;
+    }
+
+  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)
+    return 0;
+
+  if (res != realr)
+    emit_move_insn (realr, res);
+
+  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)
+    return 0;
+
+  if (res != imagr)
+    emit_move_insn (imagr, res);
+
+  emit_label (lab2);
+
+  return 1;
+}
+\f
 /* Generate code to perform an operation specified by BINOPTAB
    on operands OP0 and OP1, with result having machine-mode MODE.
 
@@ -327,6 +759,9 @@ 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;
@@ -368,8 +803,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 ();
@@ -380,7 +815,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;
 
@@ -414,7 +851,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
@@ -431,20 +868,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))
@@ -481,12 +922,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
@@ -568,7 +1012,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);
        }
@@ -576,14 +1024,18 @@ 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.  */
@@ -596,7 +1048,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;
@@ -626,26 +1078,30 @@ 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,
@@ -663,32 +1119,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.  */
@@ -702,6 +1168,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
@@ -732,6 +1199,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
        {
@@ -758,43 +1226,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.  */
@@ -807,7 +1289,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       rtx carry_tmp = gen_reg_rtx (word_mode);
       optab otheroptab = binoptab == add_optab ? sub_optab : add_optab;
       int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
-      rtx carry_in, carry_out;
+      rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
       rtx xop0, xop1;
 
       /* We can handle either a 1 or -1 value for the carry.  If STORE_FLAG
@@ -829,7 +1311,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++)
@@ -843,7 +1325,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;
 
@@ -851,12 +1333,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
+                                                 ? LT : GT),
+                                                x, op0_piece,
+                                                word_mode, 1, normalizep);
            }
 
          if (i > 0)
@@ -865,24 +1346,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
+                                                    ? LT : GT,
+                                                    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;
                }
            }
@@ -892,14 +1376,16 @@ 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);
+
+             set_unique_reg_note (temp,
+                                  REG_EQUAL,
+                                  gen_rtx_fmt_ee (binoptab->code, mode,
+                                                  copy_rtx (xop0),
+                                                  copy_rtx (xop1)));
+           }
          return target;
        }
       else
@@ -973,12 +1459,13 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       rtx op1_high = operand_subword_force (op1, high, mode);
       rtx op1_low = operand_subword_force (op1, low, mode);
       rtx product = 0;
-      rtx op0_xhigh;
-      rtx op1_xhigh;
+      rtx op0_xhigh = NULL_RTX;
+      rtx op1_xhigh = NULL_RTX;
 
       /* 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.
@@ -1005,33 +1492,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);
            }
        }
 
@@ -1047,34 +1534,40 @@ 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);
+                 set_unique_reg_note (temp,
+                                      REG_EQUAL,
+                                      gen_rtx_fmt_ee (MULT, mode,
+                                                      copy_rtx (op0),
+                                                      copy_rtx (op1)));
+               }
              return product;
            }
        }
@@ -1096,15 +1589,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
@@ -1120,12 +1610,12 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       start_sequence ();
 
-      realr = gen_realpart  (submode, target);
+      realr = gen_realpart (submode, target);
       imagr = gen_imagpart (submode, target);
 
       if (GET_MODE (op0) == mode)
        {
-         real0 = gen_realpart  (submode, op0);
+         real0 = gen_realpart (submode, op0);
          imag0 = gen_imagpart (submode, op0);
        }
       else
@@ -1133,13 +1623,13 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       if (GET_MODE (op1) == mode)
        {
-         real1 = gen_realpart  (submode, op1);
+         real1 = gen_realpart (submode, op1);
          imag1 = gen_imagpart (submode, op1);
        }
       else
        real1 = op1;
 
-      if (! real0 || ! real1 || ! (imag0 || imag1))
+      if (real0 == 0 || real1 == 0 || ! (imag0 != 0|| imag1 != 0))
        abort ();
 
       switch (binoptab->code)
@@ -1150,7 +1640,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)
@@ -1163,8 +1656,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:
@@ -1172,32 +1669,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
            {
@@ -1207,25 +1721,33 @@ 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);
@@ -1238,7 +1760,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
                                     real0, real1, realr, unsignedp);
 
-             if (res != realr)
+             if (res == 0)
+               break;
+             else if (res != realr)
                emit_move_insn (realr, res);
 
              if (class == MODE_COMPLEX_FLOAT)
@@ -1248,88 +1772,34 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                res = expand_divmod (0, TRUNC_DIV_EXPR, submode,
                                     imag0, real1, imagr, unsignedp);
 
-             if (res != imagr)
+             if (res == 0)
+               break;
+             else if (res != imagr)
                emit_move_insn (imagr, res);
-           }
-         else                  /* Divisor is of complex type */
-           {                   /* X/(a+ib) */
-
-             rtx divisor;
-             rtx real_t;
-             rtx imag_t;
-             rtx lhs, rhs;
-             
-             /* Don't fetch these from memory more than once.  */
-             real0 = force_reg (submode, real0);
-             real1 = force_reg (submode, real1);
-             if (imag0)
-               imag0 = force_reg (submode, imag0);
-             imag1 = force_reg (submode, imag1);
 
-             /* Divisor: c*c + d*d */
-             divisor = expand_binop (submode, add_optab,
-                                     expand_binop (submode, smul_optab,
-                                                   real1, real1,
-                                                   0, unsignedp, methods),
-                                     expand_binop (submode, smul_optab,
-                                                   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)) */
-                 /* Calculate the dividend */
-                 real_t = expand_binop (submode, smul_optab, real0, real1,
-                                        0, unsignedp, methods);
-                 
-                 imag_t
-                   = expand_unop (submode, neg_optab,
-                                  expand_binop (submode, smul_optab, real0,
-                                                imag1, 0, unsignedp, methods),
-                                  0, unsignedp);
-               }
-             else              /* ((a+ib)(c-id))/divider */
+             ok = 1;
+           }
+         else
+           {
+             switch (flag_complex_divide_method)
                {
-                 /* Calculate the dividend */
-                 real_t = expand_binop (submode, add_optab,
-                                        expand_binop (submode, smul_optab,
-                                                      real0, real1,
-                                                      0, unsignedp, methods),
-                                        expand_binop (submode, smul_optab,
-                                                      imag0, imag1,
-                                                      0, unsignedp, methods),
-                                        0, unsignedp, methods);
-                 
-                 imag_t = expand_binop (submode, sub_optab,
-                                        expand_binop (submode, smul_optab,
-                                                      imag0, real1,
-                                                      0, unsignedp, methods),
-                                        expand_binop (submode, smul_optab,
-                                                      real0, imag1,
-                                                      0, unsignedp, methods),
-                                        0, unsignedp, methods);
-
+               case 0:
+                 ok = expand_cmplxdiv_straight (real0, real1, imag0, imag1,
+                                                realr, imagr, submode,
+                                                unsignedp, methods,
+                                                class, binoptab);
+                 break;
+
+               case 1:
+                 ok = expand_cmplxdiv_wide (real0, real1, imag0, imag1,
+                                            realr, imagr, submode,
+                                            unsignedp, methods,
+                                            class, binoptab);
+                 break;
+
+               default:
+                 abort ();
                }
-
-             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 != realr)
-               emit_move_insn (realr, res);
-
-             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 != imagr)
-               emit_move_insn (imagr, res);
            }
          break;
          
@@ -1340,15 +1810,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.
@@ -1358,7 +1832,6 @@ 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;
@@ -1373,6 +1846,10 @@ 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.  */
       value = emit_library_call_value (binoptab->handlers[(int) mode].libfunc,
@@ -1384,7 +1861,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
 
       target = gen_reg_rtx (mode);
       emit_libcall_block (insns, target, value,
-                         gen_rtx (binoptab->code, mode, op0, op1));
+                         gen_rtx_fmt_ee (binoptab->code, mode, op0, op1));
 
       return target;
     }
@@ -1528,7 +2005,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.  */
@@ -1798,7 +2275,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;
     }
 
@@ -1842,7 +2320,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;
     }
 
@@ -1850,7 +2329,6 @@ 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 ();
@@ -1864,7 +2342,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
       target = gen_reg_rtx (mode);
       emit_libcall_block (insns, target, value,
-                         gen_rtx (unoptab->code, mode, op0));
+                         gen_rtx_fmt_e (unoptab->code, mode, op0));
 
       return target;
     }
@@ -1912,6 +2390,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
@@ -1922,6 +2411,85 @@ 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.
 
+ */
+
+rtx
+expand_abs (mode, op0, target, safe)
+     enum machine_mode mode;
+     rtx op0;
+     rtx target;
+     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
+    do_compare_rtx_and_jump (target, CONST0_RTX (mode), GE, 0, mode,
+                            NULL_RTX, 0, NULL_RTX, op1);
+
+  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
@@ -2043,7 +2611,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
       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.  */
@@ -2058,7 +2626,6 @@ 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 ();
@@ -2072,7 +2639,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
       target = gen_reg_rtx (submode);
       emit_libcall_block (insns, target, value,
-                         gen_rtx (abs_optab->code, mode, op0));
+                         gen_rtx_fmt_e (abs_optab->code, mode, op0));
 
       return target;
     }
@@ -2134,7 +2701,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.  */
@@ -2171,9 +2741,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.
@@ -2182,7 +2750,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.  */
 
@@ -2197,6 +2766,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.  */
@@ -2207,9 +2781,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)
@@ -2244,7 +2815,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)
     {
@@ -2252,12 +2823,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
@@ -2265,8 +2836,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));
+       set_unique_reg_note (last, REG_EQUAL, equiv);
     }
   else
     last = get_last_insn ();
@@ -2277,9 +2847,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;
 }
@@ -2318,6 +2888,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 (-1),
+                                                  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,
@@ -2362,8 +2947,9 @@ 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)
+    set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
 
   if (prev == 0)
     first = get_insns ();
@@ -2371,9 +2957,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.  */
@@ -2395,31 +2981,58 @@ emit_0_to_1_insn (x)
   emit_move_insn (x, const1_rtx);
 }
 
-/* Generate code to compare X with Y
-   so that the condition codes are set.
+/* Nonzero if we can perform a comparison of mode MODE for a conditional jump
+   straightforwardly.  */
 
-   MODE is the mode of the inputs (in case they are const_int).
-   UNSIGNEDP nonzero says that X and Y are unsigned;
+static int
+cmp_available_p (mode, code, can_use_tst_p)
+     enum machine_mode mode;
+     enum rtx_code code;
+     int can_use_tst_p;
+{
+  do
+    {
+      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing
+         || (can_use_tst_p
+             && tst_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing))
+       return 1;
+      mode = GET_MODE_WIDER_MODE (mode);
+    } while (mode != VOIDmode);
+
+  return 0;
+}
+
+/* This function is called when we are going to emit a compare instruction that
+   compares the values found in *PX and *PY, using the rtl operator COMPARISON.
+
+   *PMODE is the mode of the inputs (in case they are const_int).
+   *PUNSIGNEDP nonzero says that the operands 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.
+   If they have mode BLKmode, then SIZE specifies the size of both operands,
+   and ALIGN specifies the known shared alignment of the operands.
 
-   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.  */
+   This function performs all the setup necessary so that the caller only has
+   to emit a single comparison insn.  This setup can involve doing a BLKmode
+   comparison or emitting a library call to perform the comparison if no insn
+   is available to handle it.
+   The values which are passed in through pointers can be modified; the caller
+   should perform the comparison on the modified values.  */
 
-void
-emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
-     rtx x, y;
-     enum rtx_code comparison;
+static void
+prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align)
+     rtx *px, *py;
+     enum rtx_code *pcomparison;
      rtx size;
-     enum machine_mode mode;
-     int unsignedp;
+     enum machine_mode *pmode;
+     int *punsignedp;
      int align;
 {
+  enum rtx_code comparison = *pcomparison;
+  enum machine_mode mode = *pmode;
+  rtx x = *px, y = *py;
+  int unsignedp = *punsignedp;
   enum mode_class class;
-  enum machine_mode wider_mode;
 
   class = GET_MODE_CLASS (mode);
 
@@ -2442,6 +3055,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);
@@ -2450,6 +3071,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
 
   if (mode == BLKmode)
     {
+      rtx result;
+      enum machine_mode result_mode;
+
       emit_queue ();
       x = protect_from_queue (x, 0);
       y = protect_from_queue (y, 0);
@@ -2461,12 +3085,9 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
          && GET_CODE (size) == CONST_INT
          && INTVAL (size) < (1 << GET_MODE_BITSIZE (QImode)))
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrqi][0];
+         result = gen_reg_rtx (result_mode);
          emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
@@ -2475,27 +3096,21 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
          && GET_CODE (size) == CONST_INT
          && INTVAL (size) < (1 << GET_MODE_BITSIZE (HImode)))
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrhi][0];
+         result = gen_reg_rtx (result_mode);
          emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
 #ifdef HAVE_cmpstrsi
       if (HAVE_cmpstrsi)
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
+         result = gen_reg_rtx (result_mode);
          size = protect_from_queue (size, 0);
          emit_insn (gen_cmpstrsi (result, x, y,
                                   convert_to_mode (SImode, size, 1),
                                   GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
        }
       else
 #endif
@@ -2504,114 +3119,229 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
          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)),
-                        const0_rtx, comparison, NULL_RTX,
-                        TYPE_MODE (integer_type_node), 0, 0);
+
+         /* Immediately move the result of the libcall into a pseudo
+            register so reload doesn't clobber the value if it needs
+            the return register for a spill reg.  */
+         result = gen_reg_rtx (TYPE_MODE (integer_type_node));
+         result_mode = TYPE_MODE (integer_type_node);
+         emit_move_insn (result,
+                         hard_libcall_value (result_mode));
        }
+      *px = result;
+      *py = const0_rtx;
+      *pmode = result_mode;
       return;
     }
 
-  /* Handle some compares against zero.  */
+  *px = x;
+  *py = y;
+  if (cmp_available_p (mode, comparison, y == CONST0_RTX (mode)))
+    return;
 
-  if (y == CONST0_RTX (mode)
-      && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  /* Handle a lib call just for the mode we are using.  */
+
+  if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
     {
-      int icode = (int) tst_optab->handlers[(int) mode].insn_code;
+      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
+      rtx result;
 
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
+      /* If we want unsigned, and this mode has a distinct unsigned
+        comparison routine, use that.  */
+      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
+       libfunc = ucmp_optab->handlers[(int) mode].libfunc;
 
-      /* Now, if insn does accept these operands, put them into pseudos.  */
-      if (! (*insn_operand_predicate[icode][0])
-         (x, insn_operand_mode[icode][0]))
-       x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
+      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));
 
-      emit_insn (GEN_FCN (icode) (x));
+      /* 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".  */
+      *px = result;
+      *py = const1_rtx;
+      *pmode = word_mode;
       return;
     }
 
-  /* Handle compares for which there is a directly suitable insn.  */
+  if (class == MODE_FLOAT)
+    prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
+
+  else
+    abort ();
+}
+
+/* Before emitting an insn with code ICODE, make sure that X, which is going
+   to be used for operand OPNUM of the insn, is converted from mode MODE to
+   WIDER_MODE (UNSIGNEDP determines whether it is a unsigned conversion), and
+   that it is accepted by the operand predicate.  Return the new value.  */
+static rtx
+prepare_operand (icode, x, opnum, mode, wider_mode, unsignedp)
+     int icode;
+     rtx x;
+     int opnum;
+     enum machine_mode mode, wider_mode;
+     int unsignedp;
+{
+  x = protect_from_queue (x, 0);
+
+  if (mode != wider_mode)
+    x = convert_modes (wider_mode, mode, x, unsignedp);
 
-  if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  if (! (*insn_operand_predicate[icode][opnum])
+      (x, insn_operand_mode[icode][opnum]))
+    x = copy_to_mode_reg (insn_operand_mode[icode][opnum], x);
+  return x;
+}
+
+/* Subroutine of emit_cmp_and_jump_insns; this function is called when we know
+   we can do the comparison.
+   The arguments are the same as for emit_cmp_and_jump_insns; but LABEL may
+   be NULL_RTX which indicates that only a comparison is to be generated.  */
+
+static void
+emit_cmp_and_jump_insn_1 (x, y, mode, comparison, unsignedp, label)
+     rtx x, y;
+     enum machine_mode mode;
+     enum rtx_code comparison;
+     int unsignedp;
+     rtx label;
+{
+  rtx test = gen_rtx_fmt_ee (comparison, mode, x, y);
+  enum mode_class class = GET_MODE_CLASS (mode);
+  enum machine_mode wider_mode = mode;
+
+  /* Try combined insns first.  */
+  do
     {
-      int icode = (int) cmp_optab->handlers[(int) mode].insn_code;
+      enum insn_code icode;
+      PUT_MODE (test, wider_mode);
 
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
+      /* Handle some compares against zero.  */
+      icode = (int) tst_optab->handlers[(int) wider_mode].insn_code;
+      if (y == CONST0_RTX (mode) && icode != CODE_FOR_nothing)
+       {
+         x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
+         emit_insn (GEN_FCN (icode) (x));
+         if (label)
+           emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+         return;
+       }
 
-      /* Now, if insn doesn't accept these operands, put them into pseudos.  */
-      if (! (*insn_operand_predicate[icode][0])
-         (x, insn_operand_mode[icode][0]))
-       x = copy_to_mode_reg (insn_operand_mode[icode][0], x);
+      /* Handle compares for which there is a directly suitable insn.  */
+
+      icode = (int) cmp_optab->handlers[(int) wider_mode].insn_code;
+      if (icode != CODE_FOR_nothing)
+       {
+         x = prepare_operand (icode, x, 0, mode, wider_mode, unsignedp);
+         y = prepare_operand (icode, y, 1, mode, wider_mode, unsignedp);
+         emit_insn (GEN_FCN (icode) (x, y));
+         if (label)
+           emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+         return;
+       }
 
-      if (! (*insn_operand_predicate[icode][1])
-         (y, insn_operand_mode[icode][1]))
-       y = copy_to_mode_reg (insn_operand_mode[icode][1], y);
+      if (class != MODE_INT && class != MODE_FLOAT
+         && class != MODE_COMPLEX_FLOAT)
+       break;
 
-      emit_insn (GEN_FCN (icode) (x, y));
-      return;
-    }
+      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
+    } while (wider_mode != VOIDmode);
 
-  /* Try widening if we can find a direct insn that way.  */
+  abort ();
+}
 
-  if (class == MODE_INT || class == MODE_FLOAT || class == MODE_COMPLEX_FLOAT)
-    {
-      for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
-          wider_mode = GET_MODE_WIDER_MODE (wider_mode))
-       {
-         if (cmp_optab->handlers[(int) wider_mode].insn_code
-             != CODE_FOR_nothing)
-           {
-             x = protect_from_queue (x, 0);
-             y = protect_from_queue (y, 0);
-             x = convert_modes (wider_mode, mode, x, unsignedp);
-             y = convert_modes (wider_mode, mode, y, unsignedp);
-             emit_cmp_insn (x, y, comparison, NULL_RTX,
-                            wider_mode, unsignedp, align);
-             return;
-           }
-       }
-    }
+/* 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.
 
-  /* Handle a lib call just for the mode we are using.  */
+   UNSIGNEDP nonzero says that X and Y are unsigned; this matters if they
+   need to be widened by emit_cmp_insn.  UNSIGNEDP is also used to select
+   the proper branch condition code.
 
-  if (cmp_optab->handlers[(int) mode].libfunc
-      && class != MODE_FLOAT)
-    {
-      rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
-      /* If we want unsigned, and this mode has a distinct unsigned
-        comparison routine, use that.  */
-      if (unsignedp && ucmp_optab->handlers[(int) mode].libfunc)
-       libfunc = ucmp_optab->handlers[(int) mode].libfunc;
+   If X and Y have mode BLKmode, then SIZE specifies the size of both X and Y,
+   and ALIGN specifies the known shared alignment of X and Y. 
 
-      emit_library_call (libfunc, 1,
-                        word_mode, 2, x, mode, y, mode);
+   MODE is the mode of the inputs (in case they are const_int).
 
-      /* 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".  */
+   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).  It will
+   be passed unchanged to emit_cmp_insn, then potentially converted into an
+   unsigned variant based on UNSIGNEDP to select a proper jump instruction.  */
 
-      emit_cmp_insn (hard_libcall_value (word_mode), const1_rtx,
-                    comparison, NULL_RTX, word_mode, unsignedp, 0);
-      return;
+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) && ! CONSTANT_P (y))
+      || (GET_CODE (x) == CONST_INT && GET_CODE (y) != CONST_INT))
+    {
+      /* Swap operands and condition to ensure canonical RTL.  */
+      op0 = y;
+      op1 = x;
+      comparison = swap_condition (comparison);
+    }
+  else
+    {
+      op0 = x;
+      op1 = y;
     }
 
-  if (class == MODE_FLOAT)
-    emit_float_lib_cmp (x, y, comparison);
+#ifdef HAVE_cc0
+  /* If OP0 is still a constant, then both X and Y must be constants.  Force
+     X into a register to avoid aborting in emit_cmp_insn due to non-canonical
+     RTL.  */
+  if (CONSTANT_P (op0))
+    op0 = force_reg (mode, op0);
+#endif
 
-  else
-    abort ();
+  emit_queue ();
+  if (unsignedp)
+    comparison = unsigned_condition (comparison);
+  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align);
+  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
+}
+
+/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
+void
+emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
+     rtx x, y;
+     enum rtx_code comparison;
+     rtx size;
+     enum machine_mode mode;
+     int unsignedp;
+     int align;
+{
+  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0);
 }
 
+
 /* Nonzero if a compare of mode MODE can be done straightforwardly
    (without splitting it into pieces).  */
 
@@ -2632,15 +3362,50 @@ 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.).  */
 
-void
-emit_float_lib_cmp (x, y, comparison)
-     rtx x, y;
-     enum rtx_code comparison;
+static void
+prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp)
+     rtx *px, *py;
+     enum rtx_code *pcomparison;
+     enum machine_mode *pmode;
+     int *punsignedp;
 {
+  enum rtx_code comparison = *pcomparison;
+  rtx x = *px, y = *py;
   enum machine_mode mode = GET_MODE (x);
   rtx libfunc = 0;
+  rtx result;
+
+  if (mode == HFmode)
+    switch (comparison)
+      {
+      case EQ:
+       libfunc = eqhf2_libfunc;
+       break;
+
+      case NE:
+       libfunc = nehf2_libfunc;
+       break;
+
+      case GT:
+       libfunc = gthf2_libfunc;
+       break;
+
+      case GE:
+       libfunc = gehf2_libfunc;
+       break;
+
+      case LT:
+       libfunc = lthf2_libfunc;
+       break;
 
-  if (mode == SFmode)
+      case LE:
+       libfunc = lehf2_libfunc;
+       break;
+
+      default:
+       break;
+      }
+  else if (mode == SFmode)
     switch (comparison)
       {
       case EQ:
@@ -2666,6 +3431,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = lesf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == DFmode)
     switch (comparison)
@@ -2693,6 +3461,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = ledf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == XFmode)
     switch (comparison)
@@ -2720,6 +3491,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = lexf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else if (mode == TFmode)
     switch (comparison)
@@ -2747,6 +3521,9 @@ emit_float_lib_cmp (x, y, comparison)
       case LE:
        libfunc = letf2_libfunc;
        break;
+
+      default:
+       break;
       }
   else
     {
@@ -2761,9 +3538,9 @@ emit_float_lib_cmp (x, y, comparison)
            {
              x = protect_from_queue (x, 0);
              y = protect_from_queue (y, 0);
-             x = convert_to_mode (wider_mode, x, 0);
-             y = convert_to_mode (wider_mode, y, 0);
-             emit_float_lib_cmp (x, y, comparison);
+             *px = convert_to_mode (wider_mode, x, 0);
+             *py = convert_to_mode (wider_mode, y, 0);
+             prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
              return;
            }
        }
@@ -2776,8 +3553,19 @@ emit_float_lib_cmp (x, y, comparison)
   emit_library_call (libfunc, 1,
                     word_mode, 2, x, mode, y, mode);
 
-  emit_cmp_insn (hard_libcall_value (word_mode), const0_rtx, comparison,
-                NULL_RTX, word_mode, 0, 0);
+  /* Immediately move the result of the libcall into a pseudo
+     register so reload doesn't clobber the value if it needs
+     the return register for a spill reg.  */
+  result = gen_reg_rtx (word_mode);
+  emit_move_insn (result, hard_libcall_value (word_mode));
+  *px = result;
+  *py = const0_rtx;
+  *pmode = word_mode;
+#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
+  if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
+    *pcomparison = NE;
+#endif
+  *punsignedp = 0;
 }
 \f
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
@@ -2794,6 +3582,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.
 
@@ -2896,20 +3825,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);
            }
        }
@@ -3065,23 +3992,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.  */
@@ -3091,8 +4070,9 @@ expand_float (to, from, unsignedp)
         correct its value by 2**bitwidth.  */
 
       do_pending_stack_adjust ();
-      emit_cmp_insn (from, const0_rtx, GE, NULL_RTX, GET_MODE (from), 0, 0);
-      emit_jump_insn (gen_bge (label));
+      emit_cmp_and_jump_insns (from, const0_rtx, GE, NULL_RTX, GET_MODE (from),
+                               0, 0, label);
+
       /* On SCO 3.2.1, ldexp rejects values outside [0.5, 1).
         Rather than setting up a dconst_dot_5, let's hope SCO
         fixes the bug.  */
@@ -3102,13 +4082,14 @@ expand_float (to, from, unsignedp)
                           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;
@@ -3180,9 +4161,11 @@ expand_float (to, from, unsignedp)
       end_sequence ();
 
       emit_libcall_block (insns, target, value,
-                         gen_rtx (FLOAT, GET_MODE (to), from));
+                         gen_rtx_FLOAT (GET_MODE (to), from));
     }
 
+ done:
+
   /* Copy result to requested destination
      if we have been computing in a temp location.  */
 
@@ -3295,8 +4278,8 @@ expand_fix (to, from, unsignedp)
 
          /* See if we need to do the subtraction.  */
          do_pending_stack_adjust ();
-         emit_cmp_insn (from, limit, GE, NULL_RTX, GET_MODE (from), 0, 0);
-         emit_jump_insn (gen_bge (lab1));
+         emit_cmp_and_jump_insns (from, limit, GE, NULL_RTX, GET_MODE (from),
+                                  0, 0, lab1);
 
          /* If not, do the signed "fix" and branch around fixup code.  */
          expand_fix (to, from, 0);
@@ -3319,13 +4302,17 @@ 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);
+             set_unique_reg_note (insn,
+                                  REG_EQUAL,
+                                  gen_rtx_fmt_e (UNSIGNED_FIX,
+                                                 GET_MODE (to),
+                                                 copy_rtx (from)));
+           }
          return;
        }
 #endif
@@ -3390,6 +4377,7 @@ expand_fix (to, from, unsignedp)
   if (libfcn)
     {
       rtx insns;
+      rtx value;
 
       to = protect_from_queue (to, 1);
       from = protect_from_queue (from, 0);
@@ -3399,19 +4387,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
@@ -3455,8 +4448,8 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
     register optab optable;
     register int first_mode;
     register int last_mode;
-    register char *opname;
-    register char suffix;
+    register const char *opname;
+    register int suffix;
 {
   register int mode;
   register unsigned opname_len = strlen (opname);
@@ -3464,12 +4457,12 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
   for (mode = first_mode; (int) mode <= (int) last_mode;
        mode = (enum machine_mode) ((int) mode + 1))
     {
-      register char *mname = mode_name[(int) mode];
+      register const char *mname = GET_MODE_NAME(mode);
       register unsigned mname_len = strlen (mname);
       register char *libfunc_name
        = (char *) xmalloc (2 + opname_len + mname_len + 1 + 1);
       register char *p;
-      register char *q;
+      register const char *q;
 
       p = libfunc_name;
       *p++ = '_';
@@ -3477,11 +4470,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);
     }
 }
 
@@ -3493,8 +4486,8 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
 static void
 init_integral_libfuncs (optable, opname, suffix)
     register optab optable;
-    register char *opname;
-    register char suffix;
+    register const char *opname;
+    register int suffix;
 {
   init_libfuncs (optable, SImode, TImode, opname, suffix);
 }
@@ -3507,25 +4500,12 @@ init_integral_libfuncs (optable, opname, suffix)
 static void
 init_floating_libfuncs (optable, opname, suffix)
     register optab optable;
-    register char *opname;
-    register char suffix;
+    register const char *opname;
+    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.  */
@@ -3533,7 +4513,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.  */
@@ -3561,9 +4545,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);
@@ -3603,6 +4594,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;
@@ -3620,10 +4612,6 @@ init_optabs ()
       fixtrunctab[i][j][1] = fixtrunctab[i][j][0];
 #endif
 
-#ifdef EXTRA_CC_MODES
-  init_mov_optab ();
-#endif
-
   /* Initialize the optabs with the names of the library functions.  */
   init_integral_libfuncs (add_optab, "add", '3');
   init_floating_libfuncs (add_optab, "add", '3');
@@ -3645,8 +4633,6 @@ init_optabs ()
   init_integral_libfuncs (ashl_optab, "ashl", '3');
   init_integral_libfuncs (ashr_optab, "ashr", '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');
@@ -3665,247 +4651,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);
-#endif
-#ifdef UDIVTI3_LIBCALL
-  udiv_optab->handlers[(int) TImode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, UDIVTI3_LIBCALL);
+    = gen_rtx_SYMBOL_REF (Pmode, UDIVDI3_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);
-#endif
-
-/* Define library calls for quad FP instructions */
-#ifdef ADDTF3_LIBCALL
-  add_optab->handlers[(int) TFmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, ADDTF3_LIBCALL);
-#endif
-#ifdef SUBTF3_LIBCALL
-  sub_optab->handlers[(int) TFmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, SUBTF3_LIBCALL);
-#endif
-#ifdef MULTF3_LIBCALL
-  smul_optab->handlers[(int) TFmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, MULTF3_LIBCALL);
-#endif
-#ifdef DIVTF3_LIBCALL
-  flodiv_optab->handlers[(int) TFmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, DIVTF3_LIBCALL);
-#endif
-#ifdef SQRTTF2_LIBCALL
-  sqrt_optab->handlers[(int) TFmode].libfunc
-    = gen_rtx (SYMBOL_REF, Pmode, SQRTTF2_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");
+    = 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");
-
-  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");
-
-/* Define library calls for quad FP instructions */
-#ifdef EQTF2_LIBCALL
-  eqtf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EQTF2_LIBCALL);
-#endif
-#ifdef NETF2_LIBCALL
-  netf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, NETF2_LIBCALL);
-#endif
-#ifdef GTTF2_LIBCALL
-  gttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, GTTF2_LIBCALL);
-#endif
-#ifdef GETF2_LIBCALL
-  getf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, GETF2_LIBCALL);
-#endif
-#ifdef LTTF2_LIBCALL
-  lttf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, LTTF2_LIBCALL);
-#endif
-#ifdef LETF2_LIBCALL
-  letf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, LETF2_LIBCALL);
+    = 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
 
-  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");
-
-/* Define library calls for quad FP instructions */
-#ifdef TRUNCTFSF2_LIBCALL
-  trunctfsf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, TRUNCTFSF2_LIBCALL);
-#endif
-#ifdef TRUNCTFDF2_LIBCALL
-  trunctfdf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, TRUNCTFDF2_LIBCALL);
-#endif
-#ifdef EXTENDSFTF2_LIBCALL
-  extendsftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EXTENDSFTF2_LIBCALL);
+  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 EXTENDDFTF2_LIBCALL
-  extenddftf2_libfunc = gen_rtx (SYMBOL_REF, Pmode, EXTENDDFTF2_LIBCALL);
-#endif
-#ifdef FLOATSITF2_LIBCALL
-  floatsitf_libfunc = gen_rtx (SYMBOL_REF, Pmode, FLOATSITF2_LIBCALL);
-#endif
-#ifdef FIX_TRUNCTFSI2_LIBCALL
-  fixtfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, FIX_TRUNCTFSI2_LIBCALL);
-#endif
-#ifdef FIXUNS_TRUNCTFSI2_LIBCALL
-  fixunstfsi_libfunc = gen_rtx (SYMBOL_REF, Pmode, FIXUNS_TRUNCTFSI2_LIBCALL);
+
+#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)
@@ -3919,3 +4861,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;
+}
This page took 0.115315 seconds and 5 git commands to generate.