OSDN Git Service

* g++.old-deja/g++.other/eh3.C: New testcase.
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 9b4d4f1..5ee436d 100644 (file)
@@ -1,5 +1,6 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
-   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -28,12 +29,17 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-config.h"
 #include "rtl.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "flags.h"
 #include "insn-flags.h"
 #include "insn-codes.h"
+#include "function.h"
 #include "expr.h"
 #include "recog.h"
 #include "reload.h"
+#include "ggc.h"
+#include "real.h"
+#include "defaults.h"
 
 /* Each optab contains info on how this target machine
    can perform a particular operation
@@ -44,50 +50,9 @@ Boston, MA 02111-1307, USA.  */
 
    See expr.h for documentation of these optabs.  */
 
-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;
-optab sdivmod_optab;
-optab udiv_optab;
-optab udivmod_optab;
-optab smod_optab;
-optab umod_optab;
-optab flodiv_optab;
-optab ftrunc_optab;
-optab and_optab;
-optab ior_optab;
-optab xor_optab;
-optab ashl_optab;
-optab lshr_optab;
-optab ashr_optab;
-optab rotl_optab;
-optab rotr_optab;
-optab smin_optab;
-optab smax_optab;
-optab umin_optab;
-optab umax_optab;
-
-optab mov_optab;
-optab movstrict_optab;
-
-optab neg_optab;
-optab abs_optab;
-optab one_cmpl_optab;
-optab ffs_optab;
-optab sqrt_optab;
-optab sin_optab;
-optab cos_optab;
-
-optab cmp_optab;
-optab ucmp_optab;  /* Used only for libcalls for unsigned comparisons.  */
-optab tst_optab;
-
-optab strlen_optab;
+optab optab_table[OTI_MAX];
+
+rtx libfunc_table[LTI_MAX];
 
 /* Tables of patterns for extending one integer mode to another.  */
 enum insn_code extendtab[MAX_MACHINE_MODE][MAX_MACHINE_MODE][2];
@@ -100,129 +65,6 @@ enum insn_code floattab[NUM_MACHINE_MODES][NUM_MACHINE_MODES][2];
 /* Contains the optab used for each rtx code.  */
 optab code_to_optab[NUM_RTX_CODE + 1];
 
-/* SYMBOL_REF rtx's for the library functions that are called
-   implicitly and not via optabs.  */
-
-rtx extendsfdf2_libfunc;
-rtx extendsfxf2_libfunc;
-rtx extendsftf2_libfunc;
-rtx extenddfxf2_libfunc;
-rtx extenddftf2_libfunc;
-
-rtx truncdfsf2_libfunc;
-rtx truncxfsf2_libfunc;
-rtx trunctfsf2_libfunc;
-rtx truncxfdf2_libfunc;
-rtx trunctfdf2_libfunc;
-
-rtx memcpy_libfunc;
-rtx bcopy_libfunc;
-rtx memcmp_libfunc;
-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;
-rtx gesf2_libfunc;
-rtx ltsf2_libfunc;
-rtx lesf2_libfunc;
-
-rtx eqdf2_libfunc;
-rtx nedf2_libfunc;
-rtx gtdf2_libfunc;
-rtx gedf2_libfunc;
-rtx ltdf2_libfunc;
-rtx ledf2_libfunc;
-
-rtx eqxf2_libfunc;
-rtx nexf2_libfunc;
-rtx gtxf2_libfunc;
-rtx gexf2_libfunc;
-rtx ltxf2_libfunc;
-rtx lexf2_libfunc;
-
-rtx eqtf2_libfunc;
-rtx netf2_libfunc;
-rtx gttf2_libfunc;
-rtx getf2_libfunc;
-rtx lttf2_libfunc;
-rtx letf2_libfunc;
-
-rtx floatsisf_libfunc;
-rtx floatdisf_libfunc;
-rtx floattisf_libfunc;
-
-rtx floatsidf_libfunc;
-rtx floatdidf_libfunc;
-rtx floattidf_libfunc;
-
-rtx floatsixf_libfunc;
-rtx floatdixf_libfunc;
-rtx floattixf_libfunc;
-
-rtx floatsitf_libfunc;
-rtx floatditf_libfunc;
-rtx floattitf_libfunc;
-
-rtx fixsfsi_libfunc;
-rtx fixsfdi_libfunc;
-rtx fixsfti_libfunc;
-
-rtx fixdfsi_libfunc;
-rtx fixdfdi_libfunc;
-rtx fixdfti_libfunc;
-
-rtx fixxfsi_libfunc;
-rtx fixxfdi_libfunc;
-rtx fixxfti_libfunc;
-
-rtx fixtfsi_libfunc;
-rtx fixtfdi_libfunc;
-rtx fixtfti_libfunc;
-
-rtx fixunssfsi_libfunc;
-rtx fixunssfdi_libfunc;
-rtx fixunssfti_libfunc;
-
-rtx fixunsdfsi_libfunc;
-rtx fixunsdfdi_libfunc;
-rtx fixunsdfti_libfunc;
-
-rtx fixunsxfsi_libfunc;
-rtx fixunsxfdi_libfunc;
-rtx fixunsxfti_libfunc;
-
-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.  */
 
@@ -243,29 +85,33 @@ enum insn_code setcc_gen_code[NUM_RTX_CODE];
 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,
+static int add_equal_note      PARAMS ((rtx, rtx, enum rtx_code, rtx, rtx));
+static rtx widen_operand       PARAMS ((rtx, enum machine_mode,
                                       enum machine_mode, int, int));
-static int expand_cmplxdiv_straight PROTO((rtx, rtx, rtx, rtx,
+static int expand_cmplxdiv_straight PARAMS ((rtx, rtx, rtx, rtx,
                                           rtx, rtx, enum machine_mode,
                                           int, enum optab_methods,
                                           enum mode_class, optab));
-static int expand_cmplxdiv_wide PROTO((rtx, rtx, rtx, rtx,
+static int expand_cmplxdiv_wide PARAMS ((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,
+static enum insn_code can_fix_p        PARAMS ((enum machine_mode, enum machine_mode,
                                       int, int *));
-static enum insn_code can_float_p PROTO((enum machine_mode, enum machine_mode,
+static enum insn_code can_float_p PARAMS ((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, const char *, int));
-static void init_integral_libfuncs PROTO((optab, const char *, int));
-static void init_floating_libfuncs PROTO((optab, const char *, int));
+static rtx ftruncify   PARAMS ((rtx));
+static optab init_optab        PARAMS ((enum rtx_code));
+static void init_libfuncs PARAMS ((optab, int, int, const char *, int));
+static void init_integral_libfuncs PARAMS ((optab, const char *, int));
+static void init_floating_libfuncs PARAMS ((optab, const char *, int));
 #ifdef HAVE_conditional_trap
-static void init_traps PROTO((void));
+static void init_traps PARAMS ((void));
 #endif
+static void emit_cmp_and_jump_insn_1 PARAMS ((rtx, rtx, enum machine_mode,
+                                           enum rtx_code, int, rtx));
+static void prepare_float_lib_cmp PARAMS ((rtx *, rtx *, enum rtx_code *,
+                                        enum machine_mode *, int *));
 \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
@@ -359,16 +205,32 @@ widen_operand (op, mode, oldmode, unsignedp, no_extend)
 /* Generate code to perform a straightforward complex divide.  */
 
 static int
-expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
-                         rtx realr, rtx imagr, enum machine_mode submode,
-                         int unsignedp, enum optab_methods methods,
-                         enum mode_class class, optab binoptab)
+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;
+  optab this_add_optab = add_optab;
+  optab this_sub_optab = sub_optab;
+  optab this_neg_optab = neg_optab;
+  optab this_mul_optab = smul_optab;
              
+  if (binoptab == sdivv_optab)
+    {
+      this_add_optab = addv_optab;
+      this_sub_optab = subv_optab;
+      this_neg_optab = negv_optab;
+      this_mul_optab = smulv_optab;
+    }
+
   /* Don't fetch these from memory more than once.  */
   real0 = force_reg (submode, real0);
   real1 = force_reg (submode, real1);
@@ -379,16 +241,16 @@ expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
   imag1 = force_reg (submode, imag1);
 
   /* Divisor: c*c + d*d.  */
-  temp1 = expand_binop (submode, smul_optab, real1, real1,
+  temp1 = expand_binop (submode, this_mul_optab, real1, real1,
                        NULL_RTX, unsignedp, methods);
 
-  temp2 = expand_binop (submode, smul_optab, imag1, imag1,
+  temp2 = expand_binop (submode, this_mul_optab, imag1, imag1,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0 || temp2 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, temp2,
+  divisor = expand_binop (submode, this_add_optab, temp1, temp2,
                          NULL_RTX, unsignedp, methods);
   if (divisor == 0)
     return 0;
@@ -399,44 +261,44 @@ expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
       /* Computationally, (a+i0) / (c+id) = (ac/(cc+dd)) + i(-ad/(cc+dd)).  */
 
       /* Calculate the dividend.  */
-      real_t = expand_binop (submode, smul_optab, real0, real1,
+      real_t = expand_binop (submode, this_mul_optab, real0, real1,
                             NULL_RTX, unsignedp, methods);
                  
-      imag_t = expand_binop (submode, smul_optab, real0, imag1,
+      imag_t = expand_binop (submode, this_mul_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,
+      imag_t = expand_unop (submode, this_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,
+      temp1 = expand_binop (submode, this_mul_optab, real0, real1,
                            NULL_RTX, unsignedp, methods);
 
-      temp2 = expand_binop (submode, smul_optab, imag0, imag1,
+      temp2 = expand_binop (submode, this_mul_optab, imag0, imag1,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0 || temp2 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, temp2,
+      real_t = expand_binop (submode, this_add_optab, temp1, temp2,
                             NULL_RTX, unsignedp, methods);
                  
-      temp1 = expand_binop (submode, smul_optab, imag0, real1,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, real1,
                            NULL_RTX, unsignedp, methods);
 
-      temp2 = expand_binop (submode, smul_optab, real0, imag1,
+      temp2 = expand_binop (submode, this_mul_optab, real0, imag1,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0 || temp2 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, temp1, temp2,
+      imag_t = expand_binop (submode, this_sub_optab, temp1, temp2,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -475,10 +337,14 @@ expand_cmplxdiv_straight (rtx real0, rtx real1, rtx imag0, rtx imag1,
 /* Generate code to perform a wide-input-range-acceptable complex divide.  */
 
 static int
-expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
-                     rtx realr, rtx imagr, enum machine_mode submode,
-                     int unsignedp, enum optab_methods methods,
-                     enum mode_class class, optab binoptab)
+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;
@@ -486,6 +352,18 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
   enum machine_mode mode;
   int align;
   rtx res;
+  optab this_add_optab = add_optab;
+  optab this_sub_optab = sub_optab;
+  optab this_neg_optab = neg_optab;
+  optab this_mul_optab = smul_optab;
+
+  if (binoptab == sdivv_optab)
+    {
+      this_add_optab = addv_optab;
+      this_sub_optab = subv_optab;
+      this_neg_optab = negv_optab;
+      this_mul_optab = smulv_optab;
+    }
              
   /* Don't fetch these from memory more than once.  */
   real0 = force_reg (submode, real0);
@@ -496,11 +374,17 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
 
   imag1 = force_reg (submode, imag1);
 
-  temp1 = expand_unop (submode, abs_optab, real1, NULL_RTX,
-                      unsignedp);
-
-  temp2 = expand_unop (submode, abs_optab, imag1, NULL_RTX,
-                      unsignedp);
+  /* XXX What's an "unsigned" complex number?  */
+  if (unsignedp)
+    {
+      temp1 = real1;
+      temp2 = imag1;
+    }
+  else
+    {
+      temp1 = expand_abs (submode, real1, NULL_RTX, unsignedp, 1);
+      temp2 = expand_abs (submode, imag1, NULL_RTX, unsignedp, 1);
+    }
 
   if (temp1 == 0 || temp2 == 0)
     return 0;
@@ -525,13 +409,13 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
 
   /* Calculate divisor.  */
 
-  temp1 = expand_binop (submode, smul_optab, imag1, ratio,
+  temp1 = expand_binop (submode, this_mul_optab, imag1, ratio,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, real1,
+  divisor = expand_binop (submode, this_add_optab, temp1, real1,
                          NULL_RTX, unsignedp, methods);
 
   if (divisor == 0)
@@ -545,13 +429,13 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
 
       /* 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,
+      imag_t = expand_binop (submode, this_mul_optab, real0, ratio,
                             NULL_RTX, unsignedp, methods);
 
       if (imag_t == 0)
        return 0;
 
-      imag_t = expand_unop (submode, neg_optab, imag_t,
+      imag_t = expand_unop (submode, this_neg_optab, imag_t,
                            NULL_RTX, unsignedp);
 
       if (real_t == 0 || imag_t == 0)
@@ -562,22 +446,22 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
       /* 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,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, real0,
+      real_t = expand_binop (submode, this_add_optab, temp1, real0,
                             NULL_RTX, unsignedp, methods);
 
-      temp1 = expand_binop (submode, smul_optab, real0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, imag0, temp1,
+      imag_t = expand_binop (submode, this_sub_optab, imag0, temp1,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -630,13 +514,13 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
 
   /* Calculate divisor.  */
 
-  temp1 = expand_binop (submode, smul_optab, real1, ratio,
+  temp1 = expand_binop (submode, this_mul_optab, real1, ratio,
                        NULL_RTX, unsignedp, methods);
 
   if (temp1 == 0)
     return 0;
 
-  divisor = expand_binop (submode, add_optab, temp1, imag1,
+  divisor = expand_binop (submode, this_add_optab, temp1, imag1,
                          NULL_RTX, unsignedp, methods);
 
   if (divisor == 0)
@@ -648,10 +532,10 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
     {
       /* 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,
+      real_t = expand_binop (submode, this_mul_optab, real0, ratio,
                             NULL_RTX, unsignedp, methods);
 
-      imag_t = expand_unop (submode, neg_optab, real0,
+      imag_t = expand_unop (submode, this_neg_optab, real0,
                            NULL_RTX, unsignedp);
 
       if (real_t == 0 || imag_t == 0)
@@ -662,22 +546,22 @@ expand_cmplxdiv_wide (rtx real0, rtx real1, rtx imag0, rtx imag1,
       /* 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,
+      temp1 = expand_binop (submode, this_mul_optab, real0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      real_t = expand_binop (submode, add_optab, temp1, imag0,
+      real_t = expand_binop (submode, this_add_optab, temp1, imag0,
                             NULL_RTX, unsignedp, methods);
 
-      temp1 = expand_binop (submode, smul_optab, imag0, ratio,
+      temp1 = expand_binop (submode, this_mul_optab, imag0, ratio,
                            NULL_RTX, unsignedp, methods);
 
       if (temp1 == 0)
        return 0;
 
-      imag_t = expand_binop (submode, sub_optab, temp1, real0,
+      imag_t = expand_binop (submode, this_sub_optab, temp1, real0,
                             NULL_RTX, unsignedp, methods);
 
       if (real_t == 0 || imag_t == 0)
@@ -775,11 +659,11 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
   /* If we are inside an appropriately-short loop and one operand is an
      expensive constant, force it into a register.  */
   if (CONSTANT_P (op0) && preserve_subexpressions_p ()
-      && rtx_cost (op0, binoptab->code) > 2)
+      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
     op0 = force_reg (mode, op0);
 
   if (CONSTANT_P (op1) && preserve_subexpressions_p ()
-      && ! shift_op && rtx_cost (op1, binoptab->code) > 2)
+      && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
     op1 = force_reg (mode, op1);
 
   /* Record where to delete back to if we backtrack.  */
@@ -816,8 +700,8 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       int icode = (int) binoptab->handlers[(int) mode].insn_code;
-      enum machine_mode mode0 = insn_operand_mode[icode][1];
-      enum machine_mode mode1 = insn_operand_mode[icode][2];
+      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
       rtx pat;
       rtx xop0 = op0, xop1 = op1;
 
@@ -856,15 +740,15 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       /* 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_data[icode].operand[1].predicate) (xop0, mode0)
          && mode0 != VOIDmode)
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1)
+      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
          && mode1 != VOIDmode)
        xop1 = copy_to_mode_reg (mode1, xop1);
 
-      if (! (*insn_operand_predicate[icode][0]) (temp, mode))
+      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
        temp = gen_reg_rtx (mode);
 
       pat = GEN_FCN (icode) (temp, xop0, xop1);
@@ -970,7 +854,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && GET_MODE_SIZE (mode) > UNITS_PER_WORD
       && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
     {
-      int i;
+      unsigned int i;
       rtx insns;
       rtx equiv_value;
 
@@ -1261,10 +1145,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       && GET_MODE_SIZE (mode) >= 2 * UNITS_PER_WORD
       && binoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
     {
-      int i;
+      unsigned int i;
       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;
+      unsigned int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
       rtx carry_in = NULL_RTX, carry_out = NULL_RTX;
       rtx xop0, xop1;
 
@@ -1311,7 +1195,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              carry_out = gen_reg_rtx (word_mode);
              carry_out = emit_store_flag_force (carry_out,
                                                 (binoptab == add_optab
-                                                 ? LTU : GTU),
+                                                 ? LT : GT),
                                                 x, op0_piece,
                                                 word_mode, 1, normalizep);
            }
@@ -1334,7 +1218,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                  /* Get out carry from adding/subtracting carry in.  */
                  carry_tmp = emit_store_flag_force (carry_tmp,
                                                     binoptab == add_optab
-                                                    ? LTU : GTU,
+                                                    ? LT : GT,
                                                     x, carry_in,
                                                     word_mode, 1, normalizep);
 
@@ -1362,8 +1246,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                                   copy_rtx (xop0),
                                                   copy_rtx (xop1)));
            }
+
          return target;
        }
+
       else
        delete_insns_since (last);
     }
@@ -1544,6 +1430,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
                                                       copy_rtx (op0),
                                                       copy_rtx (op1)));
                }
+
              return product;
            }
        }
@@ -1628,7 +1515,9 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
          else if (imag0)
            res = imag0;
          else if (binoptab->code == MINUS)
-           res = expand_unop (submode, neg_optab, imag1, imagr, unsignedp);
+            res = expand_unop (submode,
+                                binoptab == subv_optab ? negv_optab : neg_optab,
+                                imag1, imagr, unsignedp);
          else
            res = imag1;
 
@@ -1662,8 +1551,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              if (temp1 == 0 || temp2 == 0)
                break;
 
-             res = expand_binop (submode, sub_optab, temp1, temp2,
-                                 realr, unsignedp, methods);
+             res = (expand_binop
+                     (submode,
+                      binoptab == smulv_optab ? subv_optab : sub_optab,
+                      temp1, temp2, realr, unsignedp, methods));
 
              if (res == 0)
                break;
@@ -1679,8 +1570,10 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
              if (temp1 == 0 || temp2 == 0)
                  break;
 
-             res = expand_binop (submode, add_optab, temp1, temp2,
-                                 imagr, unsignedp, methods);
+             res = (expand_binop
+                     (submode,
+                      binoptab == smulv_optab ? addv_optab : add_optab,
+                      temp1, temp2, imagr, unsignedp, methods));
 
              if (res == 0)
                break;
@@ -1829,7 +1722,7 @@ expand_binop (mode, binoptab, op0, op1, target, unsignedp, methods)
       /* 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,
-                                      NULL_RTX, 1, mode, 2,
+                                      NULL_RTX, LCT_CONST, mode, 2,
                                       op0, mode, op1x, op1_mode);
 
       insns = get_insns ();
@@ -2013,11 +1906,11 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
   /* If we are inside an appropriately-short loop and one operand is an
      expensive constant, force it into a register.  */
   if (CONSTANT_P (op0) && preserve_subexpressions_p ()
-      && rtx_cost (op0, binoptab->code) > 2)
+      && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
     op0 = force_reg (mode, op0);
 
   if (CONSTANT_P (op1) && preserve_subexpressions_p ()
-      && rtx_cost (op1, binoptab->code) > 2)
+      && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
     op1 = force_reg (mode, op1);
 
   if (targ0)
@@ -2035,8 +1928,8 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
   if (binoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       int icode = (int) binoptab->handlers[(int) mode].insn_code;
-      enum machine_mode mode0 = insn_operand_mode[icode][1];
-      enum machine_mode mode1 = insn_operand_mode[icode][2];
+      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+      enum machine_mode mode1 = insn_data[icode].operand[2].mode;
       rtx pat;
       rtx xop0 = op0, xop1 = op1;
 
@@ -2049,16 +1942,16 @@ expand_twoval_binop (binoptab, op0, op1, targ0, targ1, unsignedp)
        xop1 = convert_to_mode (mode1, xop1, unsignedp);
 
       /* Now, if insn doesn't accept these operands, put them into pseudos.  */
-      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_operand_predicate[icode][2]) (xop1, mode1))
+      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1))
        xop1 = copy_to_mode_reg (mode1, xop1);
 
       /* We could handle this, but we should always be called with a pseudo
         for our targets and all insns should take them as outputs.  */
-      if (! (*insn_operand_predicate[icode][0]) (targ0, mode)
-         || ! (*insn_operand_predicate[icode][3]) (targ1, mode))
+      if (! (*insn_data[icode].operand[0].predicate) (targ0, mode)
+         || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
        abort ();
        
       pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
@@ -2145,7 +2038,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
   if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       int icode = (int) unoptab->handlers[(int) mode].insn_code;
-      enum machine_mode mode0 = insn_operand_mode[icode][1];
+      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
       rtx xop0 = op0;
 
       if (target)
@@ -2159,10 +2052,10 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
 
       /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
 
-      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_operand_predicate[icode][0]) (temp, mode))
+      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
        temp = gen_reg_rtx (mode);
 
       pat = GEN_FCN (icode) (temp, xop0);
@@ -2228,7 +2121,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
       && GET_MODE_SIZE (mode) > UNITS_PER_WORD
       && unoptab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
     {
-      int i;
+      unsigned int i;
       rtx insns;
 
       if (target == 0 || target == op0)
@@ -2257,7 +2150,7 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
     }
 
   /* Open-code the complex negation operation.  */
-  else if (unoptab == neg_optab
+  else if (unoptab->code == NEG
           && (class == MODE_COMPLEX_FLOAT || class == MODE_COMPLEX_INT))
     {
       rtx target_piece;
@@ -2312,7 +2205,7 @@ expand_unop (mode, unoptab, op0, target, 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 (unoptab->handlers[(int) mode].libfunc,
-                                      NULL_RTX, 1, mode, 1, op0, mode);
+                                      NULL_RTX, LCT_CONST, mode, 1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
@@ -2368,11 +2261,13 @@ 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)
+  if (unoptab->code == NEG)
     {    
       rtx temp;
-      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
-                          target, unsignedp, OPTAB_LIB_WIDEN);
+      temp = expand_binop (mode,
+                           unoptab == negv_optab ? subv_optab : sub_optab,
+                           CONST0_RTX (mode), op0,
+                           target, unsignedp, OPTAB_LIB_WIDEN);
       if (temp)
        return temp;
     }
@@ -2390,23 +2285,47 @@ expand_unop (mode, unoptab, op0, target, unsignedp)
  */
 
 rtx
-expand_abs (mode, op0, target, safe)
+expand_abs (mode, op0, target, result_unsignedp, safe)
      enum machine_mode mode;
      rtx op0;
      rtx target;
+     int result_unsignedp;
      int safe;
 {
   rtx temp, op1;
 
+  if (! flag_trapv)
+    result_unsignedp = 1;
+
   /* First try to do it with a special abs instruction.  */
-  temp = expand_unop (mode, abs_optab, op0, target, 0);
+  temp = expand_unop (mode, result_unsignedp ? abs_optab : absv_optab,
+                      op0, target, 0);
   if (temp != 0)
     return temp;
 
+  /* If we have a MAX insn, we can do this as MAX (x, -x).  */
+  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+    {
+      rtx last = get_last_insn ();
+
+      temp = expand_unop (mode, neg_optab, op0, NULL_RTX, 0);
+      if (temp != 0)
+       temp = expand_binop (mode, smax_optab, op0, temp, target, 0,
+                            OPTAB_WIDEN);
+
+      if (temp != 0)
+       return temp;
+
+      delete_insns_since (last);
+    }
+
   /* 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.  */
+     where W is the width of MODE.  But don't do this if the machine has
+     conditional arithmetic since the branches will be converted into
+     a conditional negation insn.  */
 
+#ifndef HAVE_conditional_arithmetic
   if (GET_MODE_CLASS (mode) == MODE_INT && BRANCH_COST >= 2)
     {
       rtx extended = expand_shift (RSHIFT_EXPR, mode, op0,
@@ -2416,12 +2335,13 @@ expand_abs (mode, op0, target, safe)
       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);
+       temp = expand_binop (mode, result_unsignedp ? sub_optab : subv_optab,
+                             temp, extended, target, 0, OPTAB_LIB_WIDEN);
 
       if (temp != 0)
        return temp;
     }
+#endif
 
   /* If that does not win, use conditional jump and negate.  */
 
@@ -2444,25 +2364,16 @@ expand_abs (mode, op0, target, safe)
 
   /* 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))
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && ! can_compare_p (GE, mode, ccp_jump))
     do_jump_by_parts_greater_rtx (mode, 0, target, const0_rtx, 
                                  NULL_RTX, op1);
   else
-    {
-      temp = compare_from_rtx (target, CONST0_RTX (mode), GE, 0, mode,
-                              NULL_RTX, 0);
-      if (temp == const1_rtx)
-       return target;
-      else if (temp != const0_rtx)
-       {
-         if (bcc_gen_fctn[(int) GET_CODE (temp)] != 0)
-           emit_jump_insn ((*bcc_gen_fctn[(int) GET_CODE (temp)]) (op1));
-         else
-           abort ();
-       }
-    }
+    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);
+  op0 = expand_unop (mode, result_unsignedp ? neg_optab : negv_optab,
+                     target, target, 0);
   if (op0 != target)
     emit_move_insn (target, op0);
   emit_label (op1);
@@ -2492,6 +2403,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
   rtx entry_last = get_last_insn ();
   rtx last;
   rtx pat;
+  optab this_abs_optab;
 
   /* Find the correct mode for the real and imaginary parts.  */
   enum machine_mode submode
@@ -2514,10 +2426,14 @@ expand_complex_abs (mode, op0, target, unsignedp)
   if (target)
     target = protect_from_queue (target, 1);
 
-  if (abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
+  this_abs_optab = ! unsignedp && flag_trapv
+                   && (GET_MODE_CLASS(mode) == MODE_INT)
+                   ? absv_optab : abs_optab;
+
+  if (this_abs_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
-      int icode = (int) abs_optab->handlers[(int) mode].insn_code;
-      enum machine_mode mode0 = insn_operand_mode[icode][1];
+      int icode = (int) this_abs_optab->handlers[(int) mode].insn_code;
+      enum machine_mode mode0 = insn_data[icode].operand[1].mode;
       rtx xop0 = op0;
 
       if (target)
@@ -2531,20 +2447,22 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
       /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
 
-      if (! (*insn_operand_predicate[icode][1]) (xop0, mode0))
+      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_operand_predicate[icode][0]) (temp, submode))
+      if (! (*insn_data[icode].operand[0].predicate) (temp, submode))
        temp = gen_reg_rtx (submode);
 
       pat = GEN_FCN (icode) (temp, xop0);
       if (pat)
        {
          if (GET_CODE (pat) == SEQUENCE
-             && ! add_equal_note (pat, temp, abs_optab->code, xop0, NULL_RTX))
+             && ! add_equal_note (pat, temp, this_abs_optab->code, xop0, 
+                                  NULL_RTX))
            {
              delete_insns_since (last);
-             return expand_unop (mode, abs_optab, op0, NULL_RTX, unsignedp);
+             return expand_unop (mode, this_abs_optab, op0, NULL_RTX, 
+                                 unsignedp);
            }
 
          emit_insn (pat);
@@ -2560,7 +2478,8 @@ expand_complex_abs (mode, op0, target, unsignedp)
   for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
        wider_mode = GET_MODE_WIDER_MODE (wider_mode))
     {
-      if (abs_optab->handlers[(int) wider_mode].insn_code != CODE_FOR_nothing)
+      if (this_abs_optab->handlers[(int) wider_mode].insn_code 
+         != CODE_FOR_nothing)
        {
          rtx xop0 = op0;
 
@@ -2586,7 +2505,8 @@ expand_complex_abs (mode, op0, target, unsignedp)
 
   /* Open-code the complex absolute-value operation
      if we can open-code sqrt.  Otherwise it's not worth while.  */
-  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing)
+  if (sqrt_optab->handlers[(int) submode].insn_code != CODE_FOR_nothing
+      && ! flag_trapv)
     {
       rtx real, imag, total;
 
@@ -2610,7 +2530,7 @@ expand_complex_abs (mode, op0, target, unsignedp)
     }
 
   /* Now try a library call in this mode.  */
-  if (abs_optab->handlers[(int) mode].libfunc)
+  if (this_abs_optab->handlers[(int) mode].libfunc)
     {
       rtx insns;
       rtx value;
@@ -2620,13 +2540,13 @@ expand_complex_abs (mode, op0, target, 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 (abs_optab->handlers[(int) mode].libfunc,
-                                      NULL_RTX, 1, submode, 1, op0, mode);
+                                      NULL_RTX, LCT_CONST, submode, 1, op0, mode);
       insns = get_insns ();
       end_sequence ();
 
       target = gen_reg_rtx (submode);
       emit_libcall_block (insns, target, value,
-                         gen_rtx_fmt_e (abs_optab->code, mode, op0));
+                         gen_rtx_fmt_e (this_abs_optab->code, mode, op0));
 
       return target;
     }
@@ -2636,9 +2556,9 @@ expand_complex_abs (mode, op0, target, unsignedp)
   for (wider_mode = GET_MODE_WIDER_MODE (mode); wider_mode != VOIDmode;
        wider_mode = GET_MODE_WIDER_MODE (wider_mode))
     {
-      if ((abs_optab->handlers[(int) wider_mode].insn_code
+      if ((this_abs_optab->handlers[(int) wider_mode].insn_code
           != CODE_FOR_nothing)
-         || abs_optab->handlers[(int) wider_mode].libfunc)
+         || this_abs_optab->handlers[(int) wider_mode].libfunc)
        {
          rtx xop0 = op0;
 
@@ -2681,7 +2601,7 @@ emit_unop_insn (icode, target, op0, code)
      enum rtx_code code;
 {
   register rtx temp;
-  enum machine_mode mode0 = insn_operand_mode[icode][1];
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   rtx pat;
 
   temp = target = protect_from_queue (target, 1);
@@ -2696,10 +2616,10 @@ emit_unop_insn (icode, target, op0, code)
 
   /* Now, if insn does not accept our operands, put them into pseudos.  */
 
-  if (! (*insn_operand_predicate[icode][1]) (op0, mode0))
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
     op0 = copy_to_mode_reg (mode0, op0);
 
-  if (! (*insn_operand_predicate[icode][0]) (temp, GET_MODE (temp))
+  if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
       || (flag_force_mem && GET_CODE (temp) == MEM))
     temp = gen_reg_rtx (GET_MODE (temp));
 
@@ -2768,7 +2688,8 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
 
       next = NEXT_INSN (insn);
 
-      if (GET_CODE (PATTERN (insn)) == SET)
+      if (GET_CODE (PATTERN (insn)) == SET || GET_CODE (PATTERN (insn)) == USE
+         || GET_CODE (PATTERN (insn)) == CLOBBER)
        set = PATTERN (insn);
       else if (GET_CODE (PATTERN (insn)) == PARALLEL)
        {
@@ -2826,7 +2747,16 @@ emit_no_conflict_block (insns, target, op0, op1, equiv)
        set_unique_reg_note (last, REG_EQUAL, equiv);
     }
   else
-    last = get_last_insn ();
+    {
+      last = get_last_insn ();
+
+      /* Remove any existing REG_EQUAL note from "last", or else it will
+        be mistaken for a note referring to the full contents of the
+        alleged libcall value when found together with the REG_RETVAL
+        note added below.  An existing note can come from an insn
+        expansion at "last".  */
+      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
+    }
 
   if (prev == 0)
     first = get_insns ();
@@ -2873,22 +2803,31 @@ emit_libcall_block (insns, target, result, equiv)
      rtx result;
      rtx equiv;
 {
+  rtx final_dest = target;
   rtx prev, next, first, last, insn;
 
+  /* If this is a reg with REG_USERVAR_P set, then it could possibly turn
+     into a MEM later.  Protect the libcall block from this change.  */
+  if (! REG_P (target) || REG_USERVAR_P (target))
+    target = gen_reg_rtx (GET_MODE (target));
+
   /* 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.) */
+     reg note to indicate that this call cannot throw or execute a nonlocal
+     goto (unless there is already a REG_EH_REGION note, in which case
+     we update it).  Also set the CONST_CALL_P flag.  */
 
   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));
-        }
-    }
+    if (GET_CODE (insn) == CALL_INSN)
+      {
+       rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX);
+
+       CONST_CALL_P (insn) = 1;
+       if (note != 0)
+         XEXP (note, 0) = GEN_INT (-1);
+       else
+         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
@@ -2905,7 +2844,8 @@ emit_libcall_block (insns, target, result, equiv)
       if (set != 0 && GET_CODE (SET_DEST (set)) == REG
          && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
          && (insn == insns
-             || (! reg_mentioned_p (SET_DEST (set), PATTERN (insns))
+             || ((! INSN_P(insns)
+                  || ! reg_mentioned_p (SET_DEST (set), PATTERN (insns)))
                  && ! reg_used_between_p (SET_DEST (set), insns, insn)
                  && ! modified_in_p (SET_SRC (set), insns)
                  && ! modified_between_p (SET_SRC (set), insns, insn))))
@@ -2937,6 +2877,18 @@ emit_libcall_block (insns, target, result, equiv)
   if (mov_optab->handlers[(int) GET_MODE (target)].insn_code
       != CODE_FOR_nothing)
     set_unique_reg_note (last, REG_EQUAL, copy_rtx (equiv));
+  else
+    {
+      /* Remove any existing REG_EQUAL note from "last", or else it will
+        be mistaken for a note referring to the full contents of the
+        libcall value when found together with the REG_RETVAL note added
+        below.  An existing note can come from an insn expansion at
+        "last".  */
+      remove_note (last, find_reg_note (last, REG_EQUAL, NULL_RTX));
+    }
+
+  if (final_dest != target)
+    emit_move_insn (final_dest, target);
 
   if (prev == 0)
     first = get_insns ();
@@ -2968,31 +2920,82 @@ 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 straightforwardly.
+   PURPOSE describes how this comparison will be used.  CODE is the rtx
+   comparison code we will be using.
 
-   MODE is the mode of the inputs (in case they are const_int).
-   UNSIGNEDP nonzero says that X and Y are unsigned;
+   ??? Actually, CODE is slightly weaker than that.  A target is still
+   required to implement all of the normal bcc operations, but not 
+   required to implement all (or any) of the unordered bcc operations.  */
+  
+int
+can_compare_p (code, mode, purpose)
+     enum rtx_code code;
+     enum machine_mode mode;
+     enum can_compare_purpose purpose;
+{
+  do
+    {
+      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+       {
+         if (purpose == ccp_jump)
+           return bcc_gen_fctn[(int)code] != NULL;
+         else if (purpose == ccp_store_flag)
+           return setcc_gen_code[(int)code] != CODE_FOR_nothing;
+         else
+           /* There's only one cmov entry point, and it's allowed to fail.  */
+           return 1;
+       }
+      if (purpose == ccp_jump
+         && cbranch_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+       return 1;
+      if (purpose == ccp_cmov
+         && cmov_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+       return 1;
+      if (purpose == ccp_store_flag
+         && cstore_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
+       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;
+prepare_cmp_insn (px, py, pcomparison, size, pmode, punsignedp, align,
+                 purpose)
+     rtx *px, *py;
+     enum rtx_code *pcomparison;
      rtx size;
-     enum machine_mode mode;
-     int unsignedp;
-     int align;
+     enum machine_mode *pmode;
+     int *punsignedp;
+     int align ATTRIBUTE_UNUSED;
+     enum can_compare_purpose purpose;
 {
+  enum machine_mode mode = *pmode;
+  rtx x = *px, y = *py;
+  int unsignedp = *punsignedp;
   enum mode_class class;
-  enum machine_mode wider_mode;
+  rtx opalign ATTRIBUTE_UNUSED = GEN_INT (align / BITS_PER_UNIT);;
 
   class = GET_MODE_CLASS (mode);
 
@@ -3009,10 +3012,12 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
 
   /* If we are inside an appropriately-short loop and one operand is an
      expensive constant, force it into a register.  */
-  if (CONSTANT_P (x) && preserve_subexpressions_p () && rtx_cost (x, COMPARE) > 2)
+  if (CONSTANT_P (x) && preserve_subexpressions_p ()
+      && rtx_cost (x, COMPARE) > COSTS_N_INSNS (1))
     x = force_reg (mode, x);
 
-  if (CONSTANT_P (y) && preserve_subexpressions_p () && rtx_cost (y, COMPARE) > 2)
+  if (CONSTANT_P (y) && preserve_subexpressions_p ()
+      && rtx_cost (y, COMPARE) > COSTS_N_INSNS (1))
     y = force_reg (mode, y);
 
 #ifdef HAVE_cc0
@@ -3031,6 +3036,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);
@@ -3042,12 +3050,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);
-         emit_insn (gen_cmpstrqi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
+         result_mode = insn_data[(int) CODE_FOR_cmpstrqi].operand[0].mode;
+         result = gen_reg_rtx (result_mode);
+         emit_insn (gen_cmpstrqi (result, x, y, size, opalign));
        }
       else
 #endif
@@ -3056,42 +3061,34 @@ 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);
-         emit_insn (gen_cmpstrhi (result, x, y, size, GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
+         result_mode = insn_data[(int) CODE_FOR_cmpstrhi].operand[0].mode;
+         result = gen_reg_rtx (result_mode);
+         emit_insn (gen_cmpstrhi (result, x, y, size, opalign));
        }
       else
 #endif
 #ifdef HAVE_cmpstrsi
       if (HAVE_cmpstrsi)
        {
-         enum machine_mode result_mode
-           = insn_operand_mode[(int) CODE_FOR_cmpstrsi][0];
-         rtx result = gen_reg_rtx (result_mode);
+         result_mode = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
+         result = gen_reg_rtx (result_mode);
          size = protect_from_queue (size, 0);
          emit_insn (gen_cmpstrsi (result, x, y,
                                   convert_to_mode (SImode, size, 1),
-                                  GEN_INT (align)));
-         emit_cmp_insn (result, const0_rtx, comparison, NULL_RTX,
-                        result_mode, 0, 0);
+                                  opalign));
        }
       else
 #endif
        {
-         rtx result;
-
 #ifdef TARGET_MEM_FUNCTIONS
-         emit_library_call (memcmp_libfunc, 0,
+         emit_library_call (memcmp_libfunc, LCT_PURE_MAKE_BLOCK,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
                             convert_to_mode (TYPE_MODE (sizetype), size,
                                              TREE_UNSIGNED (sizetype)),
                             TYPE_MODE (sizetype));
 #else
-         emit_library_call (bcmp_libfunc, 0,
+         emit_library_call (bcmp_libfunc, LCT_PURE_MAKE_BLOCK,
                             TYPE_MODE (integer_type_node), 3,
                             XEXP (x, 0), Pmode, XEXP (y, 0), Pmode,
                             convert_to_mode (TYPE_MODE (integer_type_node),
@@ -3104,83 +3101,24 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
             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 (TYPE_MODE (integer_type_node)));
-         emit_cmp_insn (result,
-                        const0_rtx, comparison, NULL_RTX,
-                        TYPE_MODE (integer_type_node), 0, 0);
+                         hard_libcall_value (result_mode));
        }
+      *px = result;
+      *py = const0_rtx;
+      *pmode = result_mode;
       return;
     }
 
-  /* Handle some compares against zero.  */
-
-  if (y == CONST0_RTX (mode)
-      && tst_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-    {
-      int icode = (int) tst_optab->handlers[(int) mode].insn_code;
-
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
-
-      /* 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_insn (GEN_FCN (icode) (x));
-      return;
-    }
-
-  /* Handle compares for which there is a directly suitable insn.  */
-
-  if (cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-    {
-      int icode = (int) cmp_optab->handlers[(int) mode].insn_code;
-
-      emit_queue ();
-      x = protect_from_queue (x, 0);
-      y = protect_from_queue (y, 0);
-
-      /* 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);
-
-      if (! (*insn_operand_predicate[icode][1])
-         (y, insn_operand_mode[icode][1]))
-       y = copy_to_mode_reg (insn_operand_mode[icode][1], y);
-
-      emit_insn (GEN_FCN (icode) (x, y));
-      return;
-    }
-
-  /* Try widening if we can find a direct insn that way.  */
-
-  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;
-           }
-       }
-    }
+  *px = x;
+  *py = y;
+  if (can_compare_p (*pcomparison, mode, purpose))
+    return;
 
   /* Handle a lib call just for the mode we are using.  */
 
-  if (cmp_optab->handlers[(int) mode].libfunc
-      && class != MODE_FLOAT)
+  if (cmp_optab->handlers[(int) mode].libfunc && class != MODE_FLOAT)
     {
       rtx libfunc = cmp_optab->handlers[(int) mode].libfunc;
       rtx result;
@@ -3202,18 +3140,114 @@ emit_cmp_insn (x, y, comparison, size, mode, unsignedp, align)
       /* Integer comparison returns a result that must be compared against 1,
         so that even if we do an unsigned compare afterward,
         there is still a value that can represent the result "less than".  */
-      emit_cmp_insn (result, const1_rtx,
-                    comparison, NULL_RTX, word_mode, unsignedp, 0);
+      *px = result;
+      *py = const1_rtx;
+      *pmode = word_mode;
       return;
     }
 
   if (class == MODE_FLOAT)
-    emit_float_lib_cmp (x, y, comparison);
+    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.  */
+
+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 (! (*insn_data[icode].operand[opnum].predicate)
+      (x, insn_data[icode].operand[opnum].mode))
+    x = copy_to_mode_reg (insn_data[icode].operand[opnum].mode, x);
+  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
+    {
+      enum insn_code icode;
+      PUT_MODE (test, wider_mode);
+
+      if (label)
+       {         
+         icode = cbranch_optab->handlers[(int)wider_mode].insn_code;
+         
+         if (icode != CODE_FOR_nothing
+             && (*insn_data[icode].operand[0].predicate) (test, wider_mode))
+           {
+             x = prepare_operand (icode, x, 1, mode, wider_mode, unsignedp);
+             y = prepare_operand (icode, y, 2, mode, wider_mode, unsignedp);
+             emit_jump_insn (GEN_FCN (icode) (test, x, y, label));
+             return;
+           }
+       }
+
+      /* 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;
+       }
+
+      /* 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 (class != MODE_INT && class != MODE_FLOAT
+         && class != MODE_COMPLEX_FLOAT)
+       break;
+
+      wider_mode = GET_MODE_WIDER_MODE (wider_mode);
+    } while (wider_mode != VOIDmode);
+
+  abort ();
+}
+
 /* Generate code to compare X with Y so that the condition codes are
    set and to jump to LABEL if the condition is true.  If X is a
    constant and Y is not a constant, then the comparison is swapped to
@@ -3239,13 +3273,14 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
      rtx size;
      enum machine_mode mode;
      int unsignedp;
-     int align;
+     unsigned int align;
      rtx label;
 {
   rtx op0;
   rtx op1;
          
-  if (CONSTANT_P (x))
+  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;
@@ -3266,39 +3301,41 @@ emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, label)
     op0 = force_reg (mode, op0);
 #endif
 
-  emit_cmp_insn (op0, op1, comparison, size, mode, unsignedp, align);
-
+  emit_queue ();
   if (unsignedp)
     comparison = unsigned_condition (comparison);
-  emit_jump_insn ((*bcc_gen_fctn[(int) comparison]) (label));
+  prepare_cmp_insn (&op0, &op1, &comparison, size, &mode, &unsignedp, align,
+                   ccp_jump);
+  emit_cmp_and_jump_insn_1 (op0, op1, mode, comparison, unsignedp, label);
 }
 
+/* Like emit_cmp_and_jump_insns, but generate only the comparison.  */
 
-/* Nonzero if a compare of mode MODE can be done straightforwardly
-   (without splitting it into pieces).  */
-
-int
-can_compare_p (mode)
+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;
+     unsigned int align;
 {
-  do
-    {
-      if (cmp_optab->handlers[(int)mode].insn_code != CODE_FOR_nothing)
-       return 1;
-      mode = GET_MODE_WIDER_MODE (mode);
-    } while (mode != VOIDmode);
-
-  return 0;
+  emit_cmp_and_jump_insns (x, y, comparison, size, mode, unsignedp, align, 0);
 }
 \f
 /* 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 = protect_from_queue (*px, 0);
+  rtx y = *py = protect_from_queue (*py, 0);
   enum machine_mode mode = GET_MODE (x);
   rtx libfunc = 0;
   rtx result;
@@ -3330,6 +3367,10 @@ emit_float_lib_cmp (x, y, comparison)
        libfunc = lehf2_libfunc;
        break;
 
+      case UNORDERED:
+       libfunc = unordhf2_libfunc;
+       break;
+
       default:
        break;
       }
@@ -3360,6 +3401,10 @@ emit_float_lib_cmp (x, y, comparison)
        libfunc = lesf2_libfunc;
        break;
 
+      case UNORDERED:
+       libfunc = unordsf2_libfunc;
+       break;
+
       default:
        break;
       }
@@ -3390,6 +3435,10 @@ emit_float_lib_cmp (x, y, comparison)
        libfunc = ledf2_libfunc;
        break;
 
+      case UNORDERED:
+       libfunc = unorddf2_libfunc;
+       break;
+
       default:
        break;
       }
@@ -3420,6 +3469,10 @@ emit_float_lib_cmp (x, y, comparison)
        libfunc = lexf2_libfunc;
        break;
 
+      case UNORDERED:
+       libfunc = unordxf2_libfunc;
+       break;
+
       default:
        break;
       }
@@ -3450,6 +3503,10 @@ emit_float_lib_cmp (x, y, comparison)
        libfunc = letf2_libfunc;
        break;
 
+      case UNORDERED:
+       libfunc = unordtf2_libfunc;
+       break;
+
       default:
        break;
       }
@@ -3466,9 +3523,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;
            }
        }
@@ -3478,17 +3535,24 @@ emit_float_lib_cmp (x, y, comparison)
   if (libfunc == 0)
     abort ();
 
-  emit_library_call (libfunc, 1,
-                    word_mode, 2, x, mode, y, mode);
+  emit_library_call (libfunc, LCT_CONST_MAKE_BLOCK, word_mode, 2, x, mode, y,
+                    mode);
 
   /* Immediately move the result of the libcall into a pseudo
      register so reload doesn't clobber the value if it needs
      the return register for a spill reg.  */
   result = gen_reg_rtx (word_mode);
   emit_move_insn (result, hard_libcall_value (word_mode));
-
-  emit_cmp_insn (result, const0_rtx, comparison,
-                NULL_RTX, word_mode, 0, 0);
+  *px = result;
+  *py = const0_rtx;
+  *pmode = word_mode;
+  if (comparison == UNORDERED)
+    *pcomparison = NE;
+#ifdef FLOAT_LIB_COMPARE_RETURNS_BOOL
+  else if (FLOAT_LIB_COMPARE_RETURNS_BOOL (mode, comparison))
+    *pcomparison = NE;
+#endif
+  *punsignedp = 0;
 }
 \f
 /* Generate code to indirectly jump to a location given in the rtx LOC.  */
@@ -3497,7 +3561,7 @@ void
 emit_indirect_jump (loc)
      rtx loc;
 {
-  if (! ((*insn_operand_predicate[(int)CODE_FOR_indirect_jump][0])
+  if (! ((*insn_data[(int)CODE_FOR_indirect_jump].operand[0].predicate)
         (loc, Pmode)))
     loc = copy_to_mode_reg (Pmode, loc);
 
@@ -3547,6 +3611,14 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
       code = swap_condition (code);
     }
 
+  /* get_condition will prefer to generate LT and GT even if the old
+     comparison was against zero, so undo that canonicalization here since
+     comparisons against zero are cheaper.  */
+  if (code == LT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == 1)
+    code = LE, op1 = const0_rtx;
+  else if (code == GT && GET_CODE (op1) == CONST_INT && INTVAL (op1) == -1)
+    code = GE, op1 = const0_rtx;
+
   if (cmode == VOIDmode)
     cmode = GET_MODE (op0);
 
@@ -3589,17 +3661,17 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
 
   /* 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_data[icode].operand[0].predicate)
+      (subtarget, insn_data[icode].operand[0].mode))
+    subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
 
-  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_data[icode].operand[2].predicate)
+      (op2, insn_data[icode].operand[2].mode))
+    op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
 
-  if (! (*insn_operand_predicate[icode][3])
-      (op3, insn_operand_mode[icode][3]))
-    op3 = copy_to_mode_reg (insn_operand_mode[icode][3], op3);
+  if (! (*insn_data[icode].operand[3].predicate)
+      (op3, insn_data[icode].operand[3].mode))
+    op3 = copy_to_mode_reg (insn_data[icode].operand[3].mode, op3);
 
   /* Everything should now be in the suitable form, so emit the compare insn
      and then the conditional move.  */
@@ -3608,9 +3680,11 @@ emit_conditional_move (target, code, op0, op1, cmode, op2, op3, mode,
     = compare_from_rtx (op0, op1, code, unsignedp, cmode, NULL_RTX, 0);
 
   /* ??? Watch for const0_rtx (nop) and const_true_rtx (unconditional)?  */
+  /* We can get const0_rtx or const_true_rtx in some circumstances.  Just
+     return NULL and let the caller figure out how best to deal with this
+     situation.  */
   if (GET_CODE (comparison) != code)
-    /* This shouldn't happen.  */
-    abort ();
+    return NULL_RTX;
   
   insn = GEN_FCN (icode) (subtarget, comparison, op2, op3);
 
@@ -3661,9 +3735,12 @@ gen_add2_insn (x, y)
 {
   int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code; 
 
-  if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
-      || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
-      || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
+  if (! ((*insn_data[icode].operand[0].predicate)
+        (x, insn_data[icode].operand[0].mode))
+      || ! ((*insn_data[icode].operand[1].predicate)
+           (x, insn_data[icode].operand[1].mode))
+      || ! ((*insn_data[icode].operand[2].predicate)
+           (y, insn_data[icode].operand[2].mode)))
     abort ();
 
   return (GEN_FCN (icode) (x, x, y));
@@ -3684,9 +3761,12 @@ gen_sub2_insn (x, y)
 {
   int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code; 
 
-  if (! (*insn_operand_predicate[icode][0]) (x, insn_operand_mode[icode][0])
-      || ! (*insn_operand_predicate[icode][1]) (x, insn_operand_mode[icode][1])
-      || ! (*insn_operand_predicate[icode][2]) (y, insn_operand_mode[icode][2]))
+  if (! ((*insn_data[icode].operand[0].predicate)
+        (x, insn_data[icode].operand[0].mode))
+      || ! ((*insn_data[icode].operand[1].predicate)
+           (x, insn_data[icode].operand[1].mode))
+      || ! ((*insn_data[icode].operand[2].predicate)
+           (y, insn_data[icode].operand[2].mode)))
     abort ();
 
   return (GEN_FCN (icode) (x, x, y));
@@ -3749,7 +3829,6 @@ gen_move_insn (x, y)
          if (x == 0 && GET_CODE (x1) == MEM)
            {
              x = gen_rtx_MEM (tmode, XEXP (x1, 0));
-             RTX_UNCHANGING_P (x) = RTX_UNCHANGING_P (x1);
              MEM_COPY_ATTRIBUTES (x, x1);
              copy_replacements (x1, x);
            }
@@ -3758,7 +3837,6 @@ gen_move_insn (x, y)
          if (y == 0 && GET_CODE (y1) == MEM)
            {
              y = gen_rtx_MEM (tmode, XEXP (y1, 0));
-             RTX_UNCHANGING_P (y) = RTX_UNCHANGING_P (y1);
              MEM_COPY_ATTRIBUTES (y, y1);
              copy_replacements (y1, y);
            }
@@ -3789,7 +3867,7 @@ can_extend_p (to_mode, from_mode, unsignedp)
      enum machine_mode to_mode, from_mode;
      int unsignedp;
 {
-  return extendtab[(int) to_mode][(int) from_mode][unsignedp];
+  return extendtab[(int) to_mode][(int) from_mode][unsignedp != 0];
 }
 
 /* Generate the body of an insn to extend Y (with mode MFROM)
@@ -3801,7 +3879,7 @@ gen_extend_insn (x, y, mto, mfrom, unsignedp)
      enum machine_mode mto, mfrom;
      int unsignedp;
 {
-  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp]) (x, y));
+  return (GEN_FCN (extendtab[(int) mto][(int) mfrom][unsignedp != 0]) (x, y));
 }
 \f
 /* can_fix_p and can_float_p say whether the target machine
@@ -3820,13 +3898,14 @@ can_fix_p (fixmode, fltmode, unsignedp, truncp_ptr)
      int *truncp_ptr;
 {
   *truncp_ptr = 0;
-  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp] != CODE_FOR_nothing)
-    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp];
+  if (fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0]
+      != CODE_FOR_nothing)
+    return fixtrunctab[(int) fltmode][(int) fixmode][unsignedp != 0];
 
   if (ftrunc_optab->handlers[(int) fltmode].insn_code != CODE_FOR_nothing)
     {
       *truncp_ptr = 1;
-      return fixtab[(int) fltmode][(int) fixmode][unsignedp];
+      return fixtab[(int) fltmode][(int) fixmode][unsignedp != 0];
     }
   return CODE_FOR_nothing;
 }
@@ -3836,7 +3915,7 @@ can_float_p (fltmode, fixmode, unsignedp)
      enum machine_mode fixmode, fltmode;
      int unsignedp;
 {
-  return floattab[(int) fltmode][(int) fixmode][unsignedp];
+  return floattab[(int) fltmode][(int) fixmode][unsignedp != 0];
 }
 \f
 /* Generate code to convert FROM to floating point
@@ -3870,6 +3949,10 @@ expand_float (to, from, unsignedp)
       {
        int doing_unsigned = unsignedp;
 
+       if (fmode != GET_MODE (to)
+           && significand_size (fmode) < GET_MODE_BITSIZE (GET_MODE (from)))
+         continue;
+
        icode = can_float_p (fmode, imode, unsignedp);
        if (icode == CODE_FOR_nothing && imode != GET_MODE (from) && unsignedp)
          icode = can_float_p (fmode, imode, 0), doing_unsigned = 0;
@@ -3945,8 +4028,8 @@ expand_float (to, from, unsignedp)
              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));
+             emit_cmp_and_jump_insns (from, const0_rtx, LT, NULL_RTX, imode,
+                                      0, 0, neglabel);
 
              /* The sign bit is not set.  Convert as signed.  */
              expand_float (target, from, 0);
@@ -4077,9 +4160,9 @@ expand_float (to, from, unsignedp)
 
       start_sequence ();
 
-      value = emit_library_call_value (libfcn, NULL_RTX, 1,
-                                      GET_MODE (to),
-                                      1, from, GET_MODE (from));
+      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+                                      GET_MODE (to), 1, from,
+                                      GET_MODE (from));
       insns = get_insns ();
       end_sequence ();
 
@@ -4236,6 +4319,7 @@ expand_fix (to, from, unsignedp)
                                                  GET_MODE (to),
                                                  copy_rtx (from)));
            }
+
          return;
        }
 #endif
@@ -4310,9 +4394,9 @@ expand_fix (to, from, unsignedp)
 
       start_sequence ();
 
-      value = emit_library_call_value (libfcn, NULL_RTX, 1, GET_MODE (to),
-
-                                      1, from, GET_MODE (from));
+      value = emit_library_call_value (libfcn, NULL_RTX, LCT_CONST,
+                                      GET_MODE (to), 1, from,
+                                      GET_MODE (from));
       insns = get_insns ();
       end_sequence ();
 
@@ -4380,10 +4464,9 @@ 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 *libfunc_name = alloca (2 + opname_len + mname_len + 1 + 1);
       register char *p;
       register const char *q;
 
@@ -4393,11 +4476,13 @@ init_libfuncs (optable, first_mode, last_mode, opname, suffix)
       for (q = opname; *q; )
        *p++ = *q++;
       for (q = mname; *q; q++)
-       *p++ = tolower ((unsigned char)*q);
+       *p++ = TOLOWER (*q);
       *p++ = suffix;
-      *p++ = '\0';
+      *p = '\0';
+
       optable->handlers[(int) mode].libfunc
-       = gen_rtx_SYMBOL_REF (Pmode, libfunc_name);
+       = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (libfunc_name,
+                                                      p - libfunc_name));
     }
 }
 
@@ -4429,6 +4514,27 @@ init_floating_libfuncs (optable, opname, suffix)
   init_libfuncs (optable, SFmode, TFmode, opname, suffix);
 }
 
+rtx
+init_one_libfunc (name)
+     register const char *name;
+{
+  name = ggc_strdup (name);
+
+  return gen_rtx_SYMBOL_REF (Pmode, name);
+}
+
+/* Mark ARG (which is really an OPTAB *) for GC.  */
+
+void
+mark_optab (arg)
+     void *arg;
+{
+  optab o = *(optab *) arg;
+  int i;
+
+  for (i = 0; i < NUM_MACHINE_MODES; ++i)
+    ggc_mark_rtx (o->handlers[i].libfunc);
+}
 
 /* Call this once to initialize the contents of the optabs
    appropriately for the current target machine.  */
@@ -4436,34 +4542,29 @@ init_floating_libfuncs (optable, opname, suffix)
 void
 init_optabs ()
 {
-  int i;
-#ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC
-  int j;
-#endif
-
-  enum insn_code *p;
+  unsigned int i, j, k;
 
   /* Start by initializing all tables to contain CODE_FOR_nothing.  */
 
-  for (p = fixtab[0][0];
-       p < fixtab[0][0] + sizeof fixtab / sizeof (fixtab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
+  for (i = 0; i < ARRAY_SIZE (fixtab); i++)
+    for (j = 0; j < ARRAY_SIZE (fixtab[0]); j++)
+      for (k = 0; k < ARRAY_SIZE (fixtab[0][0]); k++)
+       fixtab[i][j][k] = CODE_FOR_nothing;
 
-  for (p = fixtrunctab[0][0];
-       p < fixtrunctab[0][0] + sizeof fixtrunctab / sizeof (fixtrunctab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
+  for (i = 0; i < ARRAY_SIZE (fixtrunctab); i++)
+    for (j = 0; j < ARRAY_SIZE (fixtrunctab[0]); j++)
+      for (k = 0; k < ARRAY_SIZE (fixtrunctab[0][0]); k++)
+       fixtrunctab[i][j][k] = CODE_FOR_nothing;
 
-  for (p = floattab[0][0];
-       p < floattab[0][0] + sizeof floattab / sizeof (floattab[0][0][0]); 
-       p++)
-    *p = CODE_FOR_nothing;
+  for (i = 0; i < ARRAY_SIZE (floattab); i++)
+    for (j = 0; j < ARRAY_SIZE (floattab[0]); j++)
+      for (k = 0; k < ARRAY_SIZE (floattab[0][0]); k++)
+       floattab[i][j][k] = CODE_FOR_nothing;
 
-  for (p = extendtab[0][0];
-       p < extendtab[0][0] + sizeof extendtab / sizeof extendtab[0][0][0];
-       p++)
-    *p = CODE_FOR_nothing;
+  for (i = 0; i < ARRAY_SIZE (extendtab); i++)
+    for (j = 0; j < ARRAY_SIZE (extendtab[0]); j++)
+      for (k = 0; k < ARRAY_SIZE (extendtab[0][0]); k++)
+       extendtab[i][j][k] = CODE_FOR_nothing;
 
   for (i = 0; i < NUM_RTX_CODE; i++)
     setcc_gen_code[i] = CODE_FOR_nothing;
@@ -4474,13 +4575,17 @@ init_optabs ()
 #endif
 
   add_optab = init_optab (PLUS);
+  addv_optab = init_optab (PLUS);
   sub_optab = init_optab (MINUS);
+  subv_optab = init_optab (MINUS);
   smul_optab = init_optab (MULT);
+  smulv_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);
+  sdivv_optab = init_optab (DIV);
   sdivmod_optab = init_optab (UNKNOWN);
   udiv_optab = init_optab (UDIV);
   udivmod_optab = init_optab (UNKNOWN);
@@ -4506,13 +4611,18 @@ init_optabs ()
   ucmp_optab = init_optab (UNKNOWN);
   tst_optab = init_optab (UNKNOWN);
   neg_optab = init_optab (NEG);
+  negv_optab = init_optab (NEG);
   abs_optab = init_optab (ABS);
+  absv_optab = init_optab (ABS);
   one_cmpl_optab = init_optab (NOT);
   ffs_optab = init_optab (FFS);
   sqrt_optab = init_optab (SQRT);
   sin_optab = init_optab (UNKNOWN);
   cos_optab = init_optab (UNKNOWN);
   strlen_optab = init_optab (UNKNOWN);
+  cbranch_optab = init_optab (UNKNOWN);
+  cmov_optab = init_optab (UNKNOWN);
+  cstore_optab = init_optab (UNKNOWN);
 
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
@@ -4535,18 +4645,21 @@ 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');
+  init_integral_libfuncs (addv_optab, "addv", '3');
+  init_floating_libfuncs (addv_optab, "add", '3');
   init_integral_libfuncs (sub_optab, "sub", '3');
   init_floating_libfuncs (sub_optab, "sub", '3');
+  init_integral_libfuncs (subv_optab, "subv", '3');
+  init_floating_libfuncs (subv_optab, "sub", '3');
   init_integral_libfuncs (smul_optab, "mul", '3');
   init_floating_libfuncs (smul_optab, "mul", '3');
+  init_integral_libfuncs (smulv_optab, "mulv", '3');
+  init_floating_libfuncs (smulv_optab, "mul", '3');
   init_integral_libfuncs (sdiv_optab, "div", '3');
+  init_integral_libfuncs (sdivv_optab, "divv", '3');
   init_integral_libfuncs (udiv_optab, "udiv", '3');
   init_integral_libfuncs (sdivmod_optab, "divmod", '4');
   init_integral_libfuncs (udivmod_optab, "udivmod", '4');
@@ -4568,6 +4681,8 @@ init_optabs ()
   init_integral_libfuncs (umax_optab, "umax", '3');
   init_integral_libfuncs (neg_optab, "neg", '2');
   init_floating_libfuncs (neg_optab, "neg", '2');
+  init_integral_libfuncs (negv_optab, "negv", '2');
+  init_floating_libfuncs (negv_optab, "neg", '2');
   init_integral_libfuncs (one_cmpl_optab, "one_cmpl", '2');
   init_integral_libfuncs (ffs_optab, "ffs", '2');
 
@@ -4578,189 +4693,191 @@ init_optabs ()
 
 #ifdef MULSI3_LIBCALL
   smul_optab->handlers[(int) SImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, MULSI3_LIBCALL);
+    = init_one_libfunc (MULSI3_LIBCALL);
 #endif
 #ifdef MULDI3_LIBCALL
   smul_optab->handlers[(int) DImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, MULDI3_LIBCALL);
+    = init_one_libfunc (MULDI3_LIBCALL);
 #endif
 
 #ifdef DIVSI3_LIBCALL
   sdiv_optab->handlers[(int) SImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, DIVSI3_LIBCALL);
+    = init_one_libfunc (DIVSI3_LIBCALL);
 #endif
 #ifdef DIVDI3_LIBCALL
   sdiv_optab->handlers[(int) DImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, DIVDI3_LIBCALL);
+    = init_one_libfunc (DIVDI3_LIBCALL);
 #endif
 
 #ifdef UDIVSI3_LIBCALL
   udiv_optab->handlers[(int) SImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, UDIVSI3_LIBCALL);
+    = init_one_libfunc (UDIVSI3_LIBCALL);
 #endif
 #ifdef UDIVDI3_LIBCALL
   udiv_optab->handlers[(int) DImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, UDIVDI3_LIBCALL);
+    = init_one_libfunc (UDIVDI3_LIBCALL);
 #endif
 
 #ifdef MODSI3_LIBCALL
   smod_optab->handlers[(int) SImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, MODSI3_LIBCALL);
+    = init_one_libfunc (MODSI3_LIBCALL);
 #endif
 #ifdef MODDI3_LIBCALL
   smod_optab->handlers[(int) DImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, MODDI3_LIBCALL);
+    = init_one_libfunc (MODDI3_LIBCALL);
 #endif
 
 #ifdef UMODSI3_LIBCALL
   umod_optab->handlers[(int) SImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, UMODSI3_LIBCALL);
+    = init_one_libfunc (UMODSI3_LIBCALL);
 #endif
 #ifdef UMODDI3_LIBCALL
   umod_optab->handlers[(int) DImode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, UMODDI3_LIBCALL);
+    = init_one_libfunc (UMODDI3_LIBCALL);
 #endif
 
   /* Use cabs for DC complex abs, since systems generally have cabs.
      Don't define any libcall for SCmode, so that cabs will be used.  */
   abs_optab->handlers[(int) DCmode].libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, "cabs");
+    = init_one_libfunc ("cabs");
 
   /* The ffs function operates on `int'.  */
-#ifndef INT_TYPE_SIZE
-#define INT_TYPE_SIZE BITS_PER_WORD
-#endif
-  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)] .libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, "ffs");
-
-  extendsfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfdf2");
-  extendsfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsfxf2");
-  extendsftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extendsftf2");
-  extenddfxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddfxf2");
-  extenddftf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__extenddftf2");
-
-  truncdfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncdfsf2");
-  truncxfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfsf2");
-  trunctfsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfsf2");
-  truncxfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__truncxfdf2");
-  trunctfdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__trunctfdf2");
-
-  memcpy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcpy");
-  bcopy_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bcopy");
-  memcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memcmp");
-  bcmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gcc_bcmp");
-  memset_libfunc = gen_rtx_SYMBOL_REF (Pmode, "memset");
-  bzero_libfunc = gen_rtx_SYMBOL_REF (Pmode, "bzero");
-
-  throw_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__throw");
-  rethrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__rethrow");
-  sjthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjthrow");
-  sjpopnthrow_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__sjpopnthrow");
-  terminate_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__terminate");
-  eh_rtime_match_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eh_rtime_match");
+  ffs_optab->handlers[(int) mode_for_size (INT_TYPE_SIZE, MODE_INT, 0)].libfunc
+    = init_one_libfunc ("ffs");
+
+  extendsfdf2_libfunc = init_one_libfunc ("__extendsfdf2");
+  extendsfxf2_libfunc = init_one_libfunc ("__extendsfxf2");
+  extendsftf2_libfunc = init_one_libfunc ("__extendsftf2");
+  extenddfxf2_libfunc = init_one_libfunc ("__extenddfxf2");
+  extenddftf2_libfunc = init_one_libfunc ("__extenddftf2");
+
+  truncdfsf2_libfunc = init_one_libfunc ("__truncdfsf2");
+  truncxfsf2_libfunc = init_one_libfunc ("__truncxfsf2");
+  trunctfsf2_libfunc = init_one_libfunc ("__trunctfsf2");
+  truncxfdf2_libfunc = init_one_libfunc ("__truncxfdf2");
+  trunctfdf2_libfunc = init_one_libfunc ("__trunctfdf2");
+
+  memcpy_libfunc = init_one_libfunc ("memcpy");
+  bcopy_libfunc = init_one_libfunc ("bcopy");
+  memcmp_libfunc = init_one_libfunc ("memcmp");
+  bcmp_libfunc = init_one_libfunc ("__gcc_bcmp");
+  memset_libfunc = init_one_libfunc ("memset");
+  bzero_libfunc = init_one_libfunc ("bzero");
+
+  throw_libfunc = init_one_libfunc ("__throw");
+  rethrow_libfunc = init_one_libfunc ("__rethrow");
+  sjthrow_libfunc = init_one_libfunc ("__sjthrow");
+  sjpopnthrow_libfunc = init_one_libfunc ("__sjpopnthrow");
+  terminate_libfunc = init_one_libfunc ("__terminate");
+  eh_rtime_match_libfunc = init_one_libfunc ("__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");
+  setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
+  longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
 #else
-  setjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "setjmp");
-  longjmp_libfunc = gen_rtx_SYMBOL_REF (Pmode, "longjmp");
+  setjmp_libfunc = init_one_libfunc ("setjmp");
+  longjmp_libfunc = init_one_libfunc ("longjmp");
 #endif
 
-  eqhf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqhf2");
-  nehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nehf2");
-  gthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gthf2");
-  gehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gehf2");
-  lthf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lthf2");
-  lehf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lehf2");
-
-  eqsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqsf2");
-  nesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nesf2");
-  gtsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtsf2");
-  gesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gesf2");
-  ltsf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltsf2");
-  lesf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lesf2");
-
-  eqdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqdf2");
-  nedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nedf2");
-  gtdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtdf2");
-  gedf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gedf2");
-  ltdf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltdf2");
-  ledf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ledf2");
-
-  eqxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqxf2");
-  nexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__nexf2");
-  gtxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gtxf2");
-  gexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gexf2");
-  ltxf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__ltxf2");
-  lexf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lexf2");
-
-  eqtf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__eqtf2");
-  netf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__netf2");
-  gttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__gttf2");
-  getf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__getf2");
-  lttf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__lttf2");
-  letf2_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__letf2");
-
-  floatsisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsisf");
-  floatdisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdisf");
-  floattisf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattisf");
-
-  floatsidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsidf");
-  floatdidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdidf");
-  floattidf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattidf");
-
-  floatsixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsixf");
-  floatdixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatdixf");
-  floattixf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattixf");
-
-  floatsitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatsitf");
-  floatditf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floatditf");
-  floattitf_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__floattitf");
-
-  fixsfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfsi");
-  fixsfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfdi");
-  fixsfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixsfti");
-
-  fixdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfsi");
-  fixdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfdi");
-  fixdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixdfti");
-
-  fixxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfsi");
-  fixxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfdi");
-  fixxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixxfti");
-
-  fixtfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfsi");
-  fixtfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfdi");
-  fixtfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixtfti");
-
-  fixunssfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfsi");
-  fixunssfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfdi");
-  fixunssfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunssfti");
-
-  fixunsdfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfsi");
-  fixunsdfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfdi");
-  fixunsdfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsdfti");
-
-  fixunsxfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfsi");
-  fixunsxfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfdi");
-  fixunsxfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunsxfti");
-
-  fixunstfsi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfsi");
-  fixunstfdi_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfdi");
-  fixunstfti_libfunc = gen_rtx_SYMBOL_REF (Pmode, "__fixunstfti");
+  eqhf2_libfunc = init_one_libfunc ("__eqhf2");
+  nehf2_libfunc = init_one_libfunc ("__nehf2");
+  gthf2_libfunc = init_one_libfunc ("__gthf2");
+  gehf2_libfunc = init_one_libfunc ("__gehf2");
+  lthf2_libfunc = init_one_libfunc ("__lthf2");
+  lehf2_libfunc = init_one_libfunc ("__lehf2");
+  unordhf2_libfunc = init_one_libfunc ("__unordhf2");
+
+  eqsf2_libfunc = init_one_libfunc ("__eqsf2");
+  nesf2_libfunc = init_one_libfunc ("__nesf2");
+  gtsf2_libfunc = init_one_libfunc ("__gtsf2");
+  gesf2_libfunc = init_one_libfunc ("__gesf2");
+  ltsf2_libfunc = init_one_libfunc ("__ltsf2");
+  lesf2_libfunc = init_one_libfunc ("__lesf2");
+  unordsf2_libfunc = init_one_libfunc ("__unordsf2");
+
+  eqdf2_libfunc = init_one_libfunc ("__eqdf2");
+  nedf2_libfunc = init_one_libfunc ("__nedf2");
+  gtdf2_libfunc = init_one_libfunc ("__gtdf2");
+  gedf2_libfunc = init_one_libfunc ("__gedf2");
+  ltdf2_libfunc = init_one_libfunc ("__ltdf2");
+  ledf2_libfunc = init_one_libfunc ("__ledf2");
+  unorddf2_libfunc = init_one_libfunc ("__unorddf2");
+
+  eqxf2_libfunc = init_one_libfunc ("__eqxf2");
+  nexf2_libfunc = init_one_libfunc ("__nexf2");
+  gtxf2_libfunc = init_one_libfunc ("__gtxf2");
+  gexf2_libfunc = init_one_libfunc ("__gexf2");
+  ltxf2_libfunc = init_one_libfunc ("__ltxf2");
+  lexf2_libfunc = init_one_libfunc ("__lexf2");
+  unordxf2_libfunc = init_one_libfunc ("__unordxf2");
+
+  eqtf2_libfunc = init_one_libfunc ("__eqtf2");
+  netf2_libfunc = init_one_libfunc ("__netf2");
+  gttf2_libfunc = init_one_libfunc ("__gttf2");
+  getf2_libfunc = init_one_libfunc ("__getf2");
+  lttf2_libfunc = init_one_libfunc ("__lttf2");
+  letf2_libfunc = init_one_libfunc ("__letf2");
+  unordtf2_libfunc = init_one_libfunc ("__unordtf2");
+
+  floatsisf_libfunc = init_one_libfunc ("__floatsisf");
+  floatdisf_libfunc = init_one_libfunc ("__floatdisf");
+  floattisf_libfunc = init_one_libfunc ("__floattisf");
+
+  floatsidf_libfunc = init_one_libfunc ("__floatsidf");
+  floatdidf_libfunc = init_one_libfunc ("__floatdidf");
+  floattidf_libfunc = init_one_libfunc ("__floattidf");
+
+  floatsixf_libfunc = init_one_libfunc ("__floatsixf");
+  floatdixf_libfunc = init_one_libfunc ("__floatdixf");
+  floattixf_libfunc = init_one_libfunc ("__floattixf");
+
+  floatsitf_libfunc = init_one_libfunc ("__floatsitf");
+  floatditf_libfunc = init_one_libfunc ("__floatditf");
+  floattitf_libfunc = init_one_libfunc ("__floattitf");
+
+  fixsfsi_libfunc = init_one_libfunc ("__fixsfsi");
+  fixsfdi_libfunc = init_one_libfunc ("__fixsfdi");
+  fixsfti_libfunc = init_one_libfunc ("__fixsfti");
+
+  fixdfsi_libfunc = init_one_libfunc ("__fixdfsi");
+  fixdfdi_libfunc = init_one_libfunc ("__fixdfdi");
+  fixdfti_libfunc = init_one_libfunc ("__fixdfti");
+
+  fixxfsi_libfunc = init_one_libfunc ("__fixxfsi");
+  fixxfdi_libfunc = init_one_libfunc ("__fixxfdi");
+  fixxfti_libfunc = init_one_libfunc ("__fixxfti");
+
+  fixtfsi_libfunc = init_one_libfunc ("__fixtfsi");
+  fixtfdi_libfunc = init_one_libfunc ("__fixtfdi");
+  fixtfti_libfunc = init_one_libfunc ("__fixtfti");
+
+  fixunssfsi_libfunc = init_one_libfunc ("__fixunssfsi");
+  fixunssfdi_libfunc = init_one_libfunc ("__fixunssfdi");
+  fixunssfti_libfunc = init_one_libfunc ("__fixunssfti");
+
+  fixunsdfsi_libfunc = init_one_libfunc ("__fixunsdfsi");
+  fixunsdfdi_libfunc = init_one_libfunc ("__fixunsdfdi");
+  fixunsdfti_libfunc = init_one_libfunc ("__fixunsdfti");
+
+  fixunsxfsi_libfunc = init_one_libfunc ("__fixunsxfsi");
+  fixunsxfdi_libfunc = init_one_libfunc ("__fixunsxfdi");
+  fixunsxfti_libfunc = init_one_libfunc ("__fixunsxfti");
+
+  fixunstfsi_libfunc = init_one_libfunc ("__fixunstfsi");
+  fixunstfdi_libfunc = init_one_libfunc ("__fixunstfdi");
+  fixunstfti_libfunc = init_one_libfunc ("__fixunstfti");
 
   /* For 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");
+  chkr_check_addr_libfunc = init_one_libfunc ("chkr_check_addr");
+  chkr_set_right_libfunc = init_one_libfunc ("chkr_set_right");
+  chkr_copy_bitmap_libfunc = init_one_libfunc ("chkr_copy_bitmap");
+  chkr_check_exec_libfunc = init_one_libfunc ("chkr_check_exec");
+  chkr_check_str_libfunc = init_one_libfunc ("chkr_check_str");
 
   /* For function entry/exit instrumentation.  */
   profile_function_entry_libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_enter");
+    = init_one_libfunc ("__cyg_profile_func_enter");
   profile_function_exit_libfunc
-    = gen_rtx_SYMBOL_REF (Pmode, "__cyg_profile_func_exit");
+    = init_one_libfunc ("__cyg_profile_func_exit");
 
 #ifdef HAVE_conditional_trap
   init_traps ();
@@ -4770,6 +4887,10 @@ init_optabs ()
   /* Allow the target to add more libcalls or rename some, etc.  */
   INIT_TARGET_OPTABS;
 #endif
+
+  /* Add these GC roots.  */
+  ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab);
+  ggc_add_rtx_root (libfunc_table, LTI_MAX);
 }
 \f
 #ifdef BROKEN_LDEXP
@@ -4793,16 +4914,17 @@ ldexp(x,n)
 /* 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.  */
+   ignored.  */
 static rtx trap_rtx;
 
 static void
 init_traps ()
 {
   if (HAVE_conditional_trap)
-    trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+    {
+      trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
+      ggc_add_rtx_root (&trap_rtx, 1);
+    }
 }
 #endif
 
@@ -4824,11 +4946,17 @@ gen_cond_trap (code, op1, op2, tcode)
       && cmp_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       rtx insn;
+      start_sequence();
       emit_insn (GEN_FCN (cmp_optab->handlers[(int) mode].insn_code) (op1, op2));
       PUT_CODE (trap_rtx, code);
       insn = gen_conditional_trap (trap_rtx, tcode);
       if (insn)
-       return insn;
+       {
+         emit_insn (insn);
+         insn = gen_sequence ();
+       }
+      end_sequence();
+      return insn;
     }
 #endif