OSDN Git Service

2005-10-18 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / optabs.c
index 8d20ad7..c043bb0 100644 (file)
@@ -16,8 +16,8 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
@@ -59,7 +59,7 @@ optab optab_table[OTI_MAX];
 rtx libfunc_table[LTI_MAX];
 
 /* Tables of patterns for converting one mode to another.  */
-convert_optab convert_optab_table[CTI_MAX];
+convert_optab convert_optab_table[COI_MAX];
 
 /* Contains the optab used for each rtx code.  */
 optab code_to_optab[NUM_RTX_CODE + 1];
@@ -127,6 +127,7 @@ 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) (gcc_unreachable (), NULL_RTX)
 #endif
 \f
 /* Add a REG_EQUAL note to the last insn in INSNS.  TARGET is being set to
@@ -293,6 +294,21 @@ optab_for_tree_code (enum tree_code code, tree type)
     case REALIGN_LOAD_EXPR:
       return vec_realign_load_optab;
 
+    case REDUC_MAX_EXPR:
+      return TYPE_UNSIGNED (type) ? reduc_umax_optab : reduc_smax_optab;
+
+    case REDUC_MIN_EXPR:
+      return TYPE_UNSIGNED (type) ? reduc_umin_optab : reduc_smin_optab;
+
+    case REDUC_PLUS_EXPR:
+      return TYPE_UNSIGNED (type) ? reduc_uplus_optab : reduc_splus_optab;
+
+    case VEC_LSHIFT_EXPR:
+      return vec_shl_optab;
+
+    case VEC_RSHIFT_EXPR:
+      return vec_shr_optab;
+
     default:
       break;
     }
@@ -333,8 +349,8 @@ optab_for_tree_code (enum tree_code code, tree type)
    this may or may not be TARGET.  */
 
 rtx
-expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0, 
-                  rtx op1, rtx op2, rtx target, int unsignedp) 
+expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
+                  rtx op1, rtx op2, rtx target, int unsignedp)
 {
   int icode = (int) ternary_optab->handlers[(int) mode].insn_code;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -361,7 +377,7 @@ expand_ternary_op (enum machine_mode mode, optab ternary_optab, rtx op0,
   if (GET_MODE (op0) != mode0 && mode0 != VOIDmode)
     xop0 = convert_modes (mode0,
                           GET_MODE (op0) != VOIDmode
-                          ? GET_MODE (op0) 
+                          ? GET_MODE (op0)
                           : mode,
                           xop0, unsignedp);
 
@@ -381,23 +397,23 @@ 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)
-      && mode0 != VOIDmode) 
+      && mode0 != VOIDmode)
     xop0 = copy_to_mode_reg (mode0, xop0);
-  
+
   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)
       && mode2 != VOIDmode)
     xop2 = copy_to_mode_reg (mode2, xop2);
-    
+
   pat = GEN_FCN (icode) (temp, xop0, xop1, xop2);
-    
+
   emit_insn (pat);
-  return temp; 
+  return temp;
 }
 
 
@@ -433,6 +449,61 @@ force_expand_binop (enum machine_mode mode, optab binoptab,
   return true;
 }
 
+/* Generate insns for VEC_LSHIFT_EXPR, VEC_RSHIFT_EXPR.  */
+
+rtx
+expand_vec_shift_expr (tree vec_shift_expr, rtx target)
+{
+  enum insn_code icode;
+  rtx rtx_op1, rtx_op2;
+  enum machine_mode mode1;
+  enum machine_mode mode2;
+  enum machine_mode mode = TYPE_MODE (TREE_TYPE (vec_shift_expr));
+  tree vec_oprnd = TREE_OPERAND (vec_shift_expr, 0);
+  tree shift_oprnd = TREE_OPERAND (vec_shift_expr, 1);
+  optab shift_optab;
+  rtx pat;
+
+  switch (TREE_CODE (vec_shift_expr))
+    {
+      case VEC_RSHIFT_EXPR:
+       shift_optab = vec_shr_optab;
+       break;
+      case VEC_LSHIFT_EXPR:
+       shift_optab = vec_shl_optab;
+       break;
+      default:
+       gcc_unreachable ();
+    }
+
+  icode = (int) shift_optab->handlers[(int) mode].insn_code;
+  gcc_assert (icode != CODE_FOR_nothing);
+
+  mode1 = insn_data[icode].operand[1].mode;
+  mode2 = insn_data[icode].operand[2].mode;
+
+  rtx_op1 = expand_expr (vec_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  if (!(*insn_data[icode].operand[1].predicate) (rtx_op1, mode1)
+      && mode1 != VOIDmode)
+    rtx_op1 = force_reg (mode1, rtx_op1);
+
+  rtx_op2 = expand_expr (shift_oprnd, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+  if (!(*insn_data[icode].operand[2].predicate) (rtx_op2, mode2)
+      && mode2 != VOIDmode)
+    rtx_op2 = force_reg (mode2, rtx_op2);
+
+  if (!target
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode))
+    target = gen_reg_rtx (mode);
+
+  /* Emit instruction */
+  pat = GEN_FCN (icode) (target, rtx_op1, rtx_op2);
+  gcc_assert (pat);
+  emit_insn (pat);
+
+  return target;
+}
+
 /* This subroutine of expand_doubleword_shift handles the cases in which
    the effective shift value is >= BITS_PER_WORD.  The arguments and return
    value are the same as for the parent routine, except that SUPERWORD_OP1
@@ -956,24 +1027,10 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                  || binoptab->code == ROTATERT);
   rtx entry_last = get_last_insn ();
   rtx last;
+  bool first_pass_p = true;
 
   class = GET_MODE_CLASS (mode);
 
-  if (flag_force_mem)
-    {
-      /* Load duplicate non-volatile operands once.  */
-      if (rtx_equal_p (op0, op1) && ! volatile_refs_p (op0))
-       {
-         op0 = force_not_mem (op0);
-         op1 = op0;
-       }
-      else
-       {
-         op0 = force_not_mem (op0);
-         op1 = force_not_mem (op1);
-       }
-    }
-
   /* If subtracting an integer constant, convert this into an addition of
      the negated constant.  */
 
@@ -1029,6 +1086,8 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        }
     }
 
+ retry:
+
   /* If we can do it with a three-operand insn, do so.  */
 
   if (methods != OPTAB_MUST_WIDEN
@@ -1114,6 +1173,22 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
        delete_insns_since (last);
     }
 
+  /* If we were trying to rotate by a constant value, and that didn't
+     work, try rotating the other direction before falling back to
+     shifts and bitwise-or.  */
+  if (first_pass_p
+      && (binoptab == rotl_optab || binoptab == rotr_optab)
+      && class == MODE_INT
+      && GET_CODE (op1) == CONST_INT
+      && INTVAL (op1) > 0
+      && (unsigned int) INTVAL (op1) < GET_MODE_BITSIZE (mode))
+    {
+      first_pass_p = false;
+      op1 = GEN_INT (GET_MODE_BITSIZE (mode) - INTVAL (op1));
+      binoptab = binoptab == rotl_optab ? rotr_optab : rotl_optab;
+      goto retry;
+    }
+
   /* If this is a multiply, see if we can do a widening operation that
      takes operands of this mode and makes a wider mode.  */
 
@@ -1128,7 +1203,9 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
 
       if (temp != 0)
        {
-         if (GET_MODE_CLASS (mode) == MODE_INT)
+         if (GET_MODE_CLASS (mode) == MODE_INT
+             && TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                        GET_MODE_BITSIZE (GET_MODE (temp))))
            return gen_lowpart (mode, temp);
          else
            return convert_to_mode (mode, temp, unsignedp);
@@ -1175,7 +1252,9 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                                 unsignedp, OPTAB_DIRECT);
            if (temp)
              {
-               if (class != MODE_INT)
+               if (class != MODE_INT
+                    || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                               GET_MODE_BITSIZE (wider_mode)))
                  {
                    if (target == 0)
                      target = gen_reg_rtx (mode);
@@ -1703,7 +1782,9 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1,
                                   unsignedp, methods);
              if (temp)
                {
-                 if (class != MODE_INT)
+                 if (class != MODE_INT
+                     || !TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (mode),
+                                                GET_MODE_BITSIZE (wider_mode)))
                    {
                      if (target == 0)
                        target = gen_reg_rtx (mode);
@@ -1800,9 +1881,6 @@ expand_twoval_unop (optab unoptab, rtx op0, rtx targ0, rtx targ1,
 
   class = GET_MODE_CLASS (mode);
 
-  if (flag_force_mem)
-    op0 = force_not_mem (op0);
-
   if (!targ0)
     targ0 = gen_reg_rtx (mode);
   if (!targ1)
@@ -1895,12 +1973,6 @@ expand_twoval_binop (optab binoptab, rtx op0, rtx op1, rtx targ0, rtx targ1,
 
   class = GET_MODE_CLASS (mode);
 
-  if (flag_force_mem)
-    {
-      op0 = force_not_mem (op0);
-      op1 = force_not_mem (op1);
-    }
-
   /* If we are inside an appropriately-short loop and we are optimizing,
      force expensive constants into a register.  */
   if (CONSTANT_P (op0) && optimize
@@ -2139,7 +2211,7 @@ expand_parity (enum machine_mode mode, rtx op0, rtx target)
   return 0;
 }
 
-/* Extract the OMODE lowpart from VAL, which has IMODE.  Under certain 
+/* 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.  */
@@ -2229,7 +2301,7 @@ expand_absneg_bit (enum rtx_code code, enum machine_mode mode,
        {
          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,
@@ -2287,9 +2359,6 @@ expand_unop (enum machine_mode mode, optab unoptab, rtx op0, rtx target,
 
   class = GET_MODE_CLASS (mode);
 
-  if (flag_force_mem)
-    op0 = force_not_mem (op0);
-
   if (unoptab->handlers[(int) mode].insn_code != CODE_FOR_nothing)
     {
       int icode = (int) unoptab->handlers[(int) mode].insn_code;
@@ -2804,7 +2873,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
        {
          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)
@@ -2851,7 +2920,7 @@ expand_copysign_bit (enum machine_mode mode, rtx op0, rtx op1, rtx target,
   return target;
 }
 
-/* Expand the C99 copysign operation.  OP0 and OP1 must be the same 
+/* 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.  */
 
@@ -2916,19 +2985,12 @@ emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
 
   temp = target;
 
-  /* Sign and zero extension from memory is often done specially on
-     RISC machines, so forcing into a register here can pessimize
-     code.  */
-  if (flag_force_mem && code != SIGN_EXTEND && code != ZERO_EXTEND)
-    op0 = force_not_mem (op0);
-
   /* Now, if insn does not accept our operands, put them into pseudos.  */
 
   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))
-      || (flag_force_mem && MEM_P (temp)))
+  if (!insn_data[icode].operand[0].predicate (temp, GET_MODE (temp)))
     temp = gen_reg_rtx (GET_MODE (temp));
 
   pat = GEN_FCN (icode) (temp, op0);
@@ -2942,6 +3004,47 @@ emit_unop_insn (int icode, rtx target, rtx op0, enum rtx_code code)
     emit_move_insn (target, temp);
 }
 \f
+struct no_conflict_data
+{
+  rtx target, first, insn;
+  bool must_stay;
+};
+
+/* Called via note_stores by emit_no_conflict_block and emit_libcall_block.
+   Set P->must_stay if the currently examined clobber / store has to stay
+   in the list of insns that constitute the actual no_conflict block /
+   libcall block.  */
+static void
+no_conflict_move_test (rtx dest, rtx set, void *p0)
+{
+  struct no_conflict_data *p= p0;
+
+  /* If this inns directly contributes to setting the target, it must stay.  */
+  if (reg_overlap_mentioned_p (p->target, dest))
+    p->must_stay = true;
+  /* If we haven't committed to keeping any other insns in the list yet,
+     there is nothing more to check.  */
+  else if (p->insn == p->first)
+    return;
+  /* If this insn sets / clobbers a register that feeds one of the insns
+     already in the list, this insn has to stay too.  */
+  else if (reg_overlap_mentioned_p (dest, PATTERN (p->first))
+          || (CALL_P (p->first) && (find_reg_fusage (p->first, USE, dest)))
+          || reg_used_between_p (dest, p->first, p->insn)
+          /* Likewise if this insn depends on a register set by a previous
+             insn in the list, or if it sets a result (presumably a hard
+             register) that is set or clobbered by a previous insn.
+             N.B. the modified_*_p (SET_DEST...) tests applied to a MEM
+             SET_DEST perform the former check on the address, and the latter
+             check on the MEM.  */
+          || (GET_CODE (set) == SET
+              && (modified_in_p (SET_SRC (set), p->first)
+                  || modified_in_p (SET_DEST (set), p->first)
+                  || modified_between_p (SET_SRC (set), p->first, p->insn)
+                  || modified_between_p (SET_DEST (set), p->first, p->insn))))
+    p->must_stay = true;
+}
+
 /* Emit code to perform a series of operations on a multi-word quantity, one
    word at a time.
 
@@ -2987,8 +3090,8 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
      these from the list.  */
   for (insn = insns; insn; insn = next)
     {
-      rtx set = 0, note;
-      int i;
+      rtx note;
+      struct no_conflict_data data;
 
       next = NEXT_INSN (insn);
 
@@ -2999,22 +3102,12 @@ emit_no_conflict_block (rtx insns, rtx target, rtx op0, rtx op1, rtx equiv)
       if ((note = find_reg_note (insn, REG_RETVAL, NULL)) != NULL)
        remove_note (insn, note);
 
-      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)
-       {
-         for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
-           if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
-             {
-               set = XVECEXP (PATTERN (insn), 0, i);
-               break;
-             }
-       }
-
-      gcc_assert (set);
-
-      if (! reg_overlap_mentioned_p (target, SET_DEST (set)))
+      data.target = target;
+      data.first = insns;
+      data.insn = insn;
+      data.must_stay = 0;
+      note_stores (PATTERN (insn), no_conflict_move_test, &data);
+      if (! data.must_stay)
        {
          if (PREV_INSN (insn))
            NEXT_INSN (PREV_INSN (insn)) = next;
@@ -3168,23 +3261,27 @@ emit_libcall_block (rtx insns, rtx target, rtx result, rtx equiv)
       next = NEXT_INSN (insn);
 
       if (set != 0 && REG_P (SET_DEST (set))
-         && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER
-         && (insn == 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))))
+         && REGNO (SET_DEST (set)) >= FIRST_PSEUDO_REGISTER)
        {
-         if (PREV_INSN (insn))
-           NEXT_INSN (PREV_INSN (insn)) = next;
-         else
-           insns = next;
+         struct no_conflict_data data;
+
+         data.target = const0_rtx;
+         data.first = insns;
+         data.insn = insn;
+         data.must_stay = 0;
+         note_stores (PATTERN (insn), no_conflict_move_test, &data);
+         if (! data.must_stay)
+           {
+             if (PREV_INSN (insn))
+               NEXT_INSN (PREV_INSN (insn)) = next;
+             else
+               insns = next;
 
-         if (next)
-           PREV_INSN (next) = PREV_INSN (insn);
+             if (next)
+               PREV_INSN (next) = PREV_INSN (insn);
 
-         add_insn (insn);
+             add_insn (insn);
+           }
        }
 
       /* Some ports use a loop to copy large arguments onto the stack.
@@ -3306,7 +3403,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,
@@ -3320,26 +3418,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.  */
-      if (rtx_equal_p (x, y) && ! volatile_refs_p (x))
-       {
-         x = force_not_mem (x);
-         y = x;
-       }
-      else
-       {
-         x = force_not_mem (x);
-         y = force_not_mem (y);
-       }
-    }
-
   /* If we are inside an appropriately-short loop and we are optimizing,
      force expensive constants into a register.  */
   if (CONSTANT_P (x) && optimize
@@ -3351,9 +3429,9 @@ 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.  */
+  /* 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
 
@@ -3385,6 +3463,8 @@ prepare_cmp_insn (rtx *px, rtx *py, enum rtx_code *pcomparison, rtx size,
          if (cmp_code == CODE_FOR_nothing)
            cmp_code = cmpstr_optab[cmp_mode];
          if (cmp_code == CODE_FOR_nothing)
+           cmp_code = cmpstrn_optab[cmp_mode];
+         if (cmp_code == CODE_FOR_nothing)
            continue;
 
          /* Must make sure the size fits the insn's mode.  */
@@ -3600,9 +3680,8 @@ emit_cmp_and_jump_insns (rtx x, rtx y, enum rtx_code comparison, rtx size,
     }
 
 #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
@@ -3827,12 +3906,6 @@ emit_conditional_move (rtx target, enum rtx_code code, rtx op0, rtx op1,
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  if (flag_force_mem)
-    {
-      op2 = force_not_mem (op2);
-      op3 = force_not_mem (op3);
-    }
-
   if (!target)
     target = gen_reg_rtx (mode);
 
@@ -3961,12 +4034,6 @@ emit_conditional_add (rtx target, enum rtx_code code, rtx op0, rtx op1,
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  if (flag_force_mem)
-    {
-      op2 = force_not_mem (op2);
-      op3 = force_not_mem (op3);
-    }
-
   if (!target)
     target = gen_reg_rtx (mode);
 
@@ -4290,9 +4357,6 @@ expand_float (rtx to, rtx from, int unsignedp)
       rtx temp;
       REAL_VALUE_TYPE offset;
 
-      if (flag_force_mem)
-       from = force_not_mem (from);
-
       /* Look for a usable floating mode FMODE wider than the source and at
         least as wide as the target.  Using FMODE will avoid rounding woes
         with unsigned values greater than the signed maximum value.  */
@@ -4400,9 +4464,6 @@ expand_float (rtx to, rtx from, int unsignedp)
       if (GET_MODE_SIZE (GET_MODE (from)) < GET_MODE_SIZE (SImode))
        from = convert_to_mode (SImode, from, unsignedp);
 
-      if (flag_force_mem)
-       from = force_not_mem (from);
-
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
       gcc_assert (libfunc);
 
@@ -4520,9 +4581,6 @@ expand_fix (rtx to, rtx from, int unsignedp)
          lab1 = gen_label_rtx ();
          lab2 = gen_label_rtx ();
 
-         if (flag_force_mem)
-           from = force_not_mem (from);
-
          if (fmode != GET_MODE (from))
            from = convert_to_mode (fmode, from, 0);
 
@@ -4589,9 +4647,6 @@ expand_fix (rtx to, rtx from, int unsignedp)
       libfunc = tab->handlers[GET_MODE (to)][GET_MODE (from)].libfunc;
       gcc_assert (libfunc);
 
-      if (flag_force_mem)
-       from = force_not_mem (from);
-
       start_sequence ();
 
       value = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
@@ -5042,9 +5097,18 @@ init_optabs (void)
   cstore_optab = init_optab (UNKNOWN);
   push_optab = init_optab (UNKNOWN);
 
+  reduc_smax_optab = init_optab (UNKNOWN);
+  reduc_umax_optab = init_optab (UNKNOWN);
+  reduc_smin_optab = init_optab (UNKNOWN);
+  reduc_umin_optab = init_optab (UNKNOWN);
+  reduc_splus_optab = init_optab (UNKNOWN);
+  reduc_uplus_optab = init_optab (UNKNOWN);
+
   vec_extract_optab = init_optab (UNKNOWN);
   vec_set_optab = init_optab (UNKNOWN);
   vec_init_optab = init_optab (UNKNOWN);
+  vec_shl_optab = init_optab (UNKNOWN);
+  vec_shr_optab = init_optab (UNKNOWN);
   vec_realign_load_optab = init_optab (UNKNOWN);
   movmisalign_optab = init_optab (UNKNOWN);
 
@@ -5064,9 +5128,10 @@ init_optabs (void)
   for (i = 0; i < NUM_MACHINE_MODES; i++)
     {
       movmem_optab[i] = CODE_FOR_nothing;
-      clrmem_optab[i] = CODE_FOR_nothing;
       cmpstr_optab[i] = CODE_FOR_nothing;
+      cmpstrn_optab[i] = CODE_FOR_nothing;
       cmpmem_optab[i] = CODE_FOR_nothing;
+      setmem_optab[i] = CODE_FOR_nothing;
 
       sync_add_optab[i] = CODE_FOR_nothing;
       sync_sub_optab[i] = CODE_FOR_nothing;
@@ -5190,9 +5255,6 @@ init_optabs (void)
   memset_libfunc = init_one_libfunc ("memset");
   setbits_libfunc = init_one_libfunc ("__setbits");
 
-  unwind_resume_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS
-                                           ? "_Unwind_SjLj_Resume"
-                                           : "_Unwind_Resume");
 #ifndef DONT_USE_BUILTIN_SETJMP
   setjmp_libfunc = init_one_libfunc ("__builtin_setjmp");
   longjmp_libfunc = init_one_libfunc ("__builtin_longjmp");
@@ -5251,7 +5313,7 @@ debug_optab_libfuncs (void)
       }
 
   /* Dump the conversion optabs.  */
-  for (i = 0; i < (int) CTI_MAX; ++i)
+  for (i = 0; i < (int) COI_MAX; ++i)
     for (j = 0; j < NUM_MACHINE_MODES; ++j)
       for (k = 0; k < NUM_MACHINE_MODES; ++k)
        {
@@ -5346,7 +5408,7 @@ get_rtx_code (enum tree_code tcode, bool unsignedp)
     case GE_EXPR:
       code = unsignedp ? GEU : GE;
       break;
-      
+
     case UNORDERED_EXPR:
       code = UNORDERED;
       break;
@@ -5392,10 +5454,10 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
      ensures that condition is a relational operation.  */
   gcc_assert (COMPARISON_CLASS_P (cond));
 
-  rcode = get_rtx_code (TREE_CODE (cond), unsignedp); 
+  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);
@@ -5403,7 +5465,7 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
   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);
@@ -5412,8 +5474,8 @@ vector_compare_rtx (tree cond, bool unsignedp, enum insn_code icode)
 }
 
 /* Return insn code for VEC_COND_EXPR EXPR.  */
-  
-static inline enum insn_code 
+
+static inline enum insn_code
 get_vcond_icode (tree expr, enum machine_mode mode)
 {
   enum insn_code icode = CODE_FOR_nothing;
@@ -5450,11 +5512,11 @@ expand_vec_cond_expr (tree vec_cond_expr, rtx target)
   if (icode == CODE_FOR_nothing)
     return 0;
 
-  if (!target)
+  if (!target || !insn_data[icode].operand[0].predicate (target, mode))
     target = gen_reg_rtx (mode);
 
   /* Get comparison rtx.  First expand both cond expr operands.  */
-  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0), 
+  comparison = vector_compare_rtx (TREE_OPERAND (vec_cond_expr, 0),
                                   unsignedp, icode);
   cc_op0 = XEXP (comparison, 0);
   cc_op1 = XEXP (comparison, 1);
@@ -5472,7 +5534,7 @@ expand_vec_cond_expr (tree vec_cond_expr, rtx target)
     rtx_op2 = force_reg (mode, rtx_op2);
 
   /* Emit instruction! */
-  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2, 
+  emit_insn (GEN_FCN (icode) (target, rtx_op1, rtx_op2,
                              comparison, cc_op0,  cc_op1));
 
   return target;
@@ -5558,7 +5620,7 @@ expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
 
       /* Ensure that if old_val == mem, that we're not comparing
         against an old value.  */
-      if (GET_CODE (old_val) == MEM)
+      if (MEM_P (old_val))
        old_val = force_reg (mode, old_val);
 
       subtarget = expand_val_compare_and_swap_1 (mem, old_val, new_val,
@@ -5598,8 +5660,8 @@ expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
        }
     }
 
-  /* Without an appropriate setcc instruction, use a set of branches to 
-     get 1 and 0 stored into target.  Presumably if the target has a 
+  /* 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 ();
@@ -5608,6 +5670,7 @@ expand_bool_compare_and_swap (rtx mem, rtx old_val, rtx new_val, rtx target)
   emit_jump_insn (bcc_gen_fctn[EQ] (label0));
   emit_move_insn (target, const0_rtx);
   emit_jump_insn (gen_jump (label1));
+  emit_barrier ();
   emit_label (label0);
   emit_move_insn (target, const1_rtx);
   emit_label (label1);
@@ -5629,24 +5692,27 @@ 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, subtarget;
+  rtx label, cmp_reg, subtarget;
 
   /* The loop we want to generate looks like
 
-       old_reg = mem;
+       cmp_reg = mem;
       label:
+        old_reg = cmp_reg;
        seq;
-       old_reg = compare-and-swap(mem, old_reg, new_reg)
-       if (old_reg != new_reg)
+       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 (old_reg, mem);
+  emit_move_insn (cmp_reg, mem);
   emit_label (label);
+  emit_move_insn (old_reg, cmp_reg);
   if (seq)
     emit_insn (seq);
 
@@ -5658,9 +5724,12 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
     {
     default:
       subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
-                                                old_reg, icode);
+                                                cmp_reg, icode);
       if (subtarget != NULL_RTX)
-       break;
+       {
+         gcc_assert (subtarget == cmp_reg);
+         break;
+       }
 
       /* FALLTHRU */
     case CODE_FOR_nothing:
@@ -5669,11 +5738,13 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
        return false;
 
       subtarget = expand_val_compare_and_swap_1 (mem, old_reg, new_reg,
-                                                old_reg, icode);
+                                                cmp_reg, icode);
       if (subtarget == NULL_RTX)
        return false;
+      if (subtarget != cmp_reg)
+       emit_move_insn (cmp_reg, subtarget);
 
-      emit_cmp_insn (subtarget, old_reg, EQ, const0_rtx, mode, true);
+      emit_cmp_insn (cmp_reg, old_reg, EQ, const0_rtx, mode, true);
     }
 
   /* ??? Mark this jump predicted not taken?  */
@@ -5683,7 +5754,7 @@ expand_compare_and_swap_loop (rtx mem, rtx old_reg, rtx new_reg, rtx seq)
 }
 
 /* This function generates the atomic operation MEM CODE= VAL.  In this
-   case, we do not care about any resulting value.  Returns NULL if we 
+   case, we do not care about any resulting value.  Returns NULL if we
    cannot generate the operation.  */
 
 rtx
@@ -5736,7 +5807,7 @@ expand_sync_operation (rtx mem, rtx val, enum rtx_code code)
        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)
        {
@@ -5774,7 +5845,7 @@ expand_sync_operation (rtx mem, rtx val, enum rtx_code code)
 
 /* 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 
+   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.  */
 
@@ -5869,7 +5940,7 @@ expand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code,
        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)
        {
@@ -5934,7 +6005,7 @@ expand_sync_fetch_operation (rtx mem, rtx val, enum rtx_code code,
 /* 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 
+   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.  */