alloc-pool.c: Fix comment formatting.
[gcc.git] / gcc / builtins.c
index 41e90f7daab506388ad7cd66df0e07294c10e206..26938105a551dce4d8cf32c52844eed118fbcfbc 100644 (file)
@@ -85,7 +85,7 @@ static REAL_VALUE_TYPE dconstpi;
 static REAL_VALUE_TYPE dconste;
 
 static int get_pointer_alignment (tree, unsigned int);
-static tree c_strlen (tree);
+static tree c_strlen (tree, int);
 static const char *c_getstr (tree);
 static rtx c_readstr (const char *, enum machine_mode);
 static int target_char_cast (tree, char *);
@@ -141,6 +141,7 @@ static rtx expand_builtin_alloca (tree, rtx);
 static rtx expand_builtin_unop (enum machine_mode, tree, rtx, rtx, optab);
 static rtx expand_builtin_frame_address (tree, tree);
 static rtx expand_builtin_fputs (tree, int, int);
+static rtx expand_builtin_sprintf (tree, rtx, enum machine_mode);
 static tree stabilize_va_list (tree, int);
 static rtx expand_builtin_expect (tree, rtx);
 static tree fold_builtin_constant_p (tree);
@@ -241,19 +242,42 @@ get_pointer_alignment (tree exp, unsigned int max_align)
    way, because it could contain a zero byte in the middle.
    TREE_STRING_LENGTH is the size of the character array, not the string.
 
+   ONLY_VALUE should be nonzero if the result is not going to be emitted
+   into the instruction stream and zero if it is going to be expanded.
+   E.g. with i++ ? "foo" : "bar", if ONLY_VALUE is nonzero, constant 3
+   is returned, otherwise NULL, since
+   len = c_strlen (src, 1); if (len) expand_expr (len, ...); would not
+   evaluate the side-effects.
+
    The value returned is of type `ssizetype'.
 
    Unfortunately, string_constant can't access the values of const char
    arrays with initializers, so neither can we do so here.  */
 
 static tree
-c_strlen (tree src)
+c_strlen (tree src, int only_value)
 {
   tree offset_node;
   HOST_WIDE_INT offset;
   int max;
   const char *ptr;
 
+  STRIP_NOPS (src);
+  if (TREE_CODE (src) == COND_EXPR
+      && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
+    {
+      tree len1, len2;
+
+      len1 = c_strlen (TREE_OPERAND (src, 1), only_value);
+      len2 = c_strlen (TREE_OPERAND (src, 2), only_value);
+      if (tree_int_cst_equal (len1, len2))      
+       return len1;
+    }
+
+  if (TREE_CODE (src) == COMPOUND_EXPR
+      && (only_value || !TREE_SIDE_EFFECTS (TREE_OPERAND (src, 0))))
+    return c_strlen (TREE_OPERAND (src, 1), only_value);
+
   src = string_constant (src, &offset_node);
   if (src == 0)
     return 0;
@@ -1203,7 +1227,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
   do_pending_stack_adjust ();
   NO_DEFER_POP;
 
-  /* Save the stack with nonlocal if available */
+  /* Save the stack with nonlocal if available */
 #ifdef HAVE_save_stack_nonlocal
   if (HAVE_save_stack_nonlocal)
     emit_stack_save (SAVE_NONLOCAL, &old_stack_level, NULL_RTX);
@@ -1653,38 +1677,35 @@ mathfn_built_in (tree type, enum built_in_function fn)
 static void
 expand_errno_check (tree exp, rtx target)
 {
-  rtx lab;
-
-  if (flag_errno_math && HONOR_NANS (GET_MODE (target)))
-    {
-      lab = gen_label_rtx ();
+  rtx lab = gen_label_rtx ();
 
-      /* Test the result; if it is NaN, set errno=EDOM because
-        the argument was not in the domain.  */
-      emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
-                              0, lab);
+  /* Test the result; if it is NaN, set errno=EDOM because
+     the argument was not in the domain.  */
+  emit_cmp_and_jump_insns (target, target, EQ, 0, GET_MODE (target),
+                          0, lab);
 
 #ifdef TARGET_EDOM
-      {
+  /* If this built-in doesn't throw an exception, set errno directly.  */
+  if (TREE_NOTHROW (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)))
+    {
 #ifdef GEN_ERRNO_RTX
-       rtx errno_rtx = GEN_ERRNO_RTX;
+      rtx errno_rtx = GEN_ERRNO_RTX;
 #else
-       rtx errno_rtx
+      rtx errno_rtx
          = gen_rtx_MEM (word_mode, gen_rtx_SYMBOL_REF (Pmode, "errno"));
 #endif
-
-       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.  */
-      NO_DEFER_POP;
-      expand_call (exp, target, 0);
-      OK_DEFER_POP;
-#endif
-
+      emit_move_insn (errno_rtx, GEN_INT (TARGET_EDOM));
       emit_label (lab);
+      return;
     }
+#endif
+
+  /* We can't set errno=EDOM directly; let the library call do it.
+     Pop the arguments right away in case the call gets deleted.  */
+  NO_DEFER_POP;
+  expand_call (exp, target, 0);
+  OK_DEFER_POP;
+  emit_label (lab);
 }
 
 
@@ -1701,35 +1722,14 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
   rtx op0, insns;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
-  enum machine_mode argmode;
+  enum machine_mode mode;
   bool errno_set = false;
+  tree arg, narg;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
     return 0;
 
-  /* Stabilize and compute the argument.  */
-  if (TREE_CODE (TREE_VALUE (arglist)) != VAR_DECL
-      && TREE_CODE (TREE_VALUE (arglist)) != PARM_DECL)
-    {
-      exp = copy_node (exp);
-      TREE_OPERAND (exp, 1) = arglist;
-      /* Wrap the computation of the argument in a SAVE_EXPR.  That
-        way, if we need to expand the argument again (as in the
-        flag_errno_math case below where we cannot directly set
-        errno), we will not perform side-effects more than once.
-        Note that here we're mutating the original EXP as well as the
-        copy; that's the right thing to do in case the original EXP
-        is expanded later.  */
-      TREE_VALUE (arglist) = save_expr (TREE_VALUE (arglist));
-      arglist = copy_node (arglist);
-    }
-  op0 = expand_expr (TREE_VALUE (arglist), subtarget, VOIDmode, 0);
-
-  /* Make a suitable register to place result in.  */
-  target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
-  emit_queue ();
-  start_sequence ();
+  arg = TREE_VALUE (arglist);
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
@@ -1744,7 +1744,9 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
     case BUILT_IN_SQRT:
     case BUILT_IN_SQRTF:
     case BUILT_IN_SQRTL:
-      errno_set = true; builtin_optab = sqrt_optab; break;
+      errno_set = ! tree_expr_nonnegative_p (arg);
+      builtin_optab = sqrt_optab;
+      break;
     case BUILT_IN_EXP:
     case BUILT_IN_EXPF:
     case BUILT_IN_EXPL:
@@ -1785,18 +1787,39 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
       abort ();
     }
 
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (exp));
+  target = gen_reg_rtx (mode);
+
+  if (! flag_errno_math || ! HONOR_NANS (mode))
+    errno_set = false;
+
+  /* Wrap the computation of the argument in a SAVE_EXPR, as we may
+     need to expand the argument again.  This way, we will not perform
+     side-effects more the once.  */
+  narg = save_expr (arg);
+  if (narg != arg)
+    {
+      arglist = build_tree_list (NULL_TREE, arg);
+      exp = build_function_call_expr (fndecl, arglist);
+    }
+
+  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+
+  emit_queue ();
+  start_sequence ();
+
   /* Compute into TARGET.
      Set TARGET to wherever the result comes back.  */
-  argmode = TYPE_MODE (TREE_TYPE (TREE_VALUE (arglist)));
-  target = expand_unop (argmode, builtin_optab, op0, target, 0);
+  target = expand_unop (mode, 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
-     a call to the library function.  */
+  /* If we were unable to expand via the builtin, stop the sequence
+     (without outputting the insns) and call to the library function
+     with the stabilized argument list.  */
   if (target == 0)
     {
       end_sequence ();
-      return 0;
+      return expand_call (exp, target, target == const0_rtx);
     }
 
   if (errno_set)
@@ -1824,8 +1847,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   rtx op0, op1, insns;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
-  tree arg0, arg1;
-  enum machine_mode argmode;
+  tree arg0, arg1, temp, narg;
+  enum machine_mode mode;
   bool errno_set = true;
   bool stable = true;
 
@@ -1835,64 +1858,67 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  /* Stabilize the arguments.  */
-  if (TREE_CODE (arg0) != VAR_DECL && TREE_CODE (arg0) != PARM_DECL)
+  switch (DECL_FUNCTION_CODE (fndecl))
     {
-      arg0 = save_expr (arg0);
-      TREE_VALUE (arglist) = arg0;
-      stable = false;
+    case BUILT_IN_POW:
+    case BUILT_IN_POWF:
+    case BUILT_IN_POWL:
+      builtin_optab = pow_optab; break;
+    case BUILT_IN_ATAN2:
+    case BUILT_IN_ATAN2F:
+    case BUILT_IN_ATAN2L:
+      builtin_optab = atan2_optab; break;
+    default:
+      abort ();
     }
-  if (TREE_CODE (arg1) != VAR_DECL && TREE_CODE (arg1) != PARM_DECL)
+
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (exp));
+  target = gen_reg_rtx (mode);
+
+  if (! flag_errno_math || ! HONOR_NANS (mode))
+    errno_set = false;
+
+  /* Alway stabilize the argument list.  */
+  narg = save_expr (arg1);
+  if (narg != arg1)
     {
-      arg1 = save_expr (arg1);
-      TREE_VALUE (TREE_CHAIN (arglist)) = arg1;
+      temp = build_tree_list (NULL_TREE, narg);
       stable = false;
     }
+  else
+    temp = TREE_CHAIN (arglist);
 
-  if (! stable)
+  narg = save_expr (arg0);
+  if (narg != arg0)
     {
-      exp = copy_node (exp);
-      arglist = tree_cons (NULL_TREE, arg0,
-                          build_tree_list (NULL_TREE, arg1));
-      TREE_OPERAND (exp, 1) = arglist;
+      arglist = tree_cons (NULL_TREE, narg, temp);
+      stable = false;
     }
+  else if (! stable)
+    arglist = tree_cons (NULL_TREE, arg0, temp);
+
+  if (! stable)
+    exp = build_function_call_expr (fndecl, arglist);
 
   op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
   op1 = expand_expr (arg1, 0, VOIDmode, 0);
 
-  /* Make a suitable register to place result in.  */
-  target = gen_reg_rtx (TYPE_MODE (TREE_TYPE (exp)));
-
   emit_queue ();
   start_sequence ();
 
-  switch (DECL_FUNCTION_CODE (fndecl))
-    {
-    case BUILT_IN_POW:
-    case BUILT_IN_POWF:
-    case BUILT_IN_POWL:
-      builtin_optab = pow_optab; break;
-    case BUILT_IN_ATAN2:
-    case BUILT_IN_ATAN2F:
-    case BUILT_IN_ATAN2L:
-      builtin_optab = atan2_optab; break;
-    default:
-      abort ();
-    }
-
   /* Compute into TARGET.
      Set TARGET to wherever the result comes back.  */
-  argmode = TYPE_MODE (TREE_TYPE (arg0));
-  target = expand_binop (argmode, builtin_optab, op0, op1,
+  target = expand_binop (mode, builtin_optab, op0, op1,
                         target, 0, OPTAB_DIRECT);
 
-  /* If we were unable to expand via the builtin, stop the
-     sequence (without outputting the insns) and return 0, causing
-     a call to the library function.  */
+  /* If we were unable to expand via the builtin, stop the sequence
+     (without outputting the insns) and call to the library function
+     with the stabilized argument list.  */
   if (target == 0)
     {
       end_sequence ();
-      return 0;
+      return expand_call (exp, target, target == const0_rtx);
     }
 
   if (errno_set)
@@ -1906,6 +1932,253 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
+/* To evaluate powi(x,n), the floating point value x raised to the
+   constant integer exponent n, we use a hybrid algorithm that
+   combines the "window method" with look-up tables.  For an
+   introduction to exponentiation algorithms and "addition chains",
+   see section 4.6.3, "Evaluation of Powers" of Donald E. Knuth,
+   "Seminumerical Algorithms", Vol. 2, "The Art of Computer Programming",
+   3rd Edition, 1998, and Daniel M. Gordon, "A Survey of Fast Exponentiation
+   Methods", Journal of Algorithms, Vol. 27, pp. 129-146, 1998.  */
+
+/* Provide a default value for POWI_MAX_MULTS, the maximum number of
+   multiplications to inline before calling the system library's pow
+   function.  powi(x,n) requires at worst 2*bits(n)-2 multiplications,
+   so this default never requires calling pow, powf or powl.  */
+#ifndef POWI_MAX_MULTS
+#define POWI_MAX_MULTS  (2*HOST_BITS_PER_WIDE_INT-2)
+#endif
+
+/* The size of the "optimal power tree" lookup table.  All
+   exponents less than this value are simply looked up in the
+   powi_table below.  This threshold is also used to size the
+   cache of pseudo registers that hold intermediate results.  */
+#define POWI_TABLE_SIZE 256
+
+/* The size, in bits of the window, used in the "window method"
+   exponentiation algorithm.  This is equivalent to a radix of
+   (1<<POWI_WINDOW_SIZE) in the corresponding "m-ary method".  */
+#define POWI_WINDOW_SIZE 3
+
+/* The following table is an efficient representation of an
+   "optimal power tree".  For each value, i, the corresponding
+   value, j, in the table states than an optimal evaluation
+   sequence for calculating pow(x,i) can be found by evaluating
+   pow(x,j)*pow(x,i-j).  An optimal power tree for the first
+   100 integers is given in Knuth's "Seminumerical algorithms".  */
+
+static const unsigned char powi_table[POWI_TABLE_SIZE] =
+  {
+      0,   1,   1,   2,   2,   3,   3,   4,  /*   0 -   7 */
+      4,   6,   5,   6,   6,  10,   7,   9,  /*   8 -  15 */
+      8,  16,   9,  16,  10,  12,  11,  13,  /*  16 -  23 */
+     12,  17,  13,  18,  14,  24,  15,  26,  /*  24 -  31 */
+     16,  17,  17,  19,  18,  33,  19,  26,  /*  32 -  39 */
+     20,  25,  21,  40,  22,  27,  23,  44,  /*  40 -  47 */
+     24,  32,  25,  34,  26,  29,  27,  44,  /*  48 -  55 */
+     28,  31,  29,  34,  30,  60,  31,  36,  /*  56 -  63 */
+     32,  64,  33,  34,  34,  46,  35,  37,  /*  64 -  71 */
+     36,  65,  37,  50,  38,  48,  39,  69,  /*  72 -  79 */
+     40,  49,  41,  43,  42,  51,  43,  58,  /*  80 -  87 */
+     44,  64,  45,  47,  46,  59,  47,  76,  /*  88 -  95 */
+     48,  65,  49,  66,  50,  67,  51,  66,  /*  96 - 103 */
+     52,  70,  53,  74,  54, 104,  55,  74,  /* 104 - 111 */
+     56,  64,  57,  69,  58,  78,  59,  68,  /* 112 - 119 */
+     60,  61,  61,  80,  62,  75,  63,  68,  /* 120 - 127 */
+     64,  65,  65, 128,  66, 129,  67,  90,  /* 128 - 135 */
+     68,  73,  69, 131,  70,  94,  71,  88,  /* 136 - 143 */
+     72, 128,  73,  98,  74, 132,  75, 121,  /* 144 - 151 */
+     76, 102,  77, 124,  78, 132,  79, 106,  /* 152 - 159 */
+     80,  97,  81, 160,  82,  99,  83, 134,  /* 160 - 167 */
+     84,  86,  85,  95,  86, 160,  87, 100,  /* 168 - 175 */
+     88, 113,  89,  98,  90, 107,  91, 122,  /* 176 - 183 */
+     92, 111,  93, 102,  94, 126,  95, 150,  /* 184 - 191 */
+     96, 128,  97, 130,  98, 133,  99, 195,  /* 192 - 199 */
+    100, 128, 101, 123, 102, 164, 103, 138,  /* 200 - 207 */
+    104, 145, 105, 146, 106, 109, 107, 149,  /* 208 - 215 */
+    108, 200, 109, 146, 110, 170, 111, 157,  /* 216 - 223 */
+    112, 128, 113, 130, 114, 182, 115, 132,  /* 224 - 231 */
+    116, 200, 117, 132, 118, 158, 119, 206,  /* 232 - 239 */
+    120, 240, 121, 162, 122, 147, 123, 152,  /* 240 - 247 */
+    124, 166, 125, 214, 126, 138, 127, 153,  /* 248 - 255 */
+  };
+
+
+/* Return the number of multiplications required to calculate
+   powi(x,n) where n is less than POWI_TABLE_SIZE.  This is a
+   subroutine of powi_cost.  CACHE is an array indicating
+   which exponents have already been calculated.  */
+
+static int
+powi_lookup_cost (unsigned HOST_WIDE_INT n, bool *cache)
+{
+  /* If we've already calculated this exponent, then this evaluation
+     doesn't require any additional multiplications.  */
+  if (cache[n])
+    return 0;
+
+  cache[n] = true;
+  return powi_lookup_cost (n - powi_table[n], cache)
+        + powi_lookup_cost (powi_table[n], cache) + 1;
+}
+
+/* Return the number of multiplications required to calculate
+   powi(x,n) for an arbitrary x, given the exponent N.  This
+   function needs to be kept in sync with expand_powi below.  */
+
+static int
+powi_cost (HOST_WIDE_INT n)
+{
+  bool cache[POWI_TABLE_SIZE];
+  unsigned HOST_WIDE_INT digit;
+  unsigned HOST_WIDE_INT val;
+  int result;
+
+  if (n == 0)
+    return 0;
+
+  /* Ignore the reciprocal when calculating the cost.  */
+  val = (n < 0) ? -n : n;
+
+  /* Initialize the exponent cache.  */
+  memset (cache, 0, POWI_TABLE_SIZE * sizeof (bool));
+  cache[1] = true;
+
+  result = 0;
+
+  while (val >= POWI_TABLE_SIZE)
+    {
+      if (val & 1)
+       {
+         digit = val & ((1 << POWI_WINDOW_SIZE) - 1);
+         result += powi_lookup_cost (digit, cache)
+                   + POWI_WINDOW_SIZE + 1;
+         val >>= POWI_WINDOW_SIZE;
+       }
+      else
+       {
+         val >>= 1;
+         result++;
+       }
+    }
+  
+  return result + powi_lookup_cost (val, cache);
+}
+
+/* Recursive subroutine of expand_powi.  This function takes the array,
+   CACHE, of already calculated exponents and an exponent N and returns
+   an RTX that corresponds to CACHE[1]**N, as calculated in mode MODE.  */
+
+static rtx
+expand_powi_1 (enum machine_mode mode, unsigned HOST_WIDE_INT n, rtx *cache)
+{
+  unsigned HOST_WIDE_INT digit;
+  rtx target, result;
+  rtx op0, op1;
+
+  if (n < POWI_TABLE_SIZE)
+    {
+      if (cache[n])
+        return cache[n];
+
+      target = gen_reg_rtx (mode);
+      cache[n] = target;
+
+      op0 = expand_powi_1 (mode, n - powi_table[n], cache);
+      op1 = expand_powi_1 (mode, powi_table[n], cache);
+    }
+  else if (n & 1)
+    {
+      target = gen_reg_rtx (mode);
+      digit = n & ((1 << POWI_WINDOW_SIZE) - 1);
+      op0 = expand_powi_1 (mode, n - digit, cache);
+      op1 = expand_powi_1 (mode, digit, cache);
+    }
+  else
+    {
+      target = gen_reg_rtx (mode);
+      op0 = expand_powi_1 (mode, n >> 1, cache);
+      op1 = op0;
+    }
+
+  result = expand_mult (mode, op0, op1, target, 0);
+  if (result != target)
+    emit_move_insn (target, result);
+  return target;
+}
+
+/* Expand the RTL to evaluate powi(x,n) in mode MODE.  X is the
+   floating point operand in mode MODE, and N is the exponent.  This
+   function needs to be kept in sync with powi_cost above.  */
+   
+static rtx
+expand_powi (rtx x, enum machine_mode mode, HOST_WIDE_INT n)
+{
+  unsigned HOST_WIDE_INT val;
+  rtx cache[POWI_TABLE_SIZE];
+  rtx result;
+
+  if (n == 0)
+    return CONST1_RTX (mode);
+
+  val = (n < 0) ? -n : n;
+
+  memset (cache, 0, sizeof(cache));
+  cache[1] = x;
+
+  result = expand_powi_1 (mode, (n < 0) ? -n : n, cache);
+
+  /* If the original exponent was negative, reciprocate the result.  */
+  if (n < 0)
+    result = expand_binop (mode, sdiv_optab, CONST1_RTX (mode),
+                          result, NULL_RTX, 0, OPTAB_LIB_WIDEN);
+
+  return result;
+}
+
+/* Expand a call to the pow built-in mathematical function.  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.  */
+
+static rtx
+expand_builtin_pow (tree exp, rtx target, rtx subtarget)
+{
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0, arg1;
+
+  if (! validate_arglist (arglist, REAL_TYPE, REAL_TYPE, VOID_TYPE))
+    return 0;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+  if (flag_unsafe_math_optimizations
+      && ! flag_errno_math
+      && ! optimize_size
+      && TREE_CODE (arg1) == REAL_CST
+      && ! TREE_CONSTANT_OVERFLOW (arg1))
+    {
+      REAL_VALUE_TYPE cint;
+      REAL_VALUE_TYPE c;
+      HOST_WIDE_INT n;
+
+      c = TREE_REAL_CST (arg1);
+      n = real_to_integer (&c);
+      real_from_integer (&cint, VOIDmode, n, n < 0 ? -1 : 0, 0);
+      if (real_identical (&c, &cint)
+         && powi_cost (n) <= POWI_MAX_MULTS)
+       {
+          enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp));
+          rtx op = expand_expr (arg0, subtarget, VOIDmode, 0);
+          op = force_reg (mode, op);
+          return expand_powi (op, mode, n);
+       }
+    }
+  return expand_builtin_mathfn_2 (exp, target, NULL_RTX);
+}
+
 /* Expand expression EXP which is a call to the strlen builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise
    try to get the result in TARGET, if convenient.  */
@@ -1926,10 +2199,22 @@ expand_builtin_strlen (tree arglist, rtx target,
       int align;
 
       /* If the length can be computed at compile-time, return it.  */
-      len = c_strlen (src);
+      len = c_strlen (src, 0);
       if (len)
        return expand_expr (len, target, target_mode, EXPAND_NORMAL);
 
+      /* If the length can be computed at compile-time and is constant
+        integer, but there are side-effects in src, evaluate
+        src for side-effects, then return len.
+        E.g. x = strlen (i++ ? "xfoo" + 1 : "bar");
+        can be optimized into: i++; x = 3;  */
+      len = c_strlen (src, 1);
+      if (len && TREE_CODE (len) == INTEGER_CST)
+       {
+         expand_expr (src, const0_rtx, VOIDmode, EXPAND_NORMAL);
+         return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+       }
+
       align = get_pointer_alignment (src, BIGGEST_ALIGNMENT) / BITS_PER_UNIT;
 
       /* If SRC is not a pointer type, don't do this operation inline.  */
@@ -2277,11 +2562,11 @@ expand_builtin_memcpy (tree arglist, rtx target, enum machine_mode mode)
          && GET_CODE (len_rtx) == CONST_INT
          && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
-                                 (PTR) src_str, dest_align))
+                                 (void *) src_str, dest_align))
        {
          dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                      builtin_memcpy_read_str,
-                                     (PTR) src_str, dest_align, 0);
+                                     (void *) src_str, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2374,13 +2659,13 @@ expand_builtin_mempcpy (tree arglist, rtx target, enum machine_mode mode,
          && GET_CODE (len_rtx) == CONST_INT
          && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
-                                 (PTR) src_str, dest_align))
+                                 (void *) src_str, dest_align))
        {
          dest_mem = get_memory_rtx (dest);
          set_mem_align (dest_mem, dest_align);
          dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                      builtin_memcpy_read_str,
-                                     (PTR) src_str, dest_align, endp);
+                                     (void *) src_str, dest_align, endp);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2499,7 +2784,7 @@ expand_builtin_bcopy (tree arglist)
 static rtx
 expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
 {
-  tree fn, len;
+  tree fn, len, src, dst;
 
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
@@ -2508,12 +2793,16 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
   if (!fn)
     return 0;
 
-  len = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
-  if (len == 0)
+  src = TREE_VALUE (TREE_CHAIN (arglist));
+  len = c_strlen (src, 1);
+  if (len == 0 || TREE_SIDE_EFFECTS (len))
     return 0;
 
+  dst = TREE_VALUE (arglist);
   len = size_binop (PLUS_EXPR, len, ssize_int (1));
-  chainon (arglist, build_tree_list (NULL_TREE, len));
+  arglist = build_tree_list (NULL_TREE, len);
+  arglist = tree_cons (NULL_TREE, src, arglist);
+  arglist = tree_cons (NULL_TREE, dst, arglist);
   return expand_expr (build_function_call_expr (fn, arglist),
                      target, mode, EXPAND_NORMAL);
 }
@@ -2530,8 +2819,7 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
     return 0;
   else
     {
-      tree newarglist;
-      tree src, len;
+      tree dst, src, len;
 
       /* If return value is ignored, transform stpcpy into strcpy.  */
       if (target == const0_rtx)
@@ -2549,13 +2837,15 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
          because the latter will potentially produce pessimized code
          when used to produce the return value.  */
       src = TREE_VALUE (TREE_CHAIN (arglist));
-      if (! c_getstr (src) || ! (len = c_strlen (src)))
+      if (! c_getstr (src) || ! (len = c_strlen (src, 0)))
        return 0;
 
+      dst = TREE_VALUE (arglist);
       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
-      newarglist = copy_list (arglist);
-      chainon (newarglist, build_tree_list (NULL_TREE, len));
-      return expand_builtin_mempcpy (newarglist, target, mode, /*endp=*/2);
+      arglist = build_tree_list (NULL_TREE, len);
+      arglist = tree_cons (NULL_TREE, src, arglist);
+      arglist = tree_cons (NULL_TREE, dst, arglist);
+      return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2);
     }
 }
 
@@ -2586,7 +2876,7 @@ expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode)
     return 0;
   else
     {
-      tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
+      tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)), 1);
       tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
       tree fn;
 
@@ -2626,13 +2916,13 @@ expand_builtin_strncpy (tree arglist, rtx target, enum machine_mode mode)
          if (!p || dest_align == 0 || !host_integerp (len, 1)
              || !can_store_by_pieces (tree_low_cst (len, 1),
                                       builtin_strncpy_read_str,
-                                      (PTR) p, dest_align))
+                                      (void *) p, dest_align))
            return 0;
 
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
-                          (PTR) p, dest_align, 0);
+                          (void *) p, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2743,7 +3033,7 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
          c = 1;
          if (!can_store_by_pieces (tree_low_cst (len, 1),
                                    builtin_memset_read_str,
-                                   (PTR) &c, dest_align))
+                                   &c, dest_align))
            return 0;
 
          val = fold (build1 (CONVERT_EXPR, unsigned_char_type_node, val));
@@ -2753,7 +3043,7 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
          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, 0);
+                          val_rtx, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -2770,14 +3060,14 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode)
          if (!host_integerp (len, 1))
            return 0;
          if (!can_store_by_pieces (tree_low_cst (len, 1),
-                                   builtin_memset_read_str, (PTR) &c,
+                                   builtin_memset_read_str, &c,
                                    dest_align))
            return 0;
 
          dest_mem = get_memory_rtx (dest);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_memset_read_str,
-                          (PTR) &c, dest_align, 0);
+                          &c, dest_align, 0);
          dest_mem = force_operand (XEXP (dest_mem, 0), NULL_RTX);
 #ifdef POINTERS_EXTEND_UNSIGNED
          if (GET_MODE (dest_mem) != ptr_mode)
@@ -3012,8 +3302,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
     enum machine_mode insn_mode
       = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
 
-    len1 = c_strlen (arg1);
-    len2 = c_strlen (arg2);
+    len1 = c_strlen (arg1, 1);
+    len2 = c_strlen (arg2, 1);
 
     if (len1)
       len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
@@ -3159,8 +3449,8 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
     enum machine_mode insn_mode
       = insn_data[(int) CODE_FOR_cmpstrsi].operand[0].mode;
 
-    len1 = c_strlen (arg1);
-    len2 = c_strlen (arg2);
+    len1 = c_strlen (arg1, 1);
+    len2 = c_strlen (arg2, 1);
 
     if (len1)
       len1 = size_binop (PLUS_EXPR, ssize_int (1), len1);
@@ -3955,7 +4245,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked)
 
   /* Get the length of the string passed to fputs.  If the length
      can't be determined, punt.  */
-  if (!(len = c_strlen (TREE_VALUE (arglist)))
+  if (!(len = c_strlen (TREE_VALUE (arglist), 1))
       || TREE_CODE (len) != INTEGER_CST)
     return 0;
 
@@ -3990,7 +4280,7 @@ expand_builtin_fputs (tree arglist, int ignore, int unlocked)
       {
        tree string_arg;
 
-       /* If optimizing for size keep fputs. */
+       /* If optimizing for size keep fputs.  */
        if (optimize_size)
          return 0;
        string_arg = TREE_VALUE (arglist);
@@ -4046,7 +4336,7 @@ expand_builtin_expect (tree arglist, rtx target)
 
       rtx_c = expand_expr (c, NULL_RTX, GET_MODE (target), EXPAND_NORMAL);
 
-      note = emit_note (NULL, NOTE_INSN_EXPECTED_VALUE);
+      note = emit_note (NOTE_INSN_EXPECTED_VALUE);
       NOTE_EXPECTED_VALUE (note) = gen_rtx_EQ (VOIDmode, target, rtx_c);
     }
 
@@ -4229,6 +4519,90 @@ expand_builtin_cabs (tree arglist, rtx target)
   return expand_complex_abs (mode, op0, target, 0);
 }
 
+/* Expand a call to sprintf with argument list ARGLIST.  Return 0 if
+   a normal call should be emitted rather than expanding the function
+   inline.  If convenient, the result should be placed in TARGET with
+   mode MODE.  */
+
+static rtx
+expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
+{
+  tree orig_arglist, dest, fmt;
+  const char *fmt_str;
+
+  orig_arglist = arglist;
+
+  /* Verify the required arguments in the original call.  */
+  if (! arglist)
+    return 0;
+  dest = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+    return 0;
+  arglist = TREE_CHAIN (arglist);
+  if (! arglist)
+    return 0;
+  fmt = TREE_VALUE (arglist);
+  if (TREE_CODE (TREE_TYPE (dest)) != POINTER_TYPE)
+    return 0;
+  arglist = TREE_CHAIN (arglist);
+
+  /* Check whether the format is a literal string constant.  */
+  fmt_str = c_getstr (fmt);
+  if (fmt_str == NULL)
+    return 0;
+
+  /* If the format doesn't contain % args or %%, use strcpy.  */
+  if (strchr (fmt_str, '%') == 0)
+    {
+      tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+      tree exp;
+
+      if (arglist || ! fn)
+       return 0;
+      expand_expr (build_function_call_expr (fn, orig_arglist),
+                  const0_rtx, VOIDmode, EXPAND_NORMAL);
+      if (target == const0_rtx)
+       return const0_rtx;
+      exp = build_int_2 (strlen (fmt_str), 0);
+      exp = fold (build1 (NOP_EXPR, integer_type_node, exp));
+      return expand_expr (exp, target, mode, EXPAND_NORMAL);
+    }
+  /* If the format is "%s", use strcpy if the result isn't used.  */
+  else if (strcmp (fmt_str, "%s") == 0)
+    {
+      tree fn, arg, len;
+      fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+      if (! fn)
+       return 0;
+
+      if (! arglist || TREE_CHAIN (arglist))
+       return 0;
+      arg = TREE_VALUE (arglist);
+      if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+       return 0;
+
+      if (target != const0_rtx)
+       {
+         len = c_strlen (arg, 1);
+         if (! len || TREE_CODE (len) != INTEGER_CST)
+           return 0;
+       }
+      else
+       len = NULL_TREE;
+
+      arglist = build_tree_list (NULL_TREE, arg);
+      arglist = tree_cons (NULL_TREE, dest, arglist);
+      expand_expr (build_function_call_expr (fn, arglist),
+                  const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      if (target == const0_rtx)
+       return const0_rtx;
+      return expand_expr (len, target, mode, EXPAND_NORMAL);
+    }
+
+  return 0;
+}
 \f
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
@@ -4293,6 +4667,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       case BUILT_IN_BCOPY:
       case BUILT_IN_INDEX:
       case BUILT_IN_RINDEX:
+      case BUILT_IN_SPRINTF:
       case BUILT_IN_STPCPY:
       case BUILT_IN_STRCHR:
       case BUILT_IN_STRRCHR:
@@ -4460,6 +4835,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_POW:
     case BUILT_IN_POWF:
     case BUILT_IN_POWL:
+      if (! flag_unsafe_math_optimizations)
+       break;
+      target = expand_builtin_pow (exp, target, subtarget);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_ATAN2:
     case BUILT_IN_ATAN2F:
     case BUILT_IN_ATAN2L:
@@ -4764,6 +5146,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    case BUILT_IN_SPRINTF:
+      target = expand_builtin_sprintf (arglist, target, mode);
+      if (target)
+       return target;
+      break;
+
       /* Various hooks for the DWARF 2 __throw routine.  */
     case BUILT_IN_UNWIND_INIT:
       expand_builtin_unwind_init ();
@@ -5088,7 +5476,7 @@ fold_builtin (tree exp)
     case BUILT_IN_STRLEN:
       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
        {
-         tree len = c_strlen (TREE_VALUE (arglist));
+         tree len = c_strlen (TREE_VALUE (arglist), 0);
          if (len)
            {
              /* Convert from the internal "sizetype" type to "size_t".  */