OSDN Git Service

In gcc/objc/:
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 9b6fb10..384a81a 100644 (file)
@@ -106,9 +106,9 @@ static void expand_errno_check (tree, rtx);
 static rtx expand_builtin_mathfn (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_2 (tree, rtx, rtx);
 static rtx expand_builtin_mathfn_3 (tree, rtx, rtx);
-static rtx expand_builtin_interclass_mathfn (tree, rtx, rtx);
+static rtx expand_builtin_interclass_mathfn (tree, rtx);
 static rtx expand_builtin_sincos (tree);
-static rtx expand_builtin_cexpi (tree, rtx, rtx);
+static rtx expand_builtin_cexpi (tree, rtx);
 static rtx expand_builtin_int_roundingfn (tree, rtx);
 static rtx expand_builtin_int_roundingfn_2 (tree, rtx);
 static rtx expand_builtin_next_arg (void);
@@ -132,7 +132,7 @@ static rtx expand_builtin_memset (tree, rtx, enum machine_mode);
 static rtx expand_builtin_memset_args (tree, tree, tree, rtx, enum machine_mode, tree);
 static rtx expand_builtin_bzero (tree);
 static rtx expand_builtin_strlen (tree, rtx, enum machine_mode);
-static rtx expand_builtin_alloca (tree, rtx);
+static rtx expand_builtin_alloca (tree, rtx, bool);
 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
 static tree stabilize_va_list_loc (location_t, tree, int);
@@ -267,81 +267,158 @@ called_as_built_in (tree node)
 }
 
 /* Return the alignment in bits of EXP, an object.
-   Don't return more than MAX_ALIGN no matter what, ALIGN is the inital
-   guessed alignment e.g. from type alignment.  */
+   Don't return more than MAX_ALIGN no matter what.  */
 
-int
-get_object_alignment (tree exp, unsigned int align, unsigned int max_align)
+unsigned int
+get_object_alignment (tree exp, unsigned int max_align)
 {
-  unsigned int inner;
-
-  inner = max_align;
-  if (handled_component_p (exp))
-   {
-      HOST_WIDE_INT bitsize, bitpos;
-      tree offset;
-      enum machine_mode mode;
-      int unsignedp, volatilep;
-
-      exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
-                                &mode, &unsignedp, &volatilep, true);
-      if (bitpos)
-       inner = MIN (inner, (unsigned) (bitpos & -bitpos));
-      while (offset)
-       {
-         tree next_offset;
+  HOST_WIDE_INT bitsize, bitpos;
+  tree offset;
+  enum machine_mode mode;
+  int unsignedp, volatilep;
+  unsigned int align, inner;
 
-         if (TREE_CODE (offset) == PLUS_EXPR)
-           {
-             next_offset = TREE_OPERAND (offset, 0);
-             offset = TREE_OPERAND (offset, 1);
-           }
-         else
-           next_offset = NULL;
-         if (host_integerp (offset, 1))
-           {
-             /* Any overflow in calculating offset_bits won't change
-                the alignment.  */
-             unsigned offset_bits
-               = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
+  /* Get the innermost object and the constant (bitpos) and possibly
+     variable (offset) offset of the access.  */
+  exp = get_inner_reference (exp, &bitsize, &bitpos, &offset,
+                            &mode, &unsignedp, &volatilep, true);
 
-             if (offset_bits)
-               inner = MIN (inner, (offset_bits & -offset_bits));
-           }
-         else if (TREE_CODE (offset) == MULT_EXPR
-                  && host_integerp (TREE_OPERAND (offset, 1), 1))
-           {
-             /* Any overflow in calculating offset_factor won't change
-                the alignment.  */
-             unsigned offset_factor
-               = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
-                  * BITS_PER_UNIT);
-
-             if (offset_factor)
-               inner = MIN (inner, (offset_factor & -offset_factor));
-           }
-         else
-           {
-             inner = MIN (inner, BITS_PER_UNIT);
-             break;
-           }
-         offset = next_offset;
-       }
-    }
+  /* Extract alignment information from the innermost object and
+     possibly adjust bitpos and offset.  */
   if (TREE_CODE (exp) == CONST_DECL)
     exp = DECL_INITIAL (exp);
   if (DECL_P (exp)
       && TREE_CODE (exp) != LABEL_DECL)
-    align = MIN (inner, DECL_ALIGN (exp));
-#ifdef CONSTANT_ALIGNMENT
+    align = DECL_ALIGN (exp);
   else if (CONSTANT_CLASS_P (exp))
-    align = MIN (inner, (unsigned)CONSTANT_ALIGNMENT (exp, align));
+    {
+      align = TYPE_ALIGN (TREE_TYPE (exp));
+#ifdef CONSTANT_ALIGNMENT
+      align = (unsigned)CONSTANT_ALIGNMENT (exp, align);
 #endif
-  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR
-          || TREE_CODE (exp) == INDIRECT_REF)
-    align = MIN (TYPE_ALIGN (TREE_TYPE (exp)), inner);
+    }
+  else if (TREE_CODE (exp) == VIEW_CONVERT_EXPR)
+    align = TYPE_ALIGN (TREE_TYPE (exp));
+  else if (TREE_CODE (exp) == INDIRECT_REF)
+    align = TYPE_ALIGN (TREE_TYPE (exp));
+  else if (TREE_CODE (exp) == MEM_REF)
+    {
+      tree addr = TREE_OPERAND (exp, 0);
+      struct ptr_info_def *pi;
+      if (TREE_CODE (addr) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
+       {
+         align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
+                   & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+         align *= BITS_PER_UNIT;
+         addr = TREE_OPERAND (addr, 0);
+       }
+      else
+       align = BITS_PER_UNIT;
+      if (TREE_CODE (addr) == SSA_NAME
+         && (pi = SSA_NAME_PTR_INFO (addr)))
+       {
+         bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
+         align = MAX (pi->align * BITS_PER_UNIT, align);
+       }
+      else if (TREE_CODE (addr) == ADDR_EXPR)
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
+                                                 max_align));
+      bitpos += mem_ref_offset (exp).low * BITS_PER_UNIT;
+    }
+  else if (TREE_CODE (exp) == TARGET_MEM_REF)
+    {
+      struct ptr_info_def *pi;
+      tree addr = TMR_BASE (exp);
+      if (TREE_CODE (addr) == BIT_AND_EXPR
+         && TREE_CODE (TREE_OPERAND (addr, 1)) == INTEGER_CST)
+       {
+         align = (TREE_INT_CST_LOW (TREE_OPERAND (addr, 1))
+                  & -TREE_INT_CST_LOW (TREE_OPERAND (addr, 1)));
+         align *= BITS_PER_UNIT;
+         addr = TREE_OPERAND (addr, 0);
+       }
+      else
+       align = BITS_PER_UNIT;
+      if (TREE_CODE (addr) == SSA_NAME
+         && (pi = SSA_NAME_PTR_INFO (addr)))
+       {
+         bitpos += (pi->misalign * BITS_PER_UNIT) & ~(align - 1);
+         align = MAX (pi->align * BITS_PER_UNIT, align);
+       }
+      else if (TREE_CODE (addr) == ADDR_EXPR)
+       align = MAX (align, get_object_alignment (TREE_OPERAND (addr, 0),
+                                                 max_align));
+      if (TMR_OFFSET (exp))
+       bitpos += TREE_INT_CST_LOW (TMR_OFFSET (exp)) * BITS_PER_UNIT;
+      if (TMR_INDEX (exp) && TMR_STEP (exp))
+       {
+         unsigned HOST_WIDE_INT step = TREE_INT_CST_LOW (TMR_STEP (exp));
+         align = MIN (align, (step & -step) * BITS_PER_UNIT);
+       }
+      else if (TMR_INDEX (exp))
+       align = BITS_PER_UNIT;
+      if (TMR_INDEX2 (exp))
+       align = BITS_PER_UNIT;
+    }
   else
-    align = MIN (align, inner);
+    align = BITS_PER_UNIT;
+
+  /* If there is a non-constant offset part extract the maximum
+     alignment that can prevail.  */
+  inner = max_align;
+  while (offset)
+    {
+      tree next_offset;
+
+      if (TREE_CODE (offset) == PLUS_EXPR)
+       {
+         next_offset = TREE_OPERAND (offset, 0);
+         offset = TREE_OPERAND (offset, 1);
+       }
+      else
+       next_offset = NULL;
+      if (host_integerp (offset, 1))
+       {
+         /* Any overflow in calculating offset_bits won't change
+            the alignment.  */
+         unsigned offset_bits
+           = ((unsigned) tree_low_cst (offset, 1) * BITS_PER_UNIT);
+
+         if (offset_bits)
+           inner = MIN (inner, (offset_bits & -offset_bits));
+       }
+      else if (TREE_CODE (offset) == MULT_EXPR
+              && host_integerp (TREE_OPERAND (offset, 1), 1))
+       {
+         /* Any overflow in calculating offset_factor won't change
+            the alignment.  */
+         unsigned offset_factor
+           = ((unsigned) tree_low_cst (TREE_OPERAND (offset, 1), 1)
+              * BITS_PER_UNIT);
+
+         if (offset_factor)
+           inner = MIN (inner, (offset_factor & -offset_factor));
+       }
+      else
+       {
+         inner = MIN (inner, BITS_PER_UNIT);
+         break;
+       }
+      offset = next_offset;
+    }
+
+  /* Alignment is innermost object alignment adjusted by the constant
+     and non-constant offset parts.  */
+  align = MIN (align, inner);
+  bitpos = bitpos & (align - 1);
+
+  /* align and bitpos now specify known low bits of the pointer.
+     ptr & (align - 1) == bitpos.  */
+
+  if (bitpos != 0)
+    align = (bitpos & -bitpos);
+
   return MIN (align, max_align);
 }
 
@@ -363,56 +440,28 @@ can_trust_pointer_alignment (void)
    Otherwise, look at the expression to see if we can do better, i.e., if the
    expression is actually pointing at an object whose alignment is tighter.  */
 
-int
+unsigned int
 get_pointer_alignment (tree exp, unsigned int max_align)
 {
-  unsigned int align, inner;
-
-  if (!can_trust_pointer_alignment ())
-    return 0;
-
-  if (!POINTER_TYPE_P (TREE_TYPE (exp)))
-    return 0;
-
-  align = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
-  align = MIN (align, max_align);
-
-  while (1)
-    {
-      switch (TREE_CODE (exp))
-       {
-       CASE_CONVERT:
-         exp = TREE_OPERAND (exp, 0);
-         if (! POINTER_TYPE_P (TREE_TYPE (exp)))
-           return align;
-
-         inner = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (exp)));
-         align = MIN (inner, max_align);
-         break;
-
-       case POINTER_PLUS_EXPR:
-         /* If sum of pointer + int, restrict our maximum alignment to that
-            imposed by the integer.  If not, we can't do any better than
-            ALIGN.  */
-         if (! host_integerp (TREE_OPERAND (exp, 1), 1))
-           return align;
-
-         while (((tree_low_cst (TREE_OPERAND (exp, 1), 1))
-                 & (max_align / BITS_PER_UNIT - 1))
-                != 0)
-           max_align >>= 1;
-
-         exp = TREE_OPERAND (exp, 0);
-         break;
-
-       case ADDR_EXPR:
-         /* See what we are pointing at and look at its alignment.  */
-         return get_object_alignment (TREE_OPERAND (exp, 0), align, max_align);
+  STRIP_NOPS (exp);
 
-       default:
-         return align;
-       }
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    return get_object_alignment (TREE_OPERAND (exp, 0), max_align);
+  else if (TREE_CODE (exp) == SSA_NAME
+          && POINTER_TYPE_P (TREE_TYPE (exp)))
+    {
+      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (exp);
+      unsigned align;
+      if (!pi)
+       return BITS_PER_UNIT;
+      if (pi->misalign != 0)
+       align = (pi->misalign & -pi->misalign);
+      else
+       align = pi->align;
+      return MIN (max_align, align * BITS_PER_UNIT);
     }
+
+  return POINTER_TYPE_P (TREE_TYPE (exp)) ? BITS_PER_UNIT : 0;
 }
 
 /* Compute the length of a C string.  TREE_STRING_LENGTH is not the right
@@ -1520,8 +1569,10 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
     emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
 
   /* Allocate a block of memory onto the stack and copy the memory
-     arguments to the outgoing arguments address.  */
-  allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT);
+     arguments to the outgoing arguments address.  We can pass TRUE
+     as the 4th argument because we just saved the stack pointer
+     and will restore it right after the call.  */
+  allocate_dynamic_stack_space (argsize, 0, BITS_PER_UNIT, TRUE);
 
   /* Set DRAP flag to true, even though allocate_dynamic_stack_space
      may have already set current_function_calls_alloca to true.
@@ -2287,11 +2338,10 @@ interclass_mathfn_icode (tree arg, tree fndecl)
    isnan, etc).
    Return 0 if a normal call should be emitted rather than expanding the
    function in-line.  EXP is the expression that is a call to the builtin
-   function; if convenient, the result should be placed in TARGET.
-   SUBTARGET may be used as the target for computing one of EXP's operands.  */
+   function; if convenient, the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
+expand_builtin_interclass_mathfn (tree exp, rtx target)
 {
   enum insn_code icode = CODE_FOR_nothing;
   rtx op0;
@@ -2324,7 +2374,7 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
         side-effects more the once.  */
       CALL_EXPR_ARG (exp, 0) = arg = builtin_save_expr (arg);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
+      op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       if (mode != GET_MODE (op0))
        op0 = convert_to_mode (mode, op0, 0);
@@ -2391,11 +2441,10 @@ expand_builtin_sincos (tree exp)
 
 /* Expand a call to the internal cexpi builtin to the sincos math function.
    EXP is the expression that is a call to the builtin function; if convenient,
-   the result should be placed in TARGET.  SUBTARGET may be used as the target
-   for computing one of EXP's operands.  */
+   the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
+expand_builtin_cexpi (tree exp, rtx target)
 {
   tree fndecl = get_callee_fndecl (exp);
   tree arg, type;
@@ -2418,7 +2467,7 @@ expand_builtin_cexpi (tree exp, rtx target, rtx subtarget)
       op1 = gen_reg_rtx (mode);
       op2 = gen_reg_rtx (mode);
 
-      op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
+      op0 = expand_expr (arg, NULL_RTX, VOIDmode, EXPAND_NORMAL);
 
       /* Compute into op1 and op2.  */
       expand_twoval_unop (sincos_optab, op0, op2, op1, 0);
@@ -3164,7 +3213,7 @@ expand_builtin_pow (tree exp, rtx target, rtx subtarget)
    function; if convenient, the result should be placed in TARGET.  */
 
 static rtx
-expand_builtin_powi (tree exp, rtx target, rtx subtarget)
+expand_builtin_powi (tree exp, rtx target)
 {
   tree arg0, arg1;
   rtx op0, op1;
@@ -3193,7 +3242,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
              || (optimize_insn_for_speed_p ()
                  && powi_cost (n) <= POWI_MAX_MULTS)))
        {
-         op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
+         op0 = expand_expr (arg0, NULL_RTX, VOIDmode, EXPAND_NORMAL);
          op0 = force_reg (mode, op0);
          return expand_powi (op0, mode, n);
        }
@@ -3207,7 +3256,7 @@ expand_builtin_powi (tree exp, rtx target, rtx subtarget)
   if (target == NULL_RTX)
     target = gen_reg_rtx (mode);
 
-  op0 = expand_expr (arg0, subtarget, mode, EXPAND_NORMAL);
+  op0 = expand_expr (arg0, NULL_RTX, mode, EXPAND_NORMAL);
   if (GET_MODE (op0) != mode)
     op0 = convert_to_mode (mode, op0, 0);
   op1 = expand_expr (arg1, NULL_RTX, mode2, EXPAND_NORMAL);
@@ -3239,7 +3288,7 @@ expand_builtin_strlen (tree exp, rtx target,
       rtx result, src_reg, char_rtx, before_strlen;
       enum machine_mode insn_mode = target_mode, char_mode;
       enum insn_code icode = CODE_FOR_nothing;
-      int align;
+      unsigned int align;
 
       /* If the length can be computed at compile-time, return it.  */
       len = c_strlen (src, 0);
@@ -4012,9 +4061,9 @@ expand_builtin_memcmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree len = CALL_EXPR_ARG (exp, 2);
 
-    int arg1_align
+    unsigned int arg1_align
       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    int arg2_align
+    unsigned int arg2_align
       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
     enum machine_mode insn_mode;
 
@@ -4114,9 +4163,9 @@ expand_builtin_strcmp (tree exp, ATTRIBUTE_UNUSED rtx target)
       tree arg1 = CALL_EXPR_ARG (exp, 0);
       tree arg2 = CALL_EXPR_ARG (exp, 1);
 
-      int arg1_align
+      unsigned int arg1_align
        = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-      int arg2_align
+      unsigned int arg2_align
        = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
 
       /* If we don't have POINTER_TYPE, call the function.  */
@@ -4265,9 +4314,9 @@ expand_builtin_strncmp (tree exp, ATTRIBUTE_UNUSED rtx target,
     tree arg2 = CALL_EXPR_ARG (exp, 1);
     tree arg3 = CALL_EXPR_ARG (exp, 2);
 
-    int arg1_align
+    unsigned int arg1_align
       = get_pointer_alignment (arg1, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
-    int arg2_align
+    unsigned int arg2_align
       = get_pointer_alignment (arg2, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
     enum machine_mode insn_mode
       = insn_data[(int) CODE_FOR_cmpstrnsi].operand[0].mode;
@@ -4671,7 +4720,7 @@ static tree
 dummy_object (tree type)
 {
   tree t = build_int_cst (build_pointer_type (type), 0);
-  return build1 (INDIRECT_REF, type, t);
+  return build2 (MEM_REF, type, t, t);
 }
 
 /* Gimplify __builtin_va_arg, aka VA_ARG_EXPR, which is not really a
@@ -4881,12 +4930,13 @@ expand_builtin_frame_address (tree fndecl, tree exp)
     }
 }
 
-/* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if
-   we failed and the caller should emit a normal call, otherwise try to get
-   the result in TARGET, if convenient.  */
+/* Expand EXP, a call to the alloca builtin.  Return NULL_RTX if we
+   failed and the caller should emit a normal call, otherwise try to
+   get the result in TARGET, if convenient.  CANNOT_ACCUMULATE is the
+   same as for allocate_dynamic_stack_space.  */
 
 static rtx
-expand_builtin_alloca (tree exp, rtx target)
+expand_builtin_alloca (tree exp, rtx target, bool cannot_accumulate)
 {
   rtx op0;
   rtx result;
@@ -4902,7 +4952,8 @@ expand_builtin_alloca (tree exp, rtx target)
   op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
 
   /* Allocate the desired space.  */
-  result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
+  result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT,
+                                        cannot_accumulate);
   result = convert_memory_address (ptr_mode, result);
 
   return result;
@@ -4947,7 +4998,10 @@ expand_builtin_unop (enum machine_mode target_mode, tree exp, rtx target,
     return NULL_RTX;
 
   /* Compute the argument.  */
-  op0 = expand_expr (CALL_EXPR_ARG (exp, 0), subtarget,
+  op0 = expand_expr (CALL_EXPR_ARG (exp, 0),
+                    (subtarget
+                     && (TYPE_MODE (TREE_TYPE (CALL_EXPR_ARG (exp, 0)))
+                         == GET_MODE (subtarget))) ? subtarget : NULL_RTX,
                     VOIDmode, EXPAND_NORMAL);
   /* Compute op, into TARGET if possible.
      Set TARGET to wherever the result comes back.  */
@@ -5451,7 +5505,9 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode)
      satisfy the full barrier semantics of the intrinsic.  */
   mem = validize_mem (gen_rtx_MEM (mode, addr));
 
-  set_mem_align (mem, get_pointer_alignment (loc, BIGGEST_ALIGNMENT));
+  /* The alignment needs to be at least according to that of the mode.  */
+  set_mem_align (mem, MAX (GET_MODE_ALIGNMENT (mode),
+                          get_pointer_alignment (loc, BIGGEST_ALIGNMENT)));
   set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
   MEM_VOLATILE_P (mem) = 1;
 
@@ -5678,6 +5734,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
   tree fndecl = get_callee_fndecl (exp);
   enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
   enum machine_mode target_mode = TYPE_MODE (TREE_TYPE (exp));
+  int flags;
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
@@ -5700,7 +5757,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
      none of its arguments are volatile, we can avoid expanding the
      built-in call and just evaluate the arguments for side-effects.  */
   if (target == const0_rtx
-      && (DECL_PURE_P (fndecl) || TREE_READONLY (fndecl)))
+      && ((flags = flags_from_decl_or_type (fndecl)) & (ECF_CONST | ECF_PURE))
+      && !(flags & ECF_LOOPING_CONST_OR_PURE))
     {
       bool volatilep = false;
       tree arg;
@@ -5778,7 +5836,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     CASE_FLT_FN (BUILT_IN_FINITE):
     case BUILT_IN_ISFINITE:
     case BUILT_IN_ISNORMAL:
-      target = expand_builtin_interclass_mathfn (exp, target, subtarget);
+      target = expand_builtin_interclass_mathfn (exp, target);
       if (target)
        return target;
       break;
@@ -5808,7 +5866,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_POWI):
-      target = expand_builtin_powi (exp, target, subtarget);
+      target = expand_builtin_powi (exp, target);
       if (target)
        return target;
       break;
@@ -5830,7 +5888,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     CASE_FLT_FN (BUILT_IN_CEXPI):
-      target = expand_builtin_cexpi (exp, target, subtarget);
+      target = expand_builtin_cexpi (exp, target);
       gcc_assert (target);
       return target;
 
@@ -5937,7 +5995,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
     case BUILT_IN_ALLOCA:
-      target = expand_builtin_alloca (exp, target);
+      /* If the allocation stems from the declaration of a variable-sized
+        object, it cannot accumulate.  */
+      target = expand_builtin_alloca (exp, target, ALLOCA_FOR_VAR_P (exp));
       if (target)
        return target;
       break;
@@ -7676,9 +7736,9 @@ fold_builtin_bitop (tree fndecl, tree arg)
        {
        CASE_INT_FN (BUILT_IN_FFS):
          if (lo != 0)
-           result = exact_log2 (lo & -lo) + 1;
+           result = ffs_hwi (lo);
          else if (hi != 0)
-           result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi) + 1;
+           result = HOST_BITS_PER_WIDE_INT + ffs_hwi (hi);
          else
            result = 0;
          break;
@@ -7694,9 +7754,9 @@ fold_builtin_bitop (tree fndecl, tree arg)
 
        CASE_INT_FN (BUILT_IN_CTZ):
          if (lo != 0)
-           result = exact_log2 (lo & -lo);
+           result = ctz_hwi (lo);
          else if (hi != 0)
-           result = HOST_BITS_PER_WIDE_INT + exact_log2 (hi & -hi);
+           result = HOST_BITS_PER_WIDE_INT + ctz_hwi (hi);
          else if (! CTZ_DEFINED_VALUE_AT_ZERO (TYPE_MODE (type), result))
            result = width;
          break;
@@ -7706,7 +7766,7 @@ fold_builtin_bitop (tree fndecl, tree arg)
          while (lo)
            result++, lo &= lo - 1;
          while (hi)
-           result++, hi &= hi - 1;
+           result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
          break;
 
        CASE_INT_FN (BUILT_IN_PARITY):
@@ -7714,7 +7774,7 @@ fold_builtin_bitop (tree fndecl, tree arg)
          while (lo)
            result++, lo &= lo - 1;
          while (hi)
-           result++, hi &= hi - 1;
+           result++, hi &= (unsigned HOST_WIDE_INT) hi - 1;
          result &= 1;
          break;
 
@@ -8226,7 +8286,7 @@ fold_builtin_memset (location_t loc, tree dest, tree c, tree len,
   length = tree_low_cst (len, 1);
   if (GET_MODE_SIZE (TYPE_MODE (etype)) != length
       || get_pointer_alignment (dest, BIGGEST_ALIGNMENT) / BITS_PER_UNIT
-        < (int) length)
+        < length)
     return NULL_TREE;
 
   if (length > HOST_BITS_PER_WIDE_INT / BITS_PER_UNIT)
@@ -8311,7 +8371,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
   else
     {
       tree srctype, desttype;
-      int src_align, dest_align;
+      unsigned int src_align, dest_align;
       tree off0;
 
       if (endp == 3)
@@ -8329,7 +8389,7 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
          if (readonly_data_expr (src)
              || (host_integerp (len, 1)
                  && (MIN (src_align, dest_align) / BITS_PER_UNIT
-                     >= tree_low_cst (len, 1))))
+                     >= (unsigned HOST_WIDE_INT) tree_low_cst (len, 1))))
            {
              tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
              if (!fn)
@@ -8395,6 +8455,27 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
                return NULL_TREE;
              return build_call_expr_loc (loc, fn, 3, dest, src, len);
            }
+
+         /* If the destination and source do not alias optimize into
+            memcpy as well.  */
+         if ((is_gimple_min_invariant (dest)
+              || TREE_CODE (dest) == SSA_NAME)
+             && (is_gimple_min_invariant (src)
+                 || TREE_CODE (src) == SSA_NAME))
+           {
+             ao_ref destr, srcr;
+             ao_ref_init_from_ptr_and_size (&destr, dest, len);
+             ao_ref_init_from_ptr_and_size (&srcr, src, len);
+             if (!refs_may_alias_p_1 (&destr, &srcr, false))
+               {
+                 tree fn;
+                 fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+                 if (!fn)
+                   return NULL_TREE;
+                 return build_call_expr_loc (loc, fn, 3, dest, src, len);
+               }
+           }
+
          return NULL_TREE;
        }
 
@@ -8450,8 +8531,8 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
 
       src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT);
       dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
-      if (dest_align < (int) TYPE_ALIGN (desttype)
-         || src_align < (int) TYPE_ALIGN (srctype))
+      if (dest_align < TYPE_ALIGN (desttype)
+         || src_align < TYPE_ALIGN (srctype))
        return NULL_TREE;
 
       if (!ignore)
@@ -8475,8 +8556,20 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       if (TREE_CODE (srcvar) == ADDR_EXPR
          && var_decl_component_p (TREE_OPERAND (srcvar, 0))
          && tree_int_cst_equal (TYPE_SIZE_UNIT (srctype), len))
-       srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
-                             srcvar, off0);
+       {
+         if (!destvar
+             || src_align >= TYPE_ALIGN (desttype))
+           srcvar = fold_build2 (MEM_REF, destvar ? desttype : srctype,
+                                 srcvar, off0);
+         else if (!STRICT_ALIGNMENT)
+           {
+             srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
+                                           src_align);
+             srcvar = fold_build2 (MEM_REF, srctype, srcvar, off0);
+           }
+         else
+           srcvar = NULL_TREE;
+       }
       else
        srcvar = NULL_TREE;
 
@@ -8486,12 +8579,30 @@ fold_builtin_memory_op (location_t loc, tree dest, tree src,
       if (srcvar == NULL_TREE)
        {
          STRIP_NOPS (src);
-         srcvar = fold_build2 (MEM_REF, desttype, src, off0);
+         if (src_align >= TYPE_ALIGN (desttype))
+           srcvar = fold_build2 (MEM_REF, desttype, src, off0);
+         else
+           {
+             if (STRICT_ALIGNMENT)
+               return NULL_TREE;
+             srctype = build_aligned_type (TYPE_MAIN_VARIANT (desttype),
+                                           src_align);
+             srcvar = fold_build2 (MEM_REF, srctype, src, off0);
+           }
        }
       else if (destvar == NULL_TREE)
        {
          STRIP_NOPS (dest);
-         destvar = fold_build2 (MEM_REF, srctype, dest, off0);
+         if (dest_align >= TYPE_ALIGN (srctype))
+           destvar = fold_build2 (MEM_REF, srctype, dest, off0);
+         else
+           {
+             if (STRICT_ALIGNMENT)
+               return NULL_TREE;
+             desttype = build_aligned_type (TYPE_MAIN_VARIANT (srctype),
+                                            dest_align);
+             destvar = fold_build2 (MEM_REF, desttype, dest, off0);
+           }
        }
 
       expr = build2 (MODIFY_EXPR, TREE_TYPE (destvar), destvar, srcvar);
@@ -11517,9 +11628,7 @@ fold_builtin_next_arg (tree exp, bool va_start_p)
   int nargs = call_expr_nargs (exp);
   tree arg;
 
-  if (TYPE_ARG_TYPES (fntype) == 0
-      || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-         == void_type_node))
+  if (!stdarg_p (fntype))
     {
       error ("%<va_start%> used in function with fixed args");
       return true;