OSDN Git Service

gcc/fortran/
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index abb6970..2955f7b 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand the basic unary and binary arithmetic operations, for GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -84,6 +84,12 @@ enum insn_code setcc_gen_code[NUM_RTX_CODE];
 enum insn_code movcc_gen_code[NUM_MACHINE_MODES];
 #endif
 
+/* Indexed by the machine mode, gives the insn code for vector conditional
+   operation.  */
+
+enum insn_code vcond_gen_code[NUM_MACHINE_MODES];
+enum insn_code vcondu_gen_code[NUM_MACHINE_MODES];
+
 /* 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.  */
@@ -116,10 +122,12 @@ static void prepare_float_lib_cmp (rtx *, rtx *, enum rtx_code *,
                                   enum machine_mode *, int *);
 static rtx widen_clz (enum machine_mode, rtx, rtx);
 static rtx expand_parity (enum machine_mode, rtx, rtx);
+static enum rtx_code get_rtx_code (enum tree_code, bool);
+static rtx vector_compare_rtx (tree, bool, enum insn_code);
 
 #ifndef HAVE_conditional_trap
 #define HAVE_conditional_trap 0
-#define gen_conditional_trap(a,b) (abort (), NULL_RTX)
+#define gen_conditional_trap(a,b) (gcc_unreachable (), NULL_RTX)
 #endif
 \f
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
@@ -138,10 +146,7 @@ add_equal_note (rtx insns, rtx target, enum rtx_code code, rtx op0, rtx op1)
   rtx last_insn, insn, set;
   rtx note;
 
-  if (! insns
-      || ! INSN_P (insns)
-      || NEXT_INSN (insns) == NULL_RTX)
-    abort ();
+  gcc_assert (insns && INSN_P (insns) && NEXT_INSN (insns));
 
   if (GET_RTX_CLASS (code) != RTX_COMM_ARITH
       && GET_RTX_CLASS (code) != RTX_BIN_ARITH
@@ -286,9 +291,6 @@ optab_for_tree_code (enum tree_code code, tree type)
     case MIN_EXPR:
       return TYPE_UNSIGNED (type) ? umin_optab : smin_optab;
 
-    case REALIGN_STORE_EXPR:
-      return vec_realign_store_optab;
-
     case REALIGN_LOAD_EXPR:
       return vec_realign_load_optab;
 
@@ -343,11 +345,10 @@ expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
   rtx pat;
   rtx xop0 = op0, xop1 = op1, xop2 = op2;
 
-  if (ternary_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
-    abort ();
+  gcc_assert (ternary_optab->handlers[(int) mode].insn_code
+             != CODE_FOR_nothing);
 
-  if (!target
-      || ! (*insn_data[icode].operand[0].predicate) (target, mode))
+  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
     temp = gen_reg_rtx (mode);
   else
     temp = target;
@@ -382,15 +383,15 @@ expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
   /* Now, if insn's predicates don't allow our operands, put them into
      pseudo regs.  */
   
-  if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
+  if (!insn_data[icode].operand[1].predicate (xop0, mode0)
       && mode0 != VOIDmode) 
     xop0 = copy_to_mode_reg (mode0, xop0);
   
-  if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
+  if (!insn_data[icode].operand[2].predicate (xop1, mode1)
       && mode1 != VOIDmode)
     xop1 = copy_to_mode_reg (mode1, xop1);
     
-  if (! (*insn_data[icode].operand[3].predicate) (xop2, mode2)
+  if (!insn_data[icode].operand[3].predicate (xop2, mode2)
       && mode2 != VOIDmode)
     xop2 = copy_to_mode_reg (mode2, xop2);
     
@@ -419,7 +420,7 @@ simplify_expand_binop (enum machine_mode mode, optab binoptab,
 /* Like simplify_expand_binop, but always put the result in TARGET.
    Return true if the expansion succeeded.  */
 
-static bool
+bool
 force_expand_binop (enum machine_mode mode, optab binoptab,
                    rtx op0, rtx op1, rtx target, int unsignedp,
                    enum optab_methods methods)
@@ -751,6 +752,168 @@ expand_doubleword_shift (enum machine_mode op1_mode, optab binoptab,
   return true;
 }
 \f
+/* Subroutine of expand_binop.  Perform a double word multiplication of
+   operands OP0 and OP1 both of mode MODE, which is exactly twice as wide
+   as the target's word_mode.  This function return NULL_RTX if anything
+   goes wrong, in which case it may have already emitted instructions
+   which need to be deleted.
+
+   If we want to multiply two two-word values and have normal and widening
+   multiplies of single-word values, we can do this with three smaller
+   multiplications.  Note that we do not make a REG_NO_CONFLICT block here
+   because we are not operating on one word at a time.
+
+   The multiplication proceeds as follows:
+                                _______________________
+                               [__op0_high_|__op0_low__]
+                                _______________________
+        *                      [__op1_high_|__op1_low__]
+        _______________________________________________
+                                _______________________
+    (1)                                [__op0_low__*__op1_low__]
+                    _______________________
+    (2a)           [__op0_low__*__op1_high_]
+                    _______________________
+    (2b)           [__op0_high_*__op1_low__]
+         _______________________
+    (3) [__op0_high_*__op1_high_]
+
+
+  This gives a 4-word result.  Since we are only interested in the
+  lower 2 words, partial result (3) and the upper words of (2a) and
+  (2b) don't need to be calculated.  Hence (2a) and (2b) can be
+  calculated using non-widening multiplication.
+
+  (1), however, needs to be calculated with an unsigned widening
+  multiplication.  If this operation is not directly supported we
+  try using a signed widening multiplication and adjust the result.
+  This adjustment works as follows:
+
+      If both operands are positive then no adjustment is needed.
+
+      If the operands have different signs, for example op0_low < 0 and
+      op1_low >= 0, the instruction treats the most significant bit of
+      op0_low as a sign bit instead of a bit with significance
+      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
+      with 2**BITS_PER_WORD - op0_low, and two's complements the
+      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
+      the result.
+
+      Similarly, if both operands are negative, we need to add
+      (op0_low + op1_low) * 2**BITS_PER_WORD.
+
+      We use a trick to adjust quickly.  We logically shift op0_low right
+      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
+      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
+      logical shift exists, we do an arithmetic right shift and subtract
+      the 0 or -1.  */
+
+static rtx
+expand_doubleword_mult (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+                      bool umulp, enum optab_methods methods)
+{
+  int low = (WORDS_BIG_ENDIAN ? 1 : 0);
+  int high = (WORDS_BIG_ENDIAN ? 0 : 1);
+  rtx wordm1 = umulp ? NULL_RTX : GEN_INT (BITS_PER_WORD - 1);
+  rtx product, adjust, product_high, temp;
+
+  rtx op0_high = operand_subword_force (op0, high, mode);
+  rtx op0_low = operand_subword_force (op0, low, mode);
+  rtx op1_high = operand_subword_force (op1, high, mode);
+  rtx op1_low = operand_subword_force (op1, low, mode);
+
+  /* If we're using an unsigned multiply to directly compute the product
+     of the low-order words of the operands and perform any required
+     adjustments of the operands, we begin by trying two more multiplications
+     and then computing the appropriate sum.
+
+     We have checked above that the required addition is provided.
+     Full-word addition will normally always succeed, especially if
+     it is provided at all, so we don't worry about its failure.  The
+     multiplication may well fail, however, so we do handle that.  */
+
+  if (!umulp)
+    {
+      /* ??? This could be done with emit_store_flag where available.  */
+      temp = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
+                          NULL_RTX, 1, methods);
+      if (temp)
+       op0_high = expand_binop (word_mode, add_optab, op0_high, temp,
+                                NULL_RTX, 0, OPTAB_DIRECT);
+      else
+       {
+         temp = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
+                              NULL_RTX, 0, methods);
+         if (!temp)
+           return NULL_RTX;
+         op0_high = expand_binop (word_mode, sub_optab, op0_high, temp,
+                                  NULL_RTX, 0, OPTAB_DIRECT);
+       }
+
+      if (!op0_high)
+       return NULL_RTX;
+    }
+
+  adjust = expand_binop (word_mode, smul_optab, op0_high, op1_low,
+                        NULL_RTX, 0, OPTAB_DIRECT);
+  if (!adjust)
+    return NULL_RTX;
+
+  /* OP0_HIGH should now be dead.  */
+
+  if (!umulp)
+    {
+      /* ??? This could be done with emit_store_flag where available.  */
+      temp = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
+                          NULL_RTX, 1, methods);
+      if (temp)
+       op1_high = expand_binop (word_mode, add_optab, op1_high, temp,
+                                NULL_RTX, 0, OPTAB_DIRECT);
+      else
+       {
+         temp = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
+                              NULL_RTX, 0, methods);
+         if (!temp)
+           return NULL_RTX;
+         op1_high = expand_binop (word_mode, sub_optab, op1_high, temp,
+                                  NULL_RTX, 0, OPTAB_DIRECT);
+       }
+
+      if (!op1_high)
+       return NULL_RTX;
+    }
+
+  temp = expand_binop (word_mode, smul_optab, op1_high, op0_low,
+                      NULL_RTX, 0, OPTAB_DIRECT);
+  if (!temp)
+    return NULL_RTX;
+
+  /* OP1_HIGH should now be dead.  */
+
+  adjust = expand_binop (word_mode, add_optab, adjust, temp,
+                        adjust, 0, OPTAB_DIRECT);
+
+  if (target && !REG_P (target))
+    target = NULL_RTX;
+
+  if (umulp)
+    product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
+                           target, 1, OPTAB_DIRECT);
+  else
+    product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
+                           target, 1, OPTAB_DIRECT);
+
+  if (!product)
+    return NULL_RTX;
+
+  product_high = operand_subword (product, high, 1, mode);
+  adjust = expand_binop (word_mode, add_optab, product_high, adjust,
+                        REG_P (product_high) ? product_high : adjust,
+                        0, OPTAB_DIRECT);
+  emit_move_insn (product_high, adjust);
+  return product;
+}
+\f
 /* Wrapper around expand_binop which takes an rtx code to specify
    the operation to perform, not an optab pointer.  All other
    arguments are the same.  */
@@ -760,8 +923,7 @@ expand_simple_binop (enum machine_mode mode, enum rtx_code code, rtx op0,
                     enum optab_methods methods)
 {
   optab binop = code_to_optab[(int) code];
-  if (binop == 0)
-    abort ();
+  gcc_assert (binop);
 
   return expand_binop (mode, binop, op0, op1, target, unsignedp, methods);
 }
@@ -826,11 +988,19 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
      force expensive constants into a register.  */
   if (CONSTANT_P (op0) && optimize
       && rtx_cost (op0, binoptab->code) > COSTS_N_INSNS (1))
-    op0 = force_reg (mode, op0);
+    {
+      if (GET_MODE (op0) != VOIDmode)
+       op0 = convert_modes (mode, VOIDmode, op0, unsignedp);
+      op0 = force_reg (mode, op0);
+    }
 
   if (CONSTANT_P (op1) && optimize
       && ! shift_op && rtx_cost (op1, binoptab->code) > COSTS_N_INSNS (1))
-    op1 = force_reg (mode, op1);
+    {
+      if (GET_MODE (op1) != VOIDmode)
+       op1 = convert_modes (mode, VOIDmode, op1, unsignedp);
+      op1 = force_reg (mode, op1);
+    }
 
   /* Record where to delete back to if we backtrack.  */
   last = get_last_insn ();
@@ -913,15 +1083,15 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
       /* Now, if insn's predicates don't allow our operands, put them into
         pseudo regs.  */
 
-      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0)
+      if (!insn_data[icode].operand[1].predicate (xop0, mode0)
          && mode0 != VOIDmode)
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_data[icode].operand[2].predicate) (xop1, mode1)
+      if (!insn_data[icode].operand[2].predicate (xop1, mode1)
          && mode1 != VOIDmode)
        xop1 = copy_to_mode_reg (mode1, xop1);
 
-      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
+      if (!insn_data[icode].operand[0].predicate (temp, mode))
        temp = gen_reg_rtx (mode);
 
       pat = GEN_FCN (icode) (temp, xop0, xop1);
@@ -1359,6 +1529,11 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                }
              emit_move_insn (target_piece, newx);
            }
+         else
+           {
+             if (x != target_piece)
+               emit_move_insn (target_piece, x);
+           }
 
          carry_in = carry_out;
        }
@@ -1386,197 +1561,51 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        delete_insns_since (last);
     }
 
-  /* If we want to multiply two two-word values and have normal and widening
-     multiplies of single-word values, we can do this with three smaller
-     multiplications.  Note that we do not make a REG_NO_CONFLICT block here
-     because we are not operating on one word at a time.
-
-     The multiplication proceeds as follows:
-                                _______________________
-                               [__op0_high_|__op0_low__]
-                                _______________________
-        *                      [__op1_high_|__op1_low__]
-        _______________________________________________
-                                _______________________
-    (1)                                [__op0_low__*__op1_low__]
-                    _______________________
-    (2a)           [__op0_low__*__op1_high_]
-                    _______________________
-    (2b)           [__op0_high_*__op1_low__]
-         _______________________
-    (3) [__op0_high_*__op1_high_]
-
-
-    This gives a 4-word result.  Since we are only interested in the
-    lower 2 words, partial result (3) and the upper words of (2a) and
-    (2b) don't need to be calculated.  Hence (2a) and (2b) can be
-    calculated using non-widening multiplication.
-
-    (1), however, needs to be calculated with an unsigned widening
-    multiplication.  If this operation is not directly supported we
-    try using a signed widening multiplication and adjust the result.
-    This adjustment works as follows:
-
-      If both operands are positive then no adjustment is needed.
-
-      If the operands have different signs, for example op0_low < 0 and
-      op1_low >= 0, the instruction treats the most significant bit of
-      op0_low as a sign bit instead of a bit with significance
-      2**(BITS_PER_WORD-1), i.e. the instruction multiplies op1_low
-      with 2**BITS_PER_WORD - op0_low, and two's complements the
-      result.  Conclusion: We need to add op1_low * 2**BITS_PER_WORD to
-      the result.
-
-      Similarly, if both operands are negative, we need to add
-      (op0_low + op1_low) * 2**BITS_PER_WORD.
-
-      We use a trick to adjust quickly.  We logically shift op0_low right
-      (op1_low) BITS_PER_WORD-1 steps to get 0 or 1, and add this to
-      op0_high (op1_high) before it is used to calculate 2b (2a).  If no
-      logical shift exists, we do an arithmetic right shift and subtract
-      the 0 or -1.  */
+  /* Attempt to synthesize double word multiplies using a sequence of word
+     mode multiplications.  We first attempt to generate a sequence using a
+     more efficient unsigned widening multiply, and if that fails we then
+     try using a signed widening multiply.  */
 
   if (binoptab == smul_optab
       && class == MODE_INT
       && GET_MODE_SIZE (mode) == 2 * UNITS_PER_WORD
       && smul_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
-      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing
-      && ((umul_widen_optab->handlers[(int) mode].insn_code
-          != CODE_FOR_nothing)
-         || (smul_widen_optab->handlers[(int) mode].insn_code
-             != CODE_FOR_nothing)))
+      && add_optab->handlers[(int) word_mode].insn_code != CODE_FOR_nothing)
     {
-      int low = (WORDS_BIG_ENDIAN ? 1 : 0);
-      int high = (WORDS_BIG_ENDIAN ? 0 : 1);
-      rtx op0_high = operand_subword_force (op0, high, mode);
-      rtx op0_low = operand_subword_force (op0, low, mode);
-      rtx op1_high = operand_subword_force (op1, high, mode);
-      rtx op1_low = operand_subword_force (op1, low, mode);
-      rtx product = 0;
-      rtx op0_xhigh = NULL_RTX;
-      rtx op1_xhigh = NULL_RTX;
-
-      /* If the target is the same as one of the inputs, don't use it.  This
-        prevents problems with the REG_EQUAL note.  */
-      if (target == op0 || target == op1
-         || (target != 0 && !REG_P (target)))
-       target = 0;
-
-      /* Multiply the two lower words to get a double-word product.
-        If unsigned widening multiplication is available, use that;
-        otherwise use the signed form and compensate.  */
-
-      if (umul_widen_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-       {
-         product = expand_binop (mode, umul_widen_optab, op0_low, op1_low,
-                                 target, 1, OPTAB_DIRECT);
+      rtx product = NULL_RTX;
 
-         /* If we didn't succeed, delete everything we did so far.  */
-         if (product == 0)
+      if (umul_widen_optab->handlers[(int) mode].insn_code
+         != CODE_FOR_nothing)
+       {
+         product = expand_doubleword_mult (mode, op0, op1, target,
+                                           true, methods);
+         if (!product)
            delete_insns_since (last);
-         else
-           op0_xhigh = op0_high, op1_xhigh = op1_high;
        }
 
-      if (product == 0
+      if (product == NULL_RTX
          && smul_widen_optab->handlers[(int) mode].insn_code
-              != CODE_FOR_nothing)
+            != CODE_FOR_nothing)
        {
-         rtx wordm1 = GEN_INT (BITS_PER_WORD - 1);
-         product = expand_binop (mode, smul_widen_optab, op0_low, op1_low,
-                                 target, 1, OPTAB_DIRECT);
-         op0_xhigh = expand_binop (word_mode, lshr_optab, op0_low, wordm1,
-                                   NULL_RTX, 1, next_methods);
-         if (op0_xhigh)
-           op0_xhigh = expand_binop (word_mode, add_optab, op0_high,
-                                     op0_xhigh, op0_xhigh, 0, next_methods);
-         else
-           {
-             op0_xhigh = expand_binop (word_mode, ashr_optab, op0_low, wordm1,
-                                       NULL_RTX, 0, next_methods);
-             if (op0_xhigh)
-               op0_xhigh = expand_binop (word_mode, sub_optab, op0_high,
-                                         op0_xhigh, op0_xhigh, 0,
-                                         next_methods);
-           }
-
-         op1_xhigh = expand_binop (word_mode, lshr_optab, op1_low, wordm1,
-                                   NULL_RTX, 1, next_methods);
-         if (op1_xhigh)
-           op1_xhigh = expand_binop (word_mode, add_optab, op1_high,
-                                     op1_xhigh, op1_xhigh, 0, next_methods);
-         else
-           {
-             op1_xhigh = expand_binop (word_mode, ashr_optab, op1_low, wordm1,
-                                       NULL_RTX, 0, next_methods);
-             if (op1_xhigh)
-               op1_xhigh = expand_binop (word_mode, sub_optab, op1_high,
-                                         op1_xhigh, op1_xhigh, 0,
-                                         next_methods);
-           }
+         product = expand_doubleword_mult (mode, op0, op1, target,
+                                           false, methods);
+         if (!product)
+           delete_insns_since (last);
        }
 
-      /* If we have been able to directly compute the product of the
-        low-order words of the operands and perform any required adjustments
-        of the operands, we proceed by trying two more multiplications
-        and then computing the appropriate sum.
-
-        We have checked above that the required addition is provided.
-        Full-word addition will normally always succeed, especially if
-        it is provided at all, so we don't worry about its failure.  The
-        multiplication may well fail, however, so we do handle that.  */
-
-      if (product && op0_xhigh && op1_xhigh)
+      if (product != NULL_RTX)
        {
-         rtx product_high = operand_subword (product, high, 1, mode);
-         rtx temp = expand_binop (word_mode, binoptab, op0_low, op1_xhigh,
-                                  NULL_RTX, 0, OPTAB_DIRECT);
-
-         if (!REG_P (product_high))
-           product_high = force_reg (word_mode, product_high);
-
-         if (temp != 0)
-           temp = expand_binop (word_mode, add_optab, temp, product_high,
-                                product_high, 0, next_methods);
-
-         if (temp != 0 && temp != product_high)
-           emit_move_insn (product_high, temp);
-
-         if (temp != 0)
-           temp = expand_binop (word_mode, binoptab, op1_low, op0_xhigh,
-                                NULL_RTX, 0, OPTAB_DIRECT);
-
-         if (temp != 0)
-           temp = expand_binop (word_mode, add_optab, temp,
-                                product_high, product_high,
-                                0, next_methods);
-
-         if (temp != 0 && temp != product_high)
-           emit_move_insn (product_high, temp);
-
-         emit_move_insn (operand_subword (product, high, 1, mode), product_high);
-
-         if (temp != 0)
+         if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
            {
-             if (mov_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
-               {
-                 temp = emit_move_insn (product, product);
-                 set_unique_reg_note (temp,
-                                      REG_EQUAL,
-                                      gen_rtx_fmt_ee (MULT, mode,
-                                                      copy_rtx (op0),
-                                                      copy_rtx (op1)));
-               }
-
-             return product;
+             temp = emit_move_insn (target ? target : product, product);
+             set_unique_reg_note (temp,
+                                  REG_EQUAL,
+                                  gen_rtx_fmt_ee (MULT, mode,
+                                                  copy_rtx (op0),
+                                                  copy_rtx (op1)));
            }
+         return product;
        }
-
-      /* If we get here, we couldn't do it for some reason even though we
-        originally thought we could.  Delete anything we've emitted in
-        trying to do it.  */
-
-      delete_insns_since (last);
     }
 
   /* It can't be open-coded in this mode.
@@ -1795,14 +1824,13 @@ expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
        xop0 = convert_to_mode (mode0, xop0, unsignedp);
 
       /* Now, if insn doesn't accept these operands, put them into pseudos.  */
-      if (! (*insn_data[icode].operand[2].predicate) (xop0, mode0))
+      if (!insn_data[icode].operand[2].predicate (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
       /* 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_data[icode].operand[0].predicate) (targ0, mode)
-         || ! (*insn_data[icode].operand[1].predicate) (targ1, mode))
-       abort ();
+      gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode));
+      gcc_assert (insn_data[icode].operand[1].predicate (targ1, mode));
 
       pat = GEN_FCN (icode) (targ0, targ1, xop0);
       if (pat)
@@ -1921,17 +1949,16 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
                              xop1, unsignedp);
 
       /* Now, if insn doesn't accept these operands, put them into pseudos.  */
-      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
+      if (!insn_data[icode].operand[1].predicate (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_data[icode].operand[2].predicate) (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_data[icode].operand[0].predicate) (targ0, mode)
-         || ! (*insn_data[icode].operand[3].predicate) (targ1, mode))
-       abort ();
+      gcc_assert (insn_data[icode].operand[0].predicate (targ0, mode));
+      gcc_assert (insn_data[icode].operand[3].predicate (targ1, mode));
 
       pat = GEN_FCN (icode) (targ0, xop0, xop1, targ1);
       if (pat)
@@ -1994,8 +2021,7 @@ expand_twoval_binop_libfunc (optab binoptab, rtx op0, rtx op1,
   rtx insns;
 
   /* Exactly one of TARG0 or TARG1 should be non-NULL.  */
-  if (!((targ0 != NULL_RTX) ^ (targ1 != NULL_RTX)))
-    abort ();
+  gcc_assert (!targ0 != !targ1);
 
   mode = GET_MODE (op0);
   if (!binoptab->handlers[(int) mode].libfunc)
@@ -2032,8 +2058,7 @@ expand_simple_unop (enum machine_mode mode, enum rtx_code code, rtx op0,
                    rtx target, int unsignedp)
 {
   optab unop = code_to_optab[(int) code];
-  if (unop == 0)
-    abort ();
+  gcc_assert (unop);
 
   return expand_unop (mode, unop, op0, target, unsignedp);
 }
@@ -2115,6 +2140,131 @@ expand_parity (enum machine_mode mode, rtx op0, rtx target)
   return 0;
 }
 
+/* Extract the OMODE lowpart from VAL, which has IMODE.  Under certain 
+   conditions, VAL may already be a SUBREG against which we cannot generate
+   a further SUBREG.  In this case, we expect forcing the value into a
+   register will work around the situation.  */
+
+static rtx
+lowpart_subreg_maybe_copy (enum machine_mode omode, rtx val,
+                          enum machine_mode imode)
+{
+  rtx ret;
+  ret = lowpart_subreg (omode, val, imode);
+  if (ret == NULL)
+    {
+      val = force_reg (imode, val);
+      ret = lowpart_subreg (omode, val, imode);
+      gcc_assert (ret != NULL);
+    }
+  return ret;
+}
+
+/* Expand a floating point absolute value or negation operation via a
+   logical operation on the sign bit.  */
+
+static rtx
+expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
+                  rtx op0, rtx target)
+{
+  const struct real_format *fmt;
+  int bitpos, word, nwords, i;
+  enum machine_mode imode;
+  HOST_WIDE_INT hi, lo;
+  rtx temp, insns;
+
+  /* The format has to have a simple sign bit.  */
+  fmt = REAL_MODE_FORMAT (mode);
+  if (fmt == NULL)
+    return NULL_RTX;
+
+  bitpos = fmt->signbit_rw;
+  if (bitpos < 0)
+    return NULL_RTX;
+
+  /* Don't create negative zeros if the format doesn't support them.  */
+  if (code == NEG && !fmt->has_signed_zero)
+    return NULL_RTX;
+
+  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+    {
+      imode = int_mode_for_mode (mode);
+      if (imode == BLKmode)
+       return NULL_RTX;
+      word = 0;
+      nwords = 1;
+    }
+  else
+    {
+      imode = word_mode;
+
+      if (FLOAT_WORDS_BIG_ENDIAN)
+       word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
+      else
+       word = bitpos / BITS_PER_WORD;
+      bitpos = bitpos % BITS_PER_WORD;
+      nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
+    }
+
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
+    {
+      hi = 0;
+      lo = (HOST_WIDE_INT) 1 << bitpos;
+    }
+  else
+    {
+      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+      lo = 0;
+    }
+  if (code == ABS)
+    lo = ~lo, hi = ~hi;
+
+  if (target == 0 || target == op0)
+    target = gen_reg_rtx (mode);
+
+  if (nwords > 1)
+    {
+      start_sequence ();
+
+      for (i = 0; i < nwords; ++i)
+       {
+         rtx targ_piece = operand_subword (target, i, 1, mode);
+         rtx op0_piece = operand_subword_force (op0, i, mode);
+       
+         if (i == word)
+           {
+             temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
+                                  op0_piece,
+                                  immed_double_const (lo, hi, imode),
+                                  targ_piece, 1, OPTAB_LIB_WIDEN);
+             if (temp != targ_piece)
+               emit_move_insn (targ_piece, temp);
+           }
+         else
+           emit_move_insn (targ_piece, op0_piece);
+       }
+
+      insns = get_insns ();
+      end_sequence ();
+
+      temp = gen_rtx_fmt_e (code, mode, copy_rtx (op0));
+      emit_no_conflict_block (insns, target, op0, NULL_RTX, temp);
+    }
+  else
+    {
+      temp = expand_binop (imode, code == ABS ? and_optab : xor_optab,
+                          gen_lowpart (imode, op0),
+                          immed_double_const (lo, hi, imode),
+                          gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
+      target = lowpart_subreg_maybe_copy (mode, temp, imode);
+
+      set_unique_reg_note (get_last_insn (), REG_EQUAL,
+                          gen_rtx_fmt_e (code, mode, copy_rtx (op0)));
+    }
+
+  return target;
+}
+
 /* Generate code to perform an operation specified by UNOPTAB
    on operand OP0, with result having machine-mode MODE.
 
@@ -2158,10 +2308,10 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
 
       /* Now, if insn doesn't accept our operand, put it into a pseudo.  */
 
-      if (! (*insn_data[icode].operand[1].predicate) (xop0, mode0))
+      if (!insn_data[icode].operand[1].predicate (xop0, mode0))
        xop0 = copy_to_mode_reg (mode0, xop0);
 
-      if (! (*insn_data[icode].operand[0].predicate) (temp, mode))
+      if (!insn_data[icode].operand[0].predicate (temp, mode))
        temp = gen_reg_rtx (mode);
 
       pat = GEN_FCN (icode) (temp, xop0);
@@ -2266,54 +2416,27 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
       return target;
     }
 
-  /* Try negating floating point values by flipping the sign bit.  */
-  if (unoptab->code == NEG && class == MODE_FLOAT
-      && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+  if (unoptab->code == NEG)
     {
-      const struct real_format *fmt = REAL_MODE_FORMAT (mode);
-      enum machine_mode imode = int_mode_for_mode (mode);
-      int bitpos = (fmt != 0) ? fmt->signbit : -1;
-
-      if (imode != BLKmode && bitpos >= 0 && fmt->has_signed_zero)
+      /* Try negating floating point values by flipping the sign bit.  */
+      if (class == MODE_FLOAT)
        {
-         HOST_WIDE_INT hi, lo;
-         rtx last = get_last_insn ();
-
-         /* Handle targets with different FP word orders.  */
-         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
-           {
-             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
-             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
-             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
-           }
+         temp = expand_absneg_bit (NEG, mode, op0, target);
+         if (temp)
+           return temp;
+       }
 
-         if (bitpos < HOST_BITS_PER_WIDE_INT)
-           {
-             hi = 0;
-             lo = (HOST_WIDE_INT) 1 << bitpos;
-           }
-         else
-           {
-             hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
-             lo = 0;
-           }
-         temp = expand_binop (imode, xor_optab,
-                              gen_lowpart (imode, op0),
-                              immed_double_const (lo, hi, imode),
-                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
-         if (temp != 0)
-           {
-             rtx insn;
-             if (target == 0)
-               target = gen_reg_rtx (mode);
-             insn = emit_move_insn (target, gen_lowpart (mode, temp));
-             set_unique_reg_note (insn, REG_EQUAL,
-                                  gen_rtx_fmt_e (NEG, mode,
-                                                 copy_rtx (op0)));
-             return target;
-           }
-         delete_insns_since (last);
-        }
+      /* If there is no negation pattern, and we have no negative zero,
+        try subtracting from zero.  */
+      if (!HONOR_SIGNED_ZEROS (mode))
+       {
+         temp = expand_binop (mode, (unoptab == negv_optab
+                                     ? subv_optab : sub_optab),
+                              CONST0_RTX (mode), op0, target,
+                              unsignedp, OPTAB_DIRECT);
+         if (temp)
+           return temp;
+       }
     }
 
   /* Try calculating parity (x) as popcount (x) % 2.  */
@@ -2324,15 +2447,6 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
        return temp;
     }
 
-  /* If there is no negation pattern, try subtracting from zero.  */
-  if (unoptab == neg_optab && class == MODE_INT)
-    {
-      temp = expand_binop (mode, sub_optab, CONST0_RTX (mode), op0,
-                           target, unsignedp, OPTAB_DIRECT);
-      if (temp)
-       return temp;
-    }
-
  try_libcall:
   /* Now try a library call in this mode.  */
   if (unoptab->handlers[(int) mode].libfunc)
@@ -2416,10 +2530,9 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
        }
     }
 
-  /* If there is no negate operation, try doing a subtract from zero.
-     The US Software GOFAST library needs this.  FIXME: This is *wrong*
-     for floating-point operations due to negative zeros!  */
-  if (unoptab->code == NEG)
+  /* One final attempt at implementing negation via subtraction,
+     this time allowing widening of the operand.  */
+  if (unoptab->code == NEG && !HONOR_SIGNED_ZEROS (mode))
     {
       rtx temp;
       temp = expand_binop (mode,
@@ -2427,7 +2540,7 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
                            CONST0_RTX (mode), op0,
                            target, unsignedp, OPTAB_LIB_WIDEN);
       if (temp)
-       return temp;
+        return temp;
     }
 
   return 0;
@@ -2458,57 +2571,16 @@ expand_abs_nojump (enum machine_mode mode, rtx op0, rtx target,
     return temp;
 
   /* For floating point modes, try clearing the sign bit.  */
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_MODE_BITSIZE (mode) <= 2 * HOST_BITS_PER_WIDE_INT)
+  if (GET_MODE_CLASS (mode) == MODE_FLOAT)
     {
-      const struct real_format *fmt = REAL_MODE_FORMAT (mode);
-      enum machine_mode imode = int_mode_for_mode (mode);
-      int bitpos = (fmt != 0) ? fmt->signbit : -1;
-
-      if (imode != BLKmode && bitpos >= 0)
-       {
-         HOST_WIDE_INT hi, lo;
-         rtx last = get_last_insn ();
-
-         /* Handle targets with different FP word orders.  */
-         if (FLOAT_WORDS_BIG_ENDIAN != WORDS_BIG_ENDIAN)
-           {
-             int nwords = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
-             int word = nwords - (bitpos / BITS_PER_WORD) - 1;
-             bitpos = word * BITS_PER_WORD + bitpos % BITS_PER_WORD;
-           }
-
-         if (bitpos < HOST_BITS_PER_WIDE_INT)
-           {
-             hi = 0;
-             lo = (HOST_WIDE_INT) 1 << bitpos;
-           }
-         else
-           {
-             hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
-             lo = 0;
-           }
-         temp = expand_binop (imode, and_optab,
-                              gen_lowpart (imode, op0),
-                              immed_double_const (~lo, ~hi, imode),
-                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
-         if (temp != 0)
-           {
-             rtx insn;
-             if (target == 0)
-               target = gen_reg_rtx (mode);
-             insn = emit_move_insn (target, gen_lowpart (mode, temp));
-             set_unique_reg_note (insn, REG_EQUAL,
-                                  gen_rtx_fmt_e (ABS, mode,
-                                                 copy_rtx (op0)));
-             return target;
-           }
-         delete_insns_since (last);
-       }
+      temp = expand_absneg_bit (ABS, mode, op0, target);
+      if (temp)
+       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)
+  if (smax_optab->handlers[(int) mode].insn_code != CODE_FOR_nothing
+      && !HONOR_SIGNED_ZEROS (mode))
     {
       rtx last = get_last_insn ();
 
@@ -2596,8 +2668,241 @@ expand_abs (enum machine_mode mode, rtx op0, rtx target,
   OK_DEFER_POP;
   return target;
 }
-\f
-/* Generate an instruction whose insn-code is INSN_CODE,
+
+/* A subroutine of expand_copysign, perform the copysign operation using the
+   abs and neg primitives advertised to exist on the target.  The assumption
+   is that we have a split register file, and leaving op0 in fp registers,
+   and not playing with subregs so much, will help the register allocator.  */
+
+static rtx
+expand_copysign_absneg (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+                       int bitpos, bool op0_is_abs)
+{
+  enum machine_mode imode;
+  HOST_WIDE_INT hi, lo;
+  int word;
+  rtx label;
+
+  if (target == op1)
+    target = NULL_RTX;
+
+  if (!op0_is_abs)
+    {
+      op0 = expand_unop (mode, abs_optab, op0, target, 0);
+      if (op0 == NULL)
+       return NULL_RTX;
+      target = op0;
+    }
+  else
+    {
+      if (target == NULL_RTX)
+        target = copy_to_reg (op0);
+      else
+       emit_move_insn (target, op0);
+    }
+
+  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+    {
+      imode = int_mode_for_mode (mode);
+      if (imode == BLKmode)
+       return NULL_RTX;
+      op1 = gen_lowpart (imode, op1);
+    }
+  else
+    {
+      imode = word_mode;
+      if (FLOAT_WORDS_BIG_ENDIAN)
+       word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
+      else
+       word = bitpos / BITS_PER_WORD;
+      bitpos = bitpos % BITS_PER_WORD;
+      op1 = operand_subword_force (op1, word, mode);
+    }
+
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
+    {
+      hi = 0;
+      lo = (HOST_WIDE_INT) 1 << bitpos;
+    }
+  else
+    {
+      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+      lo = 0;
+    }
+
+  op1 = expand_binop (imode, and_optab, op1,
+                     immed_double_const (lo, hi, imode),
+                     NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+  label = gen_label_rtx ();
+  emit_cmp_and_jump_insns (op1, const0_rtx, EQ, NULL_RTX, imode, 1, label);
+
+  if (GET_CODE (op0) == CONST_DOUBLE)
+    op0 = simplify_unary_operation (NEG, mode, op0, mode);
+  else
+    op0 = expand_unop (mode, neg_optab, op0, target, 0);
+  if (op0 != target)
+    emit_move_insn (target, op0);
+
+  emit_label (label);
+
+  return target;
+}
+
+
+/* A subroutine of expand_copysign, perform the entire copysign operation
+   with integer bitmasks.  BITPOS is the position of the sign bit; OP0_IS_ABS
+   is true if op0 is known to have its sign bit clear.  */
+
+static rtx
+expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
+                    int bitpos, bool op0_is_abs)
+{
+  enum machine_mode imode;
+  HOST_WIDE_INT hi, lo;
+  int word, nwords, i;
+  rtx temp, insns;
+
+  if (GET_MODE_SIZE (mode) <= UNITS_PER_WORD)
+    {
+      imode = int_mode_for_mode (mode);
+      if (imode == BLKmode)
+       return NULL_RTX;
+      word = 0;
+      nwords = 1;
+    }
+  else
+    {
+      imode = word_mode;
+
+      if (FLOAT_WORDS_BIG_ENDIAN)
+       word = (GET_MODE_BITSIZE (mode) - bitpos) / BITS_PER_WORD;
+      else
+       word = bitpos / BITS_PER_WORD;
+      bitpos = bitpos % BITS_PER_WORD;
+      nwords = (GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD;
+    }
+
+  if (bitpos < HOST_BITS_PER_WIDE_INT)
+    {
+      hi = 0;
+      lo = (HOST_WIDE_INT) 1 << bitpos;
+    }
+  else
+    {
+      hi = (HOST_WIDE_INT) 1 << (bitpos - HOST_BITS_PER_WIDE_INT);
+      lo = 0;
+    }
+
+  if (target == 0 || target == op0 || target == op1)
+    target = gen_reg_rtx (mode);
+
+  if (nwords > 1)
+    {
+      start_sequence ();
+
+      for (i = 0; i < nwords; ++i)
+       {
+         rtx targ_piece = operand_subword (target, i, 1, mode);
+         rtx op0_piece = operand_subword_force (op0, i, mode);
+       
+         if (i == word)
+           {
+             if (!op0_is_abs)
+               op0_piece = expand_binop (imode, and_optab, op0_piece,
+                                         immed_double_const (~lo, ~hi, imode),
+                                         NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+             op1 = expand_binop (imode, and_optab,
+                                 operand_subword_force (op1, i, mode),
+                                 immed_double_const (lo, hi, imode),
+                                 NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+             temp = expand_binop (imode, ior_optab, op0_piece, op1,
+                                  targ_piece, 1, OPTAB_LIB_WIDEN);
+             if (temp != targ_piece)
+               emit_move_insn (targ_piece, temp);
+           }
+         else
+           emit_move_insn (targ_piece, op0_piece);
+       }
+
+      insns = get_insns ();
+      end_sequence ();
+
+      emit_no_conflict_block (insns, target, op0, op1, NULL_RTX);
+    }
+  else
+    {
+      op1 = expand_binop (imode, and_optab, gen_lowpart (imode, op1),
+                         immed_double_const (lo, hi, imode),
+                         NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+      op0 = gen_lowpart (imode, op0);
+      if (!op0_is_abs)
+       op0 = expand_binop (imode, and_optab, op0,
+                           immed_double_const (~lo, ~hi, imode),
+                           NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+      temp = expand_binop (imode, ior_optab, op0, op1,
+                          gen_lowpart (imode, target), 1, OPTAB_LIB_WIDEN);
+      target = lowpart_subreg_maybe_copy (mode, temp, imode);
+    }
+
+  return target;
+}
+
+/* Expand the C99 copysign operation.  OP0 and OP1 must be the same 
+   scalar floating point mode.  Return NULL if we do not know how to
+   expand the operation inline.  */
+
+rtx
+expand_copysign (rtx op0, rtx op1, rtx target)
+{
+  enum machine_mode mode = GET_MODE (op0);
+  const struct real_format *fmt;
+  bool op0_is_abs;
+  rtx temp;
+
+  gcc_assert (SCALAR_FLOAT_MODE_P (mode));
+  gcc_assert (GET_MODE (op1) == mode);
+
+  /* First try to do it with a special instruction.  */
+  temp = expand_binop (mode, copysign_optab, op0, op1,
+                      target, 0, OPTAB_DIRECT);
+  if (temp)
+    return temp;
+
+  fmt = REAL_MODE_FORMAT (mode);
+  if (fmt == NULL || !fmt->has_signed_zero)
+    return NULL_RTX;
+
+  op0_is_abs = false;
+  if (GET_CODE (op0) == CONST_DOUBLE)
+    {
+      if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
+       op0 = simplify_unary_operation (ABS, mode, op0, mode);
+      op0_is_abs = true;
+    }
+
+  if (fmt->signbit_ro >= 0
+      && (GET_CODE (op0) == CONST_DOUBLE
+         || (neg_optab->handlers[mode].insn_code != CODE_FOR_nothing
+             && abs_optab->handlers[mode].insn_code != CODE_FOR_nothing)))
+    {
+      temp = expand_copysign_absneg (mode, op0, op1, target,
+                                    fmt->signbit_ro, op0_is_abs);
+      if (temp)
+       return temp;
+    }
+
+  if (fmt->signbit_rw < 0)
+    return NULL_RTX;
+  return expand_copysign_bit (mode, op0, op1, target,
+                             fmt->signbit_rw, op0_is_abs);
+}
+\f
+/* Generate an instruction whose insn-code is INSN_CODE,
    with two operands: an output TARGET and an input OP0.
    TARGET *must* be nonzero, and the output is always stored there.
    CODE is an rtx code such that (CODE OP0) is an rtx that describes
@@ -2620,10 +2925,10 @@ emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
 
   /* Now, if insn does not accept our operands, put them into pseudos.  */
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+  if (!insn_data[icode].operand[1].predicate (op0, mode0))
     op0 = copy_to_mode_reg (mode0, op0);
 
-  if (! (*insn_data[icode].operand[0].predicate) (temp, GET_MODE (temp))
+  if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp))
       || (flag_force_mem && MEM_P (temp)))
     temp = gen_reg_rtx (GET_MODE (temp));
 
@@ -2708,8 +3013,7 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
              }
        }
 
-      if (set == 0)
-       abort ();
+      gcc_assert (set);
 
       if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
        {
@@ -2982,7 +3286,6 @@ can_compare_p (enum rtx_code code, enum machine_mode mode,
       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);
@@ -3004,7 +3307,8 @@ can_compare_p (enum rtx_code code, enum machine_mode mode,
    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.  */
+   should perform the comparison on the modified values.  Constant
+   comparisons must have already been folded.  */
 
 static void
 prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
@@ -3018,11 +3322,6 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
 
   class = GET_MODE_CLASS (mode);
 
-  /* They could both be VOIDmode if both args are immediate constants,
-     but we should fold that at an earlier stage.
-     With no special code here, this will call abort,
-     reminding the programmer to implement such folding.  */
-
   if (mode != BLKmode && flag_force_mem)
     {
       /* Load duplicate non-volatile operands once.  */
@@ -3049,11 +3348,10 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
     y = force_reg (mode, y);
 
 #ifdef HAVE_cc0
-  /* Abort if we have a non-canonical comparison.  The RTL documentation
-     states that canonical comparisons are required only for targets which
-     have cc0.  */
-  if (CONSTANT_P (x) && ! CONSTANT_P (y))
-    abort ();
+  /* Make sure if we have a canonical comparison.  The RTL
+     documentation states that canonical comparisons are required only
+     for targets which have cc0.  */
+  gcc_assert (!CONSTANT_P (x) || CONSTANT_P (y));
 #endif
 
   /* Don't let both operands fail to indicate the mode.  */
@@ -3072,8 +3370,7 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
       rtx opalign
        = GEN_INT (MIN (MEM_ALIGN (x), MEM_ALIGN (y)) / BITS_PER_UNIT);
 
-      if (size == 0)
-       abort ();
+      gcc_assert (size);
 
       /* Try to use a memory block compare insn - either cmpstr
         or cmpmem will do.  */
@@ -3170,11 +3467,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
       return;
     }
 
-  if (class == MODE_FLOAT)
-    prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
-
-  else
-    abort ();
+  gcc_assert (class == MODE_FLOAT);
+  prepare_float_lib_cmp (px, py, pcomparison, pmode, punsignedp);
 }
 
 /* Before emitting an insn with code ICODE, make sure that X, which is going
@@ -3182,14 +3476,14 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
    WIDER_MODE (UNSIGNEDP determines whether it is an unsigned conversion), and
    that it is accepted by the operand predicate.  Return the new value.  */
 
-rtx
+static rtx
 prepare_operand (int icode, rtx x, int opnum, enum machine_mode mode,
                 enum machine_mode wider_mode, int unsignedp)
 {
   if (mode != wider_mode)
     x = convert_modes (wider_mode, mode, x, unsignedp);
 
-  if (! (*insn_data[icode].operand[opnum].predicate)
+  if (!insn_data[icode].operand[opnum].predicate
       (x, insn_data[icode].operand[opnum].mode))
     {
       if (no_new_pseudos)
@@ -3224,7 +3518,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
          icode = cbranch_optab->handlers[(int) wider_mode].insn_code;
 
          if (icode != CODE_FOR_nothing
-             && (*insn_data[icode].operand[0].predicate) (test, wider_mode))
+             && 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);
@@ -3240,7 +3534,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
          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));
+           emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
          return;
        }
 
@@ -3253,7 +3547,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
          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));
+           emit_jump_insn (bcc_gen_fctn[(int) comparison] (label));
          return;
        }
 
@@ -3265,7 +3559,7 @@ emit_cmp_and_jump_insn_1 (rtx x, rtx y, enum machine_mode mode,
     }
   while (wider_mode != VOIDmode);
 
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Generate code to compare X with Y so that the condition codes are
@@ -3296,17 +3590,15 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
     {
       /* If we're not emitting a branch, this means some caller
          is out of sync.  */
-      if (! label)
-       abort ();
+      gcc_assert (label);
 
       op0 = y, op1 = x;
       comparison = swap_condition (comparison);
     }
 
 #ifdef HAVE_cc0
-  /* If OP0 is still a constant, then both X and Y must be constants.  Force
-     X into a register to avoid aborting in emit_cmp_insn due to non-canonical
-     RTL.  */
+  /* If OP0 is still a constant, then both X and Y must be constants.
+     Force X into a register to create canonical RTL.  */
   if (CONSTANT_P (op0))
     op0 = force_reg (mode, op0);
 #endif
@@ -3368,8 +3660,7 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
        }
     }
 
-  if (mode == VOIDmode)
-    abort ();
+  gcc_assert (mode != VOIDmode);
 
   if (mode != orig_mode)
     {
@@ -3427,7 +3718,7 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
              break;
 
            default:
-             abort ();
+             gcc_unreachable ();
            }
          equiv = simplify_gen_ternary (IF_THEN_ELSE, word_mode, word_mode,
                                        equiv, true_rtx, false_rtx);
@@ -3459,8 +3750,8 @@ prepare_float_lib_cmp (rtx *px, rtx *py, enum rtx_code *pcomparison,
 void
 emit_indirect_jump (rtx loc)
 {
-  if (! ((*insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate)
-        (loc, Pmode)))
+  if (!insn_data[(int) CODE_FOR_indirect_jump].operand[0].predicate
+      (loc, Pmode))
     loc = copy_to_mode_reg (Pmode, loc);
 
   emit_jump_insn (gen_indirect_jump (loc));
@@ -3545,15 +3836,15 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   /* If the insn doesn't accept these operands, put them in pseudos.  */
 
-  if (! (*insn_data[icode].operand[0].predicate)
+  if (!insn_data[icode].operand[0].predicate
       (subtarget, insn_data[icode].operand[0].mode))
     subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
 
-  if (! (*insn_data[icode].operand[2].predicate)
+  if (!insn_data[icode].operand[2].predicate
       (op2, insn_data[icode].operand[2].mode))
     op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
 
-  if (! (*insn_data[icode].operand[3].predicate)
+  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);
 
@@ -3677,17 +3968,17 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
 
   /* If the insn doesn't accept these operands, put them in pseudos.  */
 
-  if (! (*insn_data[icode].operand[0].predicate)
+  if (!insn_data[icode].operand[0].predicate
       (target, insn_data[icode].operand[0].mode))
     subtarget = gen_reg_rtx (insn_data[icode].operand[0].mode);
   else
     subtarget = target;
 
-  if (! (*insn_data[icode].operand[2].predicate)
+  if (!insn_data[icode].operand[2].predicate
       (op2, insn_data[icode].operand[2].mode))
     op2 = copy_to_mode_reg (insn_data[icode].operand[2].mode, op2);
 
-  if (! (*insn_data[icode].operand[3].predicate)
+  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);
 
@@ -3729,15 +4020,14 @@ gen_add2_insn (rtx x, rtx y)
 {
   int icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
-  if (! ((*insn_data[icode].operand[0].predicate)
-        (x, insn_data[icode].operand[0].mode))
-      || ! ((*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 ();
+  gcc_assert (insn_data[icode].operand[0].predicate
+             (x, insn_data[icode].operand[0].mode));
+  gcc_assert (insn_data[icode].operand[1].predicate
+             (x, insn_data[icode].operand[1].mode));
+  gcc_assert (insn_data[icode].operand[2].predicate
+             (y, insn_data[icode].operand[2].mode));
 
-  return (GEN_FCN (icode) (x, x, y));
+  return GEN_FCN (icode) (x, x, y);
 }
 
 /* Generate and return an insn body to add r1 and c,
@@ -3748,15 +4038,15 @@ gen_add3_insn (rtx r0, rtx r1, rtx c)
   int icode = (int) add_optab->handlers[(int) GET_MODE (r0)].insn_code;
 
   if (icode == CODE_FOR_nothing
-      || ! ((*insn_data[icode].operand[0].predicate)
-           (r0, insn_data[icode].operand[0].mode))
-      || ! ((*insn_data[icode].operand[1].predicate)
-           (r1, insn_data[icode].operand[1].mode))
-      || ! ((*insn_data[icode].operand[2].predicate)
-           (c, insn_data[icode].operand[2].mode)))
+      || !(insn_data[icode].operand[0].predicate
+          (r0, insn_data[icode].operand[0].mode))
+      || !(insn_data[icode].operand[1].predicate
+          (r1, insn_data[icode].operand[1].mode))
+      || !(insn_data[icode].operand[2].predicate
+          (c, insn_data[icode].operand[2].mode)))
     return NULL_RTX;
 
-  return (GEN_FCN (icode) (r0, r1, c));
+  return GEN_FCN (icode) (r0, r1, c);
 }
 
 int
@@ -3764,20 +4054,19 @@ have_add2_insn (rtx x, rtx y)
 {
   int icode;
 
-  if (GET_MODE (x) == VOIDmode)
-    abort ();
+  gcc_assert (GET_MODE (x) != VOIDmode);
 
   icode = (int) add_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  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)))
+  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)))
     return 0;
 
   return 1;
@@ -3790,15 +4079,14 @@ gen_sub2_insn (rtx x, rtx y)
 {
   int icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
-  if (! ((*insn_data[icode].operand[0].predicate)
-        (x, insn_data[icode].operand[0].mode))
-      || ! ((*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 ();
+  gcc_assert (insn_data[icode].operand[0].predicate
+             (x, insn_data[icode].operand[0].mode));
+  gcc_assert (insn_data[icode].operand[1].predicate
+             (x, insn_data[icode].operand[1].mode));
+  gcc_assert  (insn_data[icode].operand[2].predicate
+              (y, insn_data[icode].operand[2].mode));
 
-  return (GEN_FCN (icode) (x, x, y));
+  return GEN_FCN (icode) (x, x, y);
 }
 
 /* Generate and return an insn body to subtract r1 and c,
@@ -3809,15 +4097,15 @@ gen_sub3_insn (rtx r0, rtx r1, rtx c)
   int icode = (int) sub_optab->handlers[(int) GET_MODE (r0)].insn_code;
 
   if (icode == CODE_FOR_nothing
-      || ! ((*insn_data[icode].operand[0].predicate)
-           (r0, insn_data[icode].operand[0].mode))
-      || ! ((*insn_data[icode].operand[1].predicate)
-           (r1, insn_data[icode].operand[1].mode))
-      || ! ((*insn_data[icode].operand[2].predicate)
-           (c, insn_data[icode].operand[2].mode)))
+      || !(insn_data[icode].operand[0].predicate
+          (r0, insn_data[icode].operand[0].mode))
+      || !(insn_data[icode].operand[1].predicate
+          (r1, insn_data[icode].operand[1].mode))
+      || !(insn_data[icode].operand[2].predicate
+          (c, insn_data[icode].operand[2].mode)))
     return NULL_RTX;
 
-  return (GEN_FCN (icode) (r0, r1, c));
+  return GEN_FCN (icode) (r0, r1, c);
 }
 
 int
@@ -3825,20 +4113,19 @@ have_sub2_insn (rtx x, rtx y)
 {
   int icode;
 
-  if (GET_MODE (x) == VOIDmode)
-    abort ();
+  gcc_assert (GET_MODE (x) != VOIDmode);
 
   icode = (int) sub_optab->handlers[(int) GET_MODE (x)].insn_code;
 
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  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)))
+  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)))
     return 0;
 
   return 1;
@@ -3952,8 +4239,7 @@ expand_float (rtx to, rtx from, int unsignedp)
   enum machine_mode fmode, imode;
 
   /* Crash now, because we won't be able to decide which mode to use.  */
-  if (GET_MODE (from) == VOIDmode)
-    abort ();
+  gcc_assert (GET_MODE (from) != VOIDmode);
 
   /* Look for an insn to do the conversion.  Do it in the specified
      modes if possible; otherwise convert either input, output or both to
@@ -4114,8 +4400,7 @@ expand_float (rtx to, rtx from, int unsignedp)
        from = force_not_mem (from);
 
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
-      if (!libfunc)
-       abort ();
+      gcc_assert (libfunc);
 
       start_sequence ();
 
@@ -4298,8 +4583,7 @@ expand_fix (rtx to, rtx from, int unsignedp)
 
       convert_optab tab = unsignedp ? ufix_optab : sfix_optab;
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
-      if (!libfunc)
-       abort ();
+      gcc_assert (libfunc);
 
       if (flag_force_mem)
        from = force_not_mem (from);
@@ -4649,6 +4933,12 @@ init_optabs (void)
     movcc_gen_code[i] = CODE_FOR_nothing;
 #endif
 
+  for (i = 0; i < NUM_MACHINE_MODES; i++)
+    {
+      vcond_gen_code[i] = CODE_FOR_nothing;
+      vcondu_gen_code[i] = CODE_FOR_nothing;
+    }
+
   add_optab = init_optab (PLUS);
   addv_optab = init_optabv (PLUS);
   sub_optab = init_optab (MINUS);
@@ -4714,11 +5004,14 @@ init_optabs (void)
   parity_optab = init_optab (PARITY);
   sqrt_optab = init_optab (SQRT);
   floor_optab = init_optab (UNKNOWN);
+  lfloor_optab = init_optab (UNKNOWN);
   ceil_optab = init_optab (UNKNOWN);
+  lceil_optab = init_optab (UNKNOWN);
   round_optab = init_optab (UNKNOWN);
   btrunc_optab = init_optab (UNKNOWN);
   nearbyint_optab = init_optab (UNKNOWN);
   rint_optab = init_optab (UNKNOWN);
+  lrint_optab = init_optab (UNKNOWN);
   sincos_optab = init_optab (UNKNOWN);
   sin_optab = init_optab (UNKNOWN);
   asin_optab = init_optab (UNKNOWN);
@@ -4728,6 +5021,7 @@ init_optabs (void)
   exp10_optab = init_optab (UNKNOWN);
   exp2_optab = init_optab (UNKNOWN);
   expm1_optab = init_optab (UNKNOWN);
+  ldexp_optab = init_optab (UNKNOWN);
   logb_optab = init_optab (UNKNOWN);
   ilogb_optab = init_optab (UNKNOWN);
   log_optab = init_optab (UNKNOWN);
@@ -4736,6 +5030,8 @@ init_optabs (void)
   log1p_optab = init_optab (UNKNOWN);
   tan_optab = init_optab (UNKNOWN);
   atan_optab = init_optab (UNKNOWN);
+  copysign_optab = init_optab (UNKNOWN);
+
   strlen_optab = init_optab (UNKNOWN);
   cbranch_optab = init_optab (UNKNOWN);
   cmov_optab = init_optab (UNKNOWN);
@@ -4746,6 +5042,9 @@ init_optabs (void)
   vec_set_optab = init_optab (UNKNOWN);
   vec_init_optab = init_optab (UNKNOWN);
   vec_realign_load_optab = init_optab (UNKNOWN);
+  movmisalign_optab = init_optab (UNKNOWN);
+
+  powi_optab = init_optab (UNKNOWN);
 
   /* Conversions.  */
   sext_optab = init_convert_optab (SIGN_EXTEND);
@@ -4765,6 +5064,29 @@ init_optabs (void)
       cmpstr_optab[i] = CODE_FOR_nothing;
       cmpmem_optab[i] = CODE_FOR_nothing;
 
+      sync_add_optab[i] = CODE_FOR_nothing;
+      sync_sub_optab[i] = CODE_FOR_nothing;
+      sync_ior_optab[i] = CODE_FOR_nothing;
+      sync_and_optab[i] = CODE_FOR_nothing;
+      sync_xor_optab[i] = CODE_FOR_nothing;
+      sync_nand_optab[i] = CODE_FOR_nothing;
+      sync_old_add_optab[i] = CODE_FOR_nothing;
+      sync_old_sub_optab[i] = CODE_FOR_nothing;
+      sync_old_ior_optab[i] = CODE_FOR_nothing;
+      sync_old_and_optab[i] = CODE_FOR_nothing;
+      sync_old_xor_optab[i] = CODE_FOR_nothing;
+      sync_old_nand_optab[i] = CODE_FOR_nothing;
+      sync_new_add_optab[i] = CODE_FOR_nothing;
+      sync_new_sub_optab[i] = CODE_FOR_nothing;
+      sync_new_ior_optab[i] = CODE_FOR_nothing;
+      sync_new_and_optab[i] = CODE_FOR_nothing;
+      sync_new_xor_optab[i] = CODE_FOR_nothing;
+      sync_new_nand_optab[i] = CODE_FOR_nothing;
+      sync_compare_and_swap[i] = CODE_FOR_nothing;
+      sync_compare_and_swap_cc[i] = CODE_FOR_nothing;
+      sync_lock_test_and_set[i] = CODE_FOR_nothing;
+      sync_lock_release[i] = CODE_FOR_nothing;
+
 #ifdef HAVE_SECONDARY_RELOADS
       reload_in_optab[i] = reload_out_optab[i] = CODE_FOR_nothing;
 #endif
@@ -4833,6 +5155,8 @@ init_optabs (void)
   init_floating_libfuncs (le_optab, "le", '2');
   init_floating_libfuncs (unord_optab, "unord", '2');
 
+  init_floating_libfuncs (powi_optab, "powi", '2');
+
   /* Conversions.  */
   init_interclass_conv_libfuncs (sfloat_optab, "float",
                                 MODE_INT, MODE_FLOAT);
@@ -4914,8 +5238,7 @@ debug_optab_libfuncs (void)
        h = &o->handlers[j];
        if (h->libfunc)
          {
-           if (GET_CODE (h->libfunc) != SYMBOL_REF)
-             abort ();
+           gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
            fprintf (stderr, "%s\t%s:\t%s\n",
                     GET_RTX_NAME (o->code),
                     GET_MODE_NAME (j),
@@ -4935,8 +5258,7 @@ debug_optab_libfuncs (void)
          h = &o->handlers[j][k];
          if (h->libfunc)
            {
-             if (GET_CODE (h->libfunc) != SYMBOL_REF)
-               abort ();
+             gcc_assert (GET_CODE (h->libfunc) = SYMBOL_REF);
              fprintf (stderr, "%s\t%s\t%s:\t%s\n",
                       GET_RTX_NAME (o->code),
                       GET_MODE_NAME (j),
@@ -4981,6 +5303,7 @@ gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
   emit_insn (GEN_FCN (icode) (op1, op2));
 
   PUT_CODE (trap_rtx, code);
+  gcc_assert (HAVE_conditional_trap);
   insn = gen_conditional_trap (trap_rtx, tcode);
   if (insn)
     {
@@ -4992,4 +5315,672 @@ gen_cond_trap (enum rtx_code code ATTRIBUTE_UNUSED, rtx op1,
   return insn;
 }
 
+/* Return rtx code for TCODE. Use UNSIGNEDP to select signed
+   or unsigned operation code.  */
+
+static enum rtx_code
+get_rtx_code (enum tree_code tcode, bool unsignedp)
+{
+  enum rtx_code code;
+  switch (tcode)
+    {
+    case EQ_EXPR:
+      code = EQ;
+      break;
+    case NE_EXPR:
+      code = NE;
+      break;
+    case LT_EXPR:
+      code = unsignedp ? LTU : LT;
+      break;
+    case LE_EXPR:
+      code = unsignedp ? LEU : LE;
+      break;
+    case GT_EXPR:
+      code = unsignedp ? GTU : GT;
+      break;
+    case GE_EXPR:
+      code = unsignedp ? GEU : GE;
+      break;
+      
+    case UNORDERED_EXPR:
+      code = UNORDERED;
+      break;
+    case ORDERED_EXPR:
+      code = ORDERED;
+      break;
+    case UNLT_EXPR:
+      code = UNLT;
+      break;
+    case UNLE_EXPR:
+      code = UNLE;
+      break;
+    case UNGT_EXPR:
+      code = UNGT;
+      break;
+    case UNGE_EXPR:
+      code = UNGE;
+      break;
+    case UNEQ_EXPR:
+      code = UNEQ;
+      break;
+    case LTGT_EXPR:
+      code = LTGT;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+  return code;
+}
+
+/* Return comparison rtx for COND. Use UNSIGNEDP to select signed or
+   unsigned operators. Do not generate compare instruction.  */
+
+static rtx
+vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
+{
+  enum rtx_code rcode;
+  tree t_op0, t_op1;
+  rtx rtx_op0, rtx_op1;
+
+  /* This is unlikely. While generating VEC_COND_EXPR, auto vectorizer
+     ensures that condition is a relational operation.  */
+  gcc_assert (COMPARISON_CLASS_P (cond));
+
+  rcode = get_rtx_code (TREE_CODE (cond), unsignedp); 
+  t_op0 = TREE_OPERAND (cond, 0);
+  t_op1 = TREE_OPERAND (cond, 1);
+  
+  /* Expand operands.  */
+  rtx_op0 = expand_expr (t_op0, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op0)), 1);
+  rtx_op1 = expand_expr (t_op1, NULL_RTX, TYPE_MODE (TREE_TYPE (t_op1)), 1);
+
+  if (!insn_data[icode].operand[4].predicate (rtx_op0, GET_MODE (rtx_op0))
+      && GET_MODE (rtx_op0) != VOIDmode)
+    rtx_op0 = force_reg (GET_MODE (rtx_op0), rtx_op0);
+  
+  if (!insn_data[icode].operand[5].predicate (rtx_op1, GET_MODE (rtx_op1))
+      && GET_MODE (rtx_op1) != VOIDmode)
+    rtx_op1 = force_reg (GET_MODE (rtx_op1), rtx_op1);
+
+  return gen_rtx_fmt_ee (rcode, VOIDmode, rtx_op0, rtx_op1);
+}
+
+/* Return insn code for VEC_COND_EXPR EXPR.  */
+  
+static inline enum insn_code 
+get_vcond_icode (tree expr, enum machine_mode mode)
+{
+  enum insn_code icode = CODE_FOR_nothing;
+
+  if (TYPE_UNSIGNED (TREE_TYPE (expr)))
+    icode = vcondu_gen_code[mode];
+  else
+    icode = vcond_gen_code[mode];
+  return icode;
+}
+
+/* Return TRUE iff, appropriate vector insns are available
+   for vector cond expr expr in VMODE mode.  */
+
+bool
+expand_vec_cond_expr_p (tree expr, enum machine_mode vmode)
+{
+  if (get_vcond_icode (expr, vmode) == CODE_FOR_nothing)
+    return false;
+  return true;
+}
+
+/* Generate insns for VEC_COND_EXPR.  */
+
+rtx
+expand_vec_cond_expr (tree vec_cond_expr, rtx target)
+{
+  enum insn_code icode;
+  rtx comparison, rtx_op1, rtx_op2, cc_op0, cc_op1;
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_cond_expr));
+  bool unsignedp = TYPE_UNSIGNED (TREE_TYPE (vec_cond_expr));
+
+  icode = get_vcond_icode (vec_cond_expr, mode);
+  if (icode == CODE_FOR_nothing)
+    return 0;
+
+  if (!target)
+    target = gen_reg_rtx (mode);
+
+  /* Get comparison rtx.  First expand both cond expr operands.  */
+  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), 
+                                  unsignedp, icode);
+  cc_op0 = XEXP (comparison, 0);
+  cc_op1 = XEXP (comparison, 1);
+  /* Expand both operands and force them in reg, if required.  */
+  rtx_op1 = expand_expr (TREE_OPERAND (vec_cond_expr, 1),
+                        NULL_RTX, VOIDmode, 1);
+  if (!insn_data[icode].operand[1].predicate (rtx_op1, mode)
+      && mode != VOIDmode)
+    rtx_op1 = force_reg (mode, rtx_op1);
+
+  rtx_op2 = expand_expr (TREE_OPERAND (vec_cond_expr, 2),
+                        NULL_RTX, VOIDmode, 1);
+  if (!insn_data[icode].operand[2].predicate (rtx_op2, mode)
+      && mode != VOIDmode)
+    rtx_op2 = force_reg (mode, rtx_op2);
+
+  /* Emit instruction! */
+  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, 
+                             comparison, cc_op0,  cc_op1));
+
+  return target;
+}
+
+\f
+/* This is an internal subroutine of the other compare_and_swap expanders.
+   MEM, OLD_VAL and NEW_VAL are as you'd expect for a compare-and-swap
+   operation.  TARGET is an optional place to store the value result of
+   the operation.  ICODE is the particular instruction to expand.  Return
+   the result of the operation.  */
+
+static rtx
+expand_val_compare_and_swap_1 (rtx mem, rtx old_val, rtx new_val,
+                              rtx target, enum insn_code icode)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx insn;
+
+  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
+    target = gen_reg_rtx (mode);
+
+  if (GET_MODE (old_val) != VOIDmode && GET_MODE (old_val) != mode)
+    old_val = convert_modes (mode, GET_MODE (old_val), old_val, 1);
+  if (!insn_data[icode].operand[2].predicate (old_val, mode))
+    old_val = force_reg (mode, old_val);
+
+  if (GET_MODE (new_val) != VOIDmode && GET_MODE (new_val) != mode)
+    new_val = convert_modes (mode, GET_MODE (new_val), new_val, 1);
+  if (!insn_data[icode].operand[3].predicate (new_val, mode))
+    new_val = force_reg (mode, new_val);
+
+  insn = GEN_FCN (icode) (target, mem, old_val, new_val);
+  if (insn == NULL_RTX)
+    return NULL_RTX;
+  emit_insn (insn);
+
+  return target;
+}
+
+/* Expand a compare-and-swap operation and return its value.  */
+
+rtx
+expand_val_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code icode = sync_compare_and_swap[mode];
+
+  if (icode == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  return expand_val_compare_and_swap_1 (mem, old_val, new_val, target, icode);
+}
+
+/* Expand a compare-and-swap operation and store true into the result if
+   the operation was successful and false otherwise.  Return the result.
+   Unlike other routines, TARGET is not optional.  */
+
+rtx
+expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code icode;
+  rtx subtarget, label0, label1;
+
+  /* If the target supports a compare-and-swap pattern that simultaneously
+     sets some flag for success, then use it.  Otherwise use the regular
+     compare-and-swap and follow that immediately with a compare insn.  */
+  icode = sync_compare_and_swap_cc[mode];
+  switch (icode)
+    {
+    default:
+      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
+                                                NULL_RTX, icode);
+      if (subtarget != NULL_RTX)
+       break;
+
+      /* FALLTHRU */
+    case CODE_FOR_nothing:
+      icode = sync_compare_and_swap[mode];
+      if (icode == CODE_FOR_nothing)
+       return NULL_RTX;
+
+      /* Ensure that if old_val == mem, that we're not comparing
+        against an old value.  */
+      if (MEM_P (old_val))
+       old_val = force_reg (mode, old_val);
+
+      subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
+                                                NULL_RTX, icode);
+      if (subtarget == NULL_RTX)
+       return NULL_RTX;
+
+      emit_cmp_insn (subtarget, old_val, EQ, const0_rtx, mode, true);
+    }
+
+  /* If the target has a sane STORE_FLAG_VALUE, then go ahead and use a
+     setcc instruction from the beginning.  We don't work too hard here,
+     but it's nice to not be stupid about initial code gen either.  */
+  if (STORE_FLAG_VALUE == 1)
+    {
+      icode = setcc_gen_code[EQ];
+      if (icode != CODE_FOR_nothing)
+       {
+         enum machine_mode cmode = insn_data[icode].operand[0].mode;
+         rtx insn;
+
+         subtarget = target;
+         if (!insn_data[icode].operand[0].predicate (target, cmode))
+           subtarget = gen_reg_rtx (cmode);
+
+         insn = GEN_FCN (icode) (subtarget);
+         if (insn)
+           {
+             emit_insn (insn);
+             if (GET_MODE (target) != GET_MODE (subtarget))
+               {
+                 convert_move (target, subtarget, 1);
+                 subtarget = target;
+               }
+             return subtarget;
+           }
+       }
+    }
+
+  /* Without an appropriate setcc instruction, use a set of branches to 
+     get 1 and 0 stored into target.  Presumably if the target has a 
+     STORE_FLAG_VALUE that isn't 1, then this will get cleaned up by ifcvt.  */
+
+  label0 = gen_label_rtx ();
+  label1 = gen_label_rtx ();
+
+  emit_jump_insn (bcc_gen_fctn[EQ] (label0));
+  emit_move_insn (target, const0_rtx);
+  emit_jump_insn (gen_jump (label1));
+  emit_label (label0);
+  emit_move_insn (target, const1_rtx);
+  emit_label (label1);
+
+  return target;
+}
+
+/* This is a helper function for the other atomic operations.  This function
+   emits a loop that contains SEQ that iterates until a compare-and-swap
+   operation at the end succeeds.  MEM is the memory to be modified.  SEQ is
+   a set of instructions that takes a value from OLD_REG as an input and
+   produces a value in NEW_REG as an output.  Before SEQ, OLD_REG will be
+   set to the current contents of MEM.  After SEQ, a compare-and-swap will
+   attempt to update MEM with NEW_REG.  The function returns true when the
+   loop was generated successfully.  */
+
+static bool
+expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code icode;
+  rtx label, cmp_reg, subtarget;
+
+  /* The loop we want to generate looks like
+
+       cmp_reg = mem;
+      label:
+        old_reg = cmp_reg;
+       seq;
+       cmp_reg = compare-and-swap(mem, old_reg, new_reg)
+       if (cmp_reg != old_reg)
+         goto label;
+
+     Note that we only do the plain load from memory once.  Subsequent
+     iterations use the value loaded by the compare-and-swap pattern.  */
+
+  label = gen_label_rtx ();
+  cmp_reg = gen_reg_rtx (mode);
+
+  emit_move_insn (cmp_reg, mem);
+  emit_label (label);
+  emit_move_insn (old_reg, cmp_reg);
+  if (seq)
+    emit_insn (seq);
+
+  /* If the target supports a compare-and-swap pattern that simultaneously
+     sets some flag for success, then use it.  Otherwise use the regular
+     compare-and-swap and follow that immediately with a compare insn.  */
+  icode = sync_compare_and_swap_cc[mode];
+  switch (icode)
+    {
+    default:
+      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
+                                                cmp_reg, icode);
+      if (subtarget != NULL_RTX)
+       {
+         gcc_assert (subtarget == cmp_reg);
+         break;
+       }
+
+      /* FALLTHRU */
+    case CODE_FOR_nothing:
+      icode = sync_compare_and_swap[mode];
+      if (icode == CODE_FOR_nothing)
+       return false;
+
+      subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
+                                                cmp_reg, icode);
+      if (subtarget == NULL_RTX)
+       return false;
+      if (subtarget != cmp_reg)
+       emit_move_insn (cmp_reg, subtarget);
+
+      emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
+    }
+
+  /* ??? Mark this jump predicted not taken?  */
+  emit_jump_insn (bcc_gen_fctn[NE] (label));
+
+  return true;
+}
+
+/* This function generates the atomic operation MEM CODE= VAL.  In this
+   case, we do not care about any resulting value.  Returns NULL if we 
+   cannot generate the operation.  */
+
+rtx
+expand_sync_operation (rtx mem, rtx val, enum rtx_code code)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code icode;
+  rtx insn;
+
+  /* Look to see if the target supports the operation directly.  */
+  switch (code)
+    {
+    case PLUS:
+      icode = sync_add_optab[mode];
+      break;
+    case IOR:
+      icode = sync_ior_optab[mode];
+      break;
+    case XOR:
+      icode = sync_xor_optab[mode];
+      break;
+    case AND:
+      icode = sync_and_optab[mode];
+      break;
+    case NOT:
+      icode = sync_nand_optab[mode];
+      break;
+
+    case MINUS:
+      icode = sync_sub_optab[mode];
+      if (icode == CODE_FOR_nothing)
+       {
+         icode = sync_add_optab[mode];
+         if (icode != CODE_FOR_nothing)
+           {
+             val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
+             code = PLUS;
+           }
+       }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Generate the direct operation, if present.  */
+  if (icode != CODE_FOR_nothing)
+    {
+      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
+       val = convert_modes (mode, GET_MODE (val), val, 1);
+      if (!insn_data[icode].operand[1].predicate (val, mode))
+       val = force_reg (mode, val);
+      
+      insn = GEN_FCN (icode) (mem, val);
+      if (insn)
+       {
+         emit_insn (insn);
+         return const0_rtx;
+       }
+    }
+
+  /* Failing that, generate a compare-and-swap loop in which we perform the
+     operation with normal arithmetic instructions.  */
+  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
+    {
+      rtx t0 = gen_reg_rtx (mode), t1;
+
+      start_sequence ();
+
+      t1 = t0;
+      if (code == NOT)
+       {
+         t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
+         code = AND;
+       }
+      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
+                               true, OPTAB_LIB_WIDEN);
+
+      insn = get_insns ();
+      end_sequence ();
+
+      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
+       return const0_rtx;
+    }
+
+  return NULL_RTX;
+}
+
+/* This function generates the atomic operation MEM CODE= VAL.  In this
+   case, we do care about the resulting value: if AFTER is true then
+   return the value MEM holds after the operation, if AFTER is false 
+   then return the value MEM holds before the operation.  TARGET is an
+   optional place for the result value to be stored.  */
+
+rtx
+expand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code,
+                            bool after, rtx target)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code old_code, new_code, icode;
+  bool compensate;
+  rtx insn;
+
+  /* Look to see if the target supports the operation directly.  */
+  switch (code)
+    {
+    case PLUS:
+      old_code = sync_old_add_optab[mode];
+      new_code = sync_new_add_optab[mode];
+      break;
+    case IOR:
+      old_code = sync_old_ior_optab[mode];
+      new_code = sync_new_ior_optab[mode];
+      break;
+    case XOR:
+      old_code = sync_old_xor_optab[mode];
+      new_code = sync_new_xor_optab[mode];
+      break;
+    case AND:
+      old_code = sync_old_and_optab[mode];
+      new_code = sync_new_and_optab[mode];
+      break;
+    case NOT:
+      old_code = sync_old_nand_optab[mode];
+      new_code = sync_new_nand_optab[mode];
+      break;
+
+    case MINUS:
+      old_code = sync_old_sub_optab[mode];
+      new_code = sync_new_sub_optab[mode];
+      if (old_code == CODE_FOR_nothing && new_code == CODE_FOR_nothing)
+       {
+         old_code = sync_old_add_optab[mode];
+         new_code = sync_new_add_optab[mode];
+         if (old_code != CODE_FOR_nothing || new_code != CODE_FOR_nothing)
+           {
+             val = expand_simple_unop (mode, NEG, val, NULL_RTX, 1);
+             code = PLUS;
+           }
+       }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* If the target does supports the proper new/old operation, great.  But
+     if we only support the opposite old/new operation, check to see if we
+     can compensate.  In the case in which the old value is supported, then
+     we can always perform the operation again with normal arithmetic.  In
+     the case in which the new value is supported, then we can only handle
+     this in the case the operation is reversible.  */
+  compensate = false;
+  if (after)
+    {
+      icode = new_code;
+      if (icode == CODE_FOR_nothing)
+       {
+         icode = old_code;
+         if (icode != CODE_FOR_nothing)
+           compensate = true;
+       }
+    }
+  else
+    {
+      icode = old_code;
+      if (icode == CODE_FOR_nothing
+         && (code == PLUS || code == MINUS || code == XOR))
+       {
+         icode = new_code;
+         if (icode != CODE_FOR_nothing)
+           compensate = true;
+       }
+    }
+
+  /* If we found something supported, great.  */
+  if (icode != CODE_FOR_nothing)
+    {
+      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
+       target = gen_reg_rtx (mode);
+
+      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
+       val = convert_modes (mode, GET_MODE (val), val, 1);
+      if (!insn_data[icode].operand[2].predicate (val, mode))
+       val = force_reg (mode, val);
+      
+      insn = GEN_FCN (icode) (target, mem, val);
+      if (insn)
+       {
+         emit_insn (insn);
+
+         /* If we need to compensate for using an operation with the
+            wrong return value, do so now.  */
+         if (compensate)
+           {
+             if (!after)
+               {
+                 if (code == PLUS)
+                   code = MINUS;
+                 else if (code == MINUS)
+                   code = PLUS;
+               }
+
+             if (code == NOT)
+               target = expand_simple_unop (mode, NOT, target, NULL_RTX, true);
+             target = expand_simple_binop (mode, code, target, val, NULL_RTX,
+                                           true, OPTAB_LIB_WIDEN);
+           }
+
+         return target;
+       }
+    }
+
+  /* Failing that, generate a compare-and-swap loop in which we perform the
+     operation with normal arithmetic instructions.  */
+  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
+    {
+      rtx t0 = gen_reg_rtx (mode), t1;
+
+      if (!target || !register_operand (target, mode))
+       target = gen_reg_rtx (mode);
+
+      start_sequence ();
+
+      if (!after)
+       emit_move_insn (target, t0);
+      t1 = t0;
+      if (code == NOT)
+       {
+         t1 = expand_simple_unop (mode, NOT, t1, NULL_RTX, true);
+         code = AND;
+       }
+      t1 = expand_simple_binop (mode, code, t1, val, NULL_RTX,
+                               true, OPTAB_LIB_WIDEN);
+      if (after)
+       emit_move_insn (target, t1);
+
+      insn = get_insns ();
+      end_sequence ();
+
+      if (t1 != NULL && expand_compare_and_swap_loop (mem, t0, t1, insn))
+       return target;
+    }
+
+  return NULL_RTX;
+}
+
+/* This function expands a test-and-set operation.  Ideally we atomically
+   store VAL in MEM and return the previous value in MEM.  Some targets
+   may not support this operation and only support VAL with the constant 1;
+   in this case while the return value will be 0/1, but the exact value 
+   stored in MEM is target defined.  TARGET is an option place to stick
+   the return value.  */
+
+rtx
+expand_sync_lock_test_and_set (rtx mem, rtx val, rtx target)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  enum insn_code icode;
+  rtx insn;
+
+  /* If the target supports the test-and-set directly, great.  */
+  icode = sync_lock_test_and_set[mode];
+  if (icode != CODE_FOR_nothing)
+    {
+      if (!target || !insn_data[icode].operand[0].predicate (target, mode))
+       target = gen_reg_rtx (mode);
+
+      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
+       val = convert_modes (mode, GET_MODE (val), val, 1);
+      if (!insn_data[icode].operand[2].predicate (val, mode))
+       val = force_reg (mode, val);
+
+      insn = GEN_FCN (icode) (target, mem, val);
+      if (insn)
+       {
+         emit_insn (insn);
+         return target;
+       }
+    }
+
+  /* Otherwise, use a compare-and-swap loop for the exchange.  */
+  if (sync_compare_and_swap[mode] != CODE_FOR_nothing)
+    {
+      if (!target || !register_operand (target, mode))
+       target = gen_reg_rtx (mode);
+      if (GET_MODE (val) != VOIDmode && GET_MODE (val) != mode)
+       val = convert_modes (mode, GET_MODE (val), val, 1);
+      if (expand_compare_and_swap_loop (mem, target, val, NULL_RTX))
+       return target;
+    }
+
+  return NULL_RTX;
+}
+
 #include "gt-optabs.h"