OSDN Git Service

PR target/6838
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index e3adb05..a686c8d 100644 (file)
@@ -22,6 +22,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "config.h"
 #include "system.h"
 #include "machmode.h"
+#include "real.h"
 #include "rtl.h"
 #include "tree.h"
 #include "obstack.h"
@@ -41,6 +42,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "predict.h"
 #include "tm_p.h"
 #include "target.h"
+#include "langhooks.h"
 
 #define CALLED_AS_BUILT_IN(NODE) \
    (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
@@ -72,8 +74,6 @@ const char *const built_in_names[(int) END_BUILTINS] =
    initialized to NULL_TREE.  */
 tree built_in_decls[(int) END_BUILTINS];
 
-tree (*lang_type_promotes_to) PARAMS ((tree));
-
 static int get_pointer_alignment       PARAMS ((tree, unsigned int));
 static tree c_strlen                   PARAMS ((tree));
 static const char *c_getstr            PARAMS ((tree));
@@ -102,7 +102,7 @@ static rtx expand_builtin_va_start  PARAMS ((int, tree));
 static rtx expand_builtin_va_end       PARAMS ((tree));
 static rtx expand_builtin_va_copy      PARAMS ((tree));
 static rtx expand_builtin_memcmp       PARAMS ((tree, tree, rtx,
-                                                 enum machine_mode));
+                                                enum machine_mode));
 static rtx expand_builtin_strcmp       PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_strncmp      PARAMS ((tree, rtx,
@@ -118,17 +118,19 @@ static rtx expand_builtin_strspn  PARAMS ((tree, rtx,
 static rtx expand_builtin_strcspn      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx expand_builtin_memcpy       PARAMS ((tree, rtx,
-                                                 enum machine_mode));
+                                                enum machine_mode));
 static rtx expand_builtin_strcpy       PARAMS ((tree, rtx,
-                                                 enum machine_mode));
+                                                enum machine_mode));
 static rtx builtin_strncpy_read_str    PARAMS ((PTR, HOST_WIDE_INT,
                                                 enum machine_mode));
 static rtx expand_builtin_strncpy      PARAMS ((tree, rtx,
                                                 enum machine_mode));
 static rtx builtin_memset_read_str     PARAMS ((PTR, HOST_WIDE_INT,
                                                 enum machine_mode));
+static rtx builtin_memset_gen_str      PARAMS ((PTR, HOST_WIDE_INT,
+                                                enum machine_mode));
 static rtx expand_builtin_memset       PARAMS ((tree, rtx,
-                                                 enum machine_mode));
+                                                enum machine_mode));
 static rtx expand_builtin_bzero                PARAMS ((tree));
 static rtx expand_builtin_strlen       PARAMS ((tree, rtx));
 static rtx expand_builtin_strstr       PARAMS ((tree, rtx,
@@ -511,7 +513,7 @@ expand_builtin_setjmp_setup (buf_addr, receiver_label)
 
 void
 expand_builtin_setjmp_receiver (receiver_label)
-      rtx receiver_label ATTRIBUTE_UNUSED;
+     rtx receiver_label ATTRIBUTE_UNUSED;
 {
   /* Clobber the FP when we get here, so we have to make sure it's
      marked as used by this function.  */
@@ -639,7 +641,7 @@ void
 expand_builtin_longjmp (buf_addr, value)
      rtx buf_addr, value;
 {
-  rtx fp, lab, stack, insn;
+  rtx fp, lab, stack, insn, last;
   enum machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
 
   if (setjmp_alias_set == -1)
@@ -662,6 +664,7 @@ expand_builtin_longjmp (buf_addr, value)
 
   current_function_calls_longjmp = 1;
 
+  last = get_last_insn ();
 #ifdef HAVE_builtin_longjmp
   if (HAVE_builtin_longjmp)
     emit_insn (gen_builtin_longjmp (buf_addr));
@@ -707,6 +710,8 @@ expand_builtin_longjmp (buf_addr, value)
      internal exception handling use only.  */
   for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
     {
+      if (insn == last)
+       abort ();
       if (GET_CODE (insn) == JUMP_INSN)
        {
          REG_NOTES (insn) = alloc_EXPR_LIST (REG_NON_LOCAL_GOTO, const0_rtx,
@@ -714,7 +719,7 @@ expand_builtin_longjmp (buf_addr, value)
          break;
        }
       else if (GET_CODE (insn) == CALL_INSN)
-        break;
+       break;
     }
 }
 
@@ -740,7 +745,7 @@ expand_builtin_prefetch (arglist)
     {
       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
       if (TREE_CHAIN (TREE_CHAIN (arglist)))
-        arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
       else
        arg2 = build_int_2 (3, 0);
     }
@@ -756,8 +761,8 @@ expand_builtin_prefetch (arglist)
   /* Argument 1 (read/write flag) must be a compile-time constant int.  */
   if (TREE_CODE (arg1) != INTEGER_CST)
     {
-       error ("second arg to `__builtin_prefetch' must be a constant");
-       arg1 = integer_zero_node;
+      error ("second arg to `__builtin_prefetch' must be a constant");
+      arg1 = integer_zero_node;
     }
   op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
   /* Argument 1 must be either zero or one.  */
@@ -784,10 +789,17 @@ expand_builtin_prefetch (arglist)
 #ifdef HAVE_prefetch
   if (HAVE_prefetch)
     {
-      if (! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
-           (op0,
-            insn_data[(int)CODE_FOR_prefetch].operand[0].mode))
-        op0 = force_reg (Pmode, op0);
+      if ((! (*insn_data[(int)CODE_FOR_prefetch].operand[0].predicate)
+            (op0,
+             insn_data[(int)CODE_FOR_prefetch].operand[0].mode)) ||
+         (GET_MODE(op0) != Pmode))
+       {
+#ifdef POINTERS_EXTEND_UNSIGNED
+         if (GET_MODE(op0) != Pmode)
+           op0 = convert_memory_address (Pmode, op0);
+#endif
+         op0 = force_reg (Pmode, op0);
+       }
       emit_insn (gen_prefetch (op0, op1, op2));
     }
   else
@@ -1470,6 +1482,7 @@ expand_builtin_mathfn (exp, target, subtarget)
   rtx op0, insns;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode argmode;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
@@ -1518,8 +1531,8 @@ expand_builtin_mathfn (exp, target, subtarget)
 
   /* Compute into TARGET.
      Set TARGET to wherever the result comes back.  */
-  target = expand_unop (TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist))),
-                       builtin_optab, op0, target, 0);
+  argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
+  target = expand_unop (argmode, builtin_optab, op0, target, 0);
 
   /* If we were unable to expand via the builtin, stop the
      sequence (without outputting the insns) and return 0, causing
@@ -1530,18 +1543,12 @@ expand_builtin_mathfn (exp, target, subtarget)
       return 0;
     }
 
-  /* If errno must be maintained and if we are not allowing unsafe
-     math optimizations, check the result.  */
+  /* If errno must be maintained, we must set it to EDOM for NaN results.  */
 
-  if (flag_errno_math && ! flag_unsafe_math_optimizations)
+  if (flag_errno_math && HONOR_NANS (argmode))
     {
       rtx lab1;
 
-      /* Don't define the builtin FP instructions
-        if your machine is not IEEE.  */
-      if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
-       abort ();
-
       lab1 = gen_label_rtx ();
 
       /* Test the result; if it is NaN, set errno=EDOM because
@@ -1550,16 +1557,16 @@ expand_builtin_mathfn (exp, target, subtarget)
                               0, lab1);
 
 #ifdef TARGET_EDOM
-       {
+      {
 #ifdef GEN_ERRNO_RTX
-         rtx errno_rtx = GEN_ERRNO_RTX;
+       rtx errno_rtx = GEN_ERRNO_RTX;
 #else
-         rtx errno_rtx
-           = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
+       rtx errno_rtx
+         = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
 #endif
 
-         emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
-       }
+       emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
+      }
 #else
       /* We can't set errno=EDOM directly; let the library call do it.
         Pop the arguments right away in case the call gets deleted.  */
@@ -1942,20 +1949,20 @@ expand_builtin_memcpy (arglist, target, mode)
 
       /* If DEST is not a pointer type, call the normal function.  */
       if (dest_align == 0)
-        return 0;
+       return 0;
 
       /* If the LEN parameter is zero, return DEST.  */
       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
-        {
-          /* Evaluate and ignore SRC in case it has side-effects.  */
-          expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
-          return expand_expr (dest, target, mode, EXPAND_NORMAL);
-        }
+       {
+         /* Evaluate and ignore SRC in case it has side-effects.  */
+         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (dest, target, mode, EXPAND_NORMAL);
+       }
 
       /* If either SRC is not a pointer type, don't do this
          operation in-line.  */
       if (src_align == 0)
-        return 0;
+       return 0;
 
       dest_mem = get_memory_rtx (dest);
       set_mem_align (dest_mem, dest_align);
@@ -2018,7 +2025,7 @@ expand_builtin_strcpy (exp, target, mode)
   len = size_binop (PLUS_EXPR, len, ssize_int (1));
   chainon (arglist, build_tree_list (NULL_TREE, len));
   return expand_expr (build_function_call_expr (fn, arglist),
-                      target, mode, EXPAND_NORMAL);
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Callback routine for store_by_pieces.  Read GET_MODE_BITSIZE (MODE)
@@ -2063,9 +2070,9 @@ expand_builtin_strncpy (arglist, target, mode)
 
       /* If the len parameter is zero, return the dst parameter.  */
       if (integer_zerop (len))
-        {
-       /* Evaluate and ignore the src argument in case it has
-           side-effects.  */
+       {
+         /* Evaluate and ignore the src argument in case it has
+            side-effects.  */
          expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
                       VOIDmode, EXPAND_NORMAL);
          /* Return the dst parameter.  */
@@ -2106,9 +2113,9 @@ expand_builtin_strncpy (arglist, target, mode)
       /* OK transform into builtin memcpy.  */
       fn = built_in_decls[BUILT_IN_MEMCPY];
       if (!fn)
-        return 0;
+       return 0;
       return expand_expr (build_function_call_expr (fn, arglist),
-                          target, mode, EXPAND_NORMAL);
+                         target, mode, EXPAND_NORMAL);
     }
 }
 
@@ -2130,6 +2137,34 @@ builtin_memset_read_str (data, offset, mode)
   return c_readstr (p, mode);
 }
 
+/* Callback routine for store_by_pieces.  Return the RTL of a register
+   containing GET_MODE_SIZE (MODE) consecutive copies of the unsigned
+   char value given in the RTL register data.  For example, if mode is
+   4 bytes wide, return the RTL for 0x01010101*data.  */
+
+static rtx
+builtin_memset_gen_str (data, offset, mode)
+     PTR data;
+     HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
+{
+  rtx target, coeff;
+  size_t size;
+  char *p;
+
+  size = GET_MODE_SIZE (mode);
+  if (size==1)
+    return (rtx)data;
+
+  p = alloca (size);
+  memset (p, 1, size);
+  coeff = c_readstr (p, mode);
+
+  target = convert_to_mode (mode, (rtx)data, 1);
+  target = expand_mult (mode, target, coeff, NULL_RTX, 1);
+  return force_reg (mode, target);
+}
+
 /* Expand expression EXP, which is a call to the memset builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient (and in mode MODE if that's
@@ -2164,14 +2199,41 @@ expand_builtin_memset (exp, target, mode)
 
       /* If the LEN parameter is zero, return DEST.  */
       if (host_integerp (len, 1) && tree_low_cst (len, 1) == 0)
-        {
-          /* Evaluate and ignore VAL in case it has side-effects.  */
-          expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
-          return expand_expr (dest, target, mode, EXPAND_NORMAL);
-        }
+       {
+         /* Evaluate and ignore VAL in case it has side-effects.  */
+         expand_expr (val, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (dest, target, mode, EXPAND_NORMAL);
+       }
 
       if (TREE_CODE (val) != INTEGER_CST)
-       return 0;
+       {
+         rtx val_rtx;
+
+         if (!host_integerp (len, 1))
+           return 0;
+
+         if (optimize_size && tree_low_cst (len, 1) > 1)
+           return 0;
+
+         /* Assume that we can memset by pieces if we can store the
+          * the coefficients by pieces (in the required modes).
+          * We can't pass builtin_memset_gen_str as that emits RTL.  */
+         c = 1;
+         if (!can_store_by_pieces (tree_low_cst (len, 1),
+                                   builtin_memset_read_str,
+                                   (PTR) &c, dest_align))
+           return 0;
+
+         val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
+         val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+         val_rtx = force_reg (TYPE_MODE (unsigned_char_type_node),
+                              val_rtx);
+         dest_mem = get_memory_rtx (dest);
+         store_by_pieces (dest_mem, tree_low_cst (len, 1),
+                          builtin_memset_gen_str,
+                          (PTR)val_rtx, dest_align);
+         return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+       }
 
       if (target_char_cast (val, &c))
        return 0;
@@ -2256,7 +2318,7 @@ expand_builtin_memcmp (exp, arglist, target, mode)
   const char *p1, *p2;
 
   if (!validate_arglist (arglist,
-                     POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+                        POINTER_TYPE, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
     return 0;
 
   arg1 = TREE_VALUE (arglist);
@@ -2295,12 +2357,12 @@ expand_builtin_memcmp (exp, arglist, target, mode)
       tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
       tree ind1 =
       fold (build1 (CONVERT_EXPR, integer_type_node,
-                    build1 (INDIRECT_REF, cst_uchar_node,
-                            build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
+                   build1 (INDIRECT_REF, cst_uchar_node,
+                           build1 (NOP_EXPR, cst_uchar_ptr_node, arg1))));
       tree ind2 =
       fold (build1 (CONVERT_EXPR, integer_type_node,
-                    build1 (INDIRECT_REF, cst_uchar_node,
-                            build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
+                   build1 (INDIRECT_REF, cst_uchar_node,
+                           build1 (NOP_EXPR, cst_uchar_ptr_node, arg2))));
       tree result = fold (build (MINUS_EXPR, integer_type_node, ind1, ind2));
       return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -2437,12 +2499,12 @@ expand_builtin_strcmp (exp, target, mode)
   if (!len || TREE_CODE (len) != INTEGER_CST)
     {
       if (len2 && !TREE_SIDE_EFFECTS (len2))
-        len = len2;
+       len = len2;
       else if (len == 0)
-        return 0;
+       return 0;
     }
   else if (len2 && TREE_CODE (len2) == INTEGER_CST
-           && tree_int_cst_lt (len2, len))
+          && tree_int_cst_lt (len2, len))
     len = len2;
 
   /* If both arguments have side effects, we cannot optimize.  */
@@ -2455,7 +2517,7 @@ expand_builtin_strcmp (exp, target, mode)
 
   chainon (arglist, build_tree_list (NULL_TREE, len));
   return expand_expr (build_function_call_expr (fn, arglist),
-                      target, mode, EXPAND_NORMAL);
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Expand expression EXP, which is a call to the strncmp builtin.  Return 0
@@ -2483,23 +2545,23 @@ expand_builtin_strncmp (exp, target, mode)
 
   /* If the len parameter is zero, return zero.  */
   if (host_integerp (arg3, 1) && tree_low_cst (arg3, 1) == 0)
-  {
-    /* Evaluate and ignore arg1 and arg2 in case they have
-       side-effects.  */
-    expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
-    expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
-    return const0_rtx;
-  }
+    {
+      /* Evaluate and ignore arg1 and arg2 in case they have
+        side-effects.  */
+      expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      return const0_rtx;
+    }
 
   p1 = c_getstr (arg1);
   p2 = c_getstr (arg2);
 
   /* If all arguments are constant, evaluate at compile-time.  */
   if (host_integerp (arg3, 1) && p1 && p2)
-  {
-    const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
-    return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
-  }
+    {
+      const int r = strncmp (p1, p2, tree_low_cst (arg3, 1));
+      return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
+    }
 
   /* If len == 1 or (either string parameter is "" and (len >= 1)),
       return (*(const u_char*)arg1 - *(const u_char*)arg2).  */
@@ -2557,7 +2619,7 @@ expand_builtin_strncmp (exp, target, mode)
   newarglist = tree_cons (NULL_TREE, arg2, newarglist);
   newarglist = tree_cons (NULL_TREE, arg1, newarglist);
   return expand_expr (build_function_call_expr (fn, newarglist),
-                      target, mode, EXPAND_NORMAL);
+                     target, mode, EXPAND_NORMAL);
 }
 
 /* Expand expression EXP, which is a call to the strcat builtin.
@@ -2609,7 +2671,7 @@ expand_builtin_strncat (arglist, target, mode)
       /* If the requested length is zero, or the src parameter string
           length is zero, return the dst parameter.  */
       if (integer_zerop (len) || (p && *p == '\0'))
-        {
+       {
          /* Evaluate and ignore the src and len parameters in case
             they have side-effects.  */
          expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2621,7 +2683,7 @@ expand_builtin_strncat (arglist, target, mode)
          length, call strcat.  */
       if (TREE_CODE (len) == INTEGER_CST && p
          && compare_tree_int (len, strlen (p)) >= 0)
-        {
+       {
          tree newarglist
            = tree_cons (NULL_TREE, dst, build_tree_list (NULL_TREE, src));
          tree fn = built_in_decls[BUILT_IN_STRCAT];
@@ -2657,14 +2719,14 @@ expand_builtin_strspn (arglist, target, mode)
 
       /* If both arguments are constants, evaluate at compile-time.  */
       if (p1 && p2)
-        {
+       {
          const size_t r = strspn (p1, p2);
          return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
        }
 
       /* If either argument is "", return 0.  */
       if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
-        {
+       {
          /* Evaluate and ignore both arguments in case either one has
             side-effects.  */
          expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2694,14 +2756,14 @@ expand_builtin_strcspn (arglist, target, mode)
 
       /* If both arguments are constants, evaluate at compile-time.  */
       if (p1 && p2)
-        {
+       {
          const size_t r = strcspn (p1, p2);
          return expand_expr (size_int (r), target, mode, EXPAND_NORMAL);
        }
 
       /* If the first argument is "", return 0.  */
       if (p1 && *p1 == '\0')
-        {
+       {
          /* Evaluate and ignore argument s2 in case it has
             side-effects.  */
          expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2710,7 +2772,7 @@ expand_builtin_strcspn (arglist, target, mode)
 
       /* If the second argument is "", return __builtin_strlen(s1).  */
       if (p2 && *p2 == '\0')
-        {
+       {
          tree newarglist = build_tree_list (NULL_TREE, s1),
            fn = built_in_decls[BUILT_IN_STRLEN];
 
@@ -2991,37 +3053,54 @@ rtx
 std_expand_builtin_va_arg (valist, type)
      tree valist, type;
 {
-  tree addr_tree, t;
-  HOST_WIDE_INT align;
-  HOST_WIDE_INT rounded_size;
+  tree addr_tree, t, type_size = NULL;
+  tree align, alignm1;
+  tree rounded_size;
   rtx addr;
 
   /* Compute the rounded size of the type.  */
-  align = PARM_BOUNDARY / BITS_PER_UNIT;
-  rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
+  align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
+  alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    rounded_size = size_zero_node;
+  else
+    rounded_size = fold (build (MULT_EXPR, sizetype,
+                               fold (build (TRUNC_DIV_EXPR, sizetype,
+                                            fold (build (PLUS_EXPR, sizetype,
+                                                         type_size, alignm1)),
+                                            align)),
+                               align));
 
   /* Get AP.  */
   addr_tree = valist;
-  if (PAD_VARARGS_DOWN)
+  if (PAD_VARARGS_DOWN && ! integer_zerop (rounded_size))
     {
       /* Small args are padded downward.  */
-
-      HOST_WIDE_INT adj
-       = rounded_size > align ? rounded_size : int_size_in_bytes (type);
-
-      addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
-                        build_int_2 (rounded_size - adj, 0));
+      addr_tree = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
+                              fold (build (COND_EXPR, sizetype,
+                                           fold (build (GT_EXPR, sizetype,
+                                                        rounded_size,
+                                                        align)),
+                                           size_zero_node,
+                                           fold (build (MINUS_EXPR, sizetype,
+                                                        rounded_size,
+                                                        type_size))))));
     }
 
   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
 
   /* Compute new value for AP.  */
-  t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-            build (PLUS_EXPR, TREE_TYPE (valist), valist,
-                   build_int_2 (rounded_size, 0)));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (! integer_zerop (rounded_size))
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+                build (PLUS_EXPR, TREE_TYPE (valist), valist,
+                       rounded_size));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
   return addr;
 }
@@ -3061,10 +3140,11 @@ expand_builtin_va_arg (valist, type)
 
   /* Generate a diagnostic for requesting data of a type that cannot
      be passed through `...' due to type promotion at the call site.  */
-  else if ((promoted_type = (*lang_type_promotes_to) (type)) != NULL_TREE)
+  else if ((promoted_type = (*lang_hooks.types.type_promotes_to) (type))
+          != type)
     {
       const char *name = "<anonymous type>", *pname = 0;
-      static int gave_help;
+      static bool gave_help;
 
       if (TYPE_NAME (type))
        {
@@ -3083,13 +3163,24 @@ expand_builtin_va_arg (valist, type)
            pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
        }
 
-      error ("`%s' is promoted to `%s' when passed through `...'", name, pname);
+      /* Unfortunately, this is merely undefined, rather than a constraint
+        violation, so we cannot make this an error.  If this call is never
+        executed, the program is still strictly conforming.  */
+      warning ("`%s' is promoted to `%s' when passed through `...'",
+              name, pname);
       if (! gave_help)
        {
-         gave_help = 1;
-         error ("(so you should pass `%s' not `%s' to `va_arg')", pname, name);
+         gave_help = true;
+         warning ("(so you should pass `%s' not `%s' to `va_arg')",
+                  pname, name);
        }
 
+      /* We can, however, treat "undefined" any way we please.
+        Call abort to encourage the user to fix the program.  */
+      expand_builtin_trap ();
+
+      /* This is dead code, but go ahead and finish so that the
+        mode of the result comes out right.  */
       addr = const0_rtx;
     }
   else
@@ -3541,6 +3632,18 @@ expand_builtin_expect_jump (exp, if_false_label, if_true_label)
 
   return ret;
 }
+
+void
+expand_builtin_trap ()
+{
+#ifdef HAVE_trap
+  if (HAVE_trap)
+    emit_insn (gen_trap ());
+  else
+#endif
+    emit_library_call (abort_libfunc, LCT_NORETURN, VOIDmode, 0);
+  emit_barrier ();
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -3606,11 +3709,11 @@ expand_builtin (exp, target, subtarget, mode, ignore)
       case BUILT_IN_FPUTC_UNLOCKED:
       case BUILT_IN_FPUTS_UNLOCKED:
       case BUILT_IN_FWRITE_UNLOCKED:
-        return expand_call (exp, target, ignore);
+       return expand_call (exp, target, ignore);
 
       default:
-        break;
-    }
+       break;
+      }
 
   switch (fcode)
     {
@@ -3722,11 +3825,11 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        0 otherwise.  */
     case BUILT_IN_AGGREGATE_INCOMING_ADDRESS:
       if (arglist != 0
-          || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
-          || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
-        return const0_rtx;
+         || ! AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
+         || GET_CODE (DECL_RTL (DECL_RESULT (current_function_decl))) != MEM)
+       return const0_rtx;
       else
-        return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
+       return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
 
     case BUILT_IN_ALLOCA:
       target = expand_builtin_alloca (arglist, target);
@@ -3875,13 +3978,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
        }
 
     case BUILT_IN_TRAP:
-#ifdef HAVE_trap
-      if (HAVE_trap)
-       emit_insn (gen_trap ());
-      else
-#endif
-       error ("__builtin_trap not supported by this target");
-      emit_barrier ();
+      expand_builtin_trap ();
       return const0_rtx;
 
     case BUILT_IN_PUTCHAR: