OSDN Git Service

2006-03-10 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / builtins.c
index 13d80ed..1ce6083 100644 (file)
@@ -1,6 +1,6 @@
 /* Expand builtin functions.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -75,8 +75,7 @@ static int get_pointer_alignment (tree, unsigned int);
 static const char *c_getstr (tree);
 static rtx c_readstr (const char *, enum machine_mode);
 static int target_char_cast (tree, char *);
-static rtx get_memory_rtx (tree);
-static tree build_string_literal (int, const char *);
+static rtx get_memory_rtx (tree, tree);
 static int apply_args_size (void);
 static int apply_result_size (void);
 #if defined (HAVE_untyped_call) || defined (HAVE_untyped_return)
@@ -95,6 +94,7 @@ 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_sincos (tree);
 static rtx expand_builtin_int_roundingfn (tree, rtx, rtx);
 static rtx expand_builtin_args_info (tree);
 static rtx expand_builtin_next_arg (void);
@@ -113,7 +113,7 @@ static rtx expand_builtin_memcpy (tree, rtx, enum machine_mode);
 static rtx expand_builtin_mempcpy (tree, tree, rtx, enum machine_mode, int);
 static rtx expand_builtin_memmove (tree, tree, rtx, enum machine_mode, tree);
 static rtx expand_builtin_bcopy (tree);
-static rtx expand_builtin_strcpy (tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcpy (tree, tree, rtx, enum machine_mode);
 static rtx expand_builtin_stpcpy (tree, rtx, enum machine_mode);
 static rtx builtin_strncpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
 static rtx expand_builtin_strncpy (tree, rtx, enum machine_mode);
@@ -199,6 +199,15 @@ static tree fold_builtin_strncat_chk (tree, tree);
 static tree fold_builtin_sprintf_chk (tree, enum built_in_function);
 static tree fold_builtin_printf (tree, tree, bool, enum built_in_function);
 static tree fold_builtin_fprintf (tree, tree, bool, enum built_in_function);
+static bool init_target_chars (void);
+
+static unsigned HOST_WIDE_INT target_newline;
+static unsigned HOST_WIDE_INT target_percent;
+static unsigned HOST_WIDE_INT target_c;
+static unsigned HOST_WIDE_INT target_s;
+static char target_percent_c[3];
+static char target_percent_s[3];
+static char target_percent_s_newline[4];
 
 /* Return true if NODE should be considered for inline expansion regardless
    of the optimization level.  This means whenever a function is invoked with
@@ -266,15 +275,21 @@ get_pointer_alignment (tree exp, unsigned int max_align)
        case ADDR_EXPR:
          /* See what we are pointing at and look at its alignment.  */
          exp = TREE_OPERAND (exp, 0);
+         while (handled_component_p (exp))
+           {
+             if (TREE_CODE (exp) == COMPONENT_REF)
+               align = MIN (align, DECL_ALIGN (TREE_OPERAND (exp, 1)));
+             exp = TREE_OPERAND (exp, 0);
+           }
          if (TREE_CODE (exp) == FUNCTION_DECL)
-           align = FUNCTION_BOUNDARY;
+           align = MIN (align, FUNCTION_BOUNDARY);
          else if (DECL_P (exp))
-           align = DECL_ALIGN (exp);
+           align = MIN (align, DECL_ALIGN (exp));
 #ifdef CONSTANT_ALIGNMENT
          else if (CONSTANT_CLASS_P (exp))
-           align = CONSTANT_ALIGNMENT (exp, align);
+           align = MIN (align, (unsigned)CONSTANT_ALIGNMENT (exp, align));
 #endif
-         return MIN (align, max_align);
+         return align;
 
        default:
          return align;
@@ -485,7 +500,22 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
 #ifdef INITIAL_FRAME_ADDRESS_RTX
   rtx tem = INITIAL_FRAME_ADDRESS_RTX;
 #else
-  rtx tem = hard_frame_pointer_rtx;
+  rtx tem;
+
+  /* For a zero count, we don't care what frame address we return, so frame
+     pointer elimination is OK, and using the soft frame pointer is OK.
+     For a nonzero count, we require a stable offset from the current frame
+     pointer to the previous one, so we must use the hard frame pointer, and
+     we must disable frame pointer elimination.  */
+  if (count == 0)
+    tem = frame_pointer_rtx;
+  else 
+    {
+      tem = hard_frame_pointer_rtx;
+
+      /* Tell reload not to eliminate the frame pointer.  */
+      current_function_accesses_prior_frames = 1;
+    }
 #endif
 
   /* Some machines need special handling before we can access
@@ -514,8 +544,7 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
       tem = DYNAMIC_CHAIN_ADDRESS (tem);
 #endif
       tem = memory_address (Pmode, tem);
-      tem = gen_rtx_MEM (Pmode, tem);
-      set_mem_alias_set (tem, get_frame_alias_set ());
+      tem = gen_frame_mem (Pmode, tem);
       tem = copy_to_reg (tem);
     }
 
@@ -530,8 +559,7 @@ expand_builtin_return_addr (enum built_in_function fndecl_code, int count)
 #else
   tem = memory_address (Pmode,
                        plus_constant (tem, GET_MODE_SIZE (Pmode)));
-  tem = gen_rtx_MEM (Pmode, tem);
-  set_mem_alias_set (tem, get_frame_alias_set ());
+  tem = gen_frame_mem (Pmode, tem);
 #endif
   return tem;
 }
@@ -678,7 +706,7 @@ expand_builtin_setjmp (tree arglist, rtx target)
       || REGNO (target) < FIRST_PSEUDO_REGISTER)
     target = gen_reg_rtx (TYPE_MODE (integer_type_node));
 
-  buf_addr = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+  buf_addr = expand_normal (TREE_VALUE (arglist));
 
   next_lab = gen_label_rtx ();
   cont_lab = gen_label_rtx ();
@@ -820,9 +848,9 @@ expand_builtin_nonlocal_goto (tree arglist)
   arglist = TREE_CHAIN (arglist);
   t_save_area = TREE_VALUE (arglist);
 
-  r_label = expand_expr (t_label, NULL_RTX, VOIDmode, 0);
+  r_label = expand_normal (t_label);
   r_label = convert_memory_address (Pmode, r_label);
-  r_save_area = expand_expr (t_save_area, NULL_RTX, VOIDmode, 0);
+  r_save_area = expand_normal (t_save_area);
   r_save_area = convert_memory_address (Pmode, r_save_area);
   r_fp = gen_rtx_MEM (Pmode, r_save_area);
   r_sp = gen_rtx_MEM (STACK_SAVEAREA_MODE (SAVE_NONLOCAL),
@@ -953,7 +981,7 @@ expand_builtin_prefetch (tree arglist)
       error ("second argument to %<__builtin_prefetch%> must be a constant");
       arg1 = integer_zero_node;
     }
-  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  op1 = expand_normal (arg1);
   /* Argument 1 must be either zero or one.  */
   if (INTVAL (op1) != 0 && INTVAL (op1) != 1)
     {
@@ -968,7 +996,7 @@ expand_builtin_prefetch (tree arglist)
       error ("third argument to %<__builtin_prefetch%> must be a constant");
       arg2 = integer_zero_node;
     }
-  op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  op2 = expand_normal (arg2);
   /* Argument 2 must be 0, 1, 2, or 3.  */
   if (INTVAL (op2) < 0 || INTVAL (op2) > 3)
     {
@@ -998,10 +1026,12 @@ expand_builtin_prefetch (tree arglist)
 }
 
 /* Get a MEM rtx for expression EXP which is the address of an operand
-   to be used to be used in a string instruction (cmpstrsi, movmemsi, ..).  */
+   to be used in a string instruction (cmpstrsi, movmemsi, ..).  LEN is
+   the maximum length of the block of memory that might be accessed or
+   NULL if unknown.  */
 
 static rtx
-get_memory_rtx (tree exp)
+get_memory_rtx (tree exp, tree len)
 {
   rtx addr = expand_expr (exp, NULL_RTX, ptr_mode, EXPAND_NORMAL);
   rtx mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr));
@@ -1027,6 +1057,80 @@ get_memory_rtx (tree exp)
   if (exp)
     {
       set_mem_attributes (mem, exp, 0);
+
+      /* Allow the string and memory builtins to overflow from one
+        field into another, see http://gcc.gnu.org/PR23561.
+        Thus avoid COMPONENT_REFs in MEM_EXPR unless we know the whole
+        memory accessed by the string or memory builtin will fit
+        within the field.  */
+      if (MEM_EXPR (mem) && TREE_CODE (MEM_EXPR (mem)) == COMPONENT_REF)
+       {
+         tree mem_expr = MEM_EXPR (mem);
+         HOST_WIDE_INT offset = -1, length = -1;
+         tree inner = exp;
+
+         while (TREE_CODE (inner) == ARRAY_REF
+                || TREE_CODE (inner) == NOP_EXPR
+                || TREE_CODE (inner) == CONVERT_EXPR
+                || TREE_CODE (inner) == NON_LVALUE_EXPR
+                || TREE_CODE (inner) == VIEW_CONVERT_EXPR
+                || TREE_CODE (inner) == SAVE_EXPR)
+           inner = TREE_OPERAND (inner, 0);
+
+         gcc_assert (TREE_CODE (inner) == COMPONENT_REF);
+
+         if (MEM_OFFSET (mem)
+             && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+           offset = INTVAL (MEM_OFFSET (mem));
+
+         if (offset >= 0 && len && host_integerp (len, 0))
+           length = tree_low_cst (len, 0);
+
+         while (TREE_CODE (inner) == COMPONENT_REF)
+           {
+             tree field = TREE_OPERAND (inner, 1);
+             gcc_assert (! DECL_BIT_FIELD (field));
+             gcc_assert (TREE_CODE (mem_expr) == COMPONENT_REF);
+             gcc_assert (field == TREE_OPERAND (mem_expr, 1));
+
+             if (length >= 0
+                 && TYPE_SIZE_UNIT (TREE_TYPE (inner))
+                 && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0))
+               {
+                 HOST_WIDE_INT size
+                   = tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (inner)), 0);
+                 /* If we can prove the memory starting at XEXP (mem, 0)
+                    and ending at XEXP (mem, 0) + LENGTH will fit into
+                    this field, we can keep that COMPONENT_REF in MEM_EXPR.  */
+                 if (offset <= size
+                     && length <= size
+                     && offset + length <= size)
+                   break;
+               }
+
+             if (offset >= 0
+                 && host_integerp (DECL_FIELD_OFFSET (field), 0))
+               offset += tree_low_cst (DECL_FIELD_OFFSET (field), 0)
+                         + tree_low_cst (DECL_FIELD_BIT_OFFSET (field), 1)
+                           / BITS_PER_UNIT;
+             else
+               {
+                 offset = -1;
+                 length = -1;
+               }
+
+             mem_expr = TREE_OPERAND (mem_expr, 0);
+             inner = TREE_OPERAND (inner, 0);
+           }
+
+         if (mem_expr == NULL)
+           offset = -1;
+         if (mem_expr != MEM_EXPR (mem))
+           {
+             set_mem_expr (mem, mem_expr);
+             set_mem_offset (mem, offset >= 0 ? GEN_INT (offset) : NULL_RTX);
+           }
+       }
       set_mem_alias_set (mem, 0);
       set_mem_size (mem, NULL_RTX);
     }
@@ -1487,7 +1591,6 @@ type_to_class (tree type)
     {
     case VOID_TYPE:       return void_type_class;
     case INTEGER_TYPE:    return integer_type_class;
-    case CHAR_TYPE:       return char_type_class;
     case ENUMERAL_TYPE:           return enumeral_type_class;
     case BOOLEAN_TYPE:    return boolean_type_class;
     case POINTER_TYPE:    return pointer_type_class;
@@ -1692,101 +1795,53 @@ expand_builtin_mathfn (tree exp, rtx target, rtx subtarget)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-    case BUILT_IN_SQRT:
-    case BUILT_IN_SQRTF:
-    case BUILT_IN_SQRTL:
+    CASE_FLT_FN (BUILT_IN_SQRT):
       errno_set = ! tree_expr_nonnegative_p (arg);
       builtin_optab = sqrt_optab;
       break;
-    case BUILT_IN_EXP:
-    case BUILT_IN_EXPF:
-    case BUILT_IN_EXPL:
+    CASE_FLT_FN (BUILT_IN_EXP):
       errno_set = true; builtin_optab = exp_optab; break;
-    case BUILT_IN_EXP10:
-    case BUILT_IN_EXP10F:
-    case BUILT_IN_EXP10L:
-    case BUILT_IN_POW10:
-    case BUILT_IN_POW10F:
-    case BUILT_IN_POW10L:
+    CASE_FLT_FN (BUILT_IN_EXP10):
+    CASE_FLT_FN (BUILT_IN_POW10):
       errno_set = true; builtin_optab = exp10_optab; break;
-    case BUILT_IN_EXP2:
-    case BUILT_IN_EXP2F:
-    case BUILT_IN_EXP2L:
+    CASE_FLT_FN (BUILT_IN_EXP2):
       errno_set = true; builtin_optab = exp2_optab; break;
-    case BUILT_IN_EXPM1:
-    case BUILT_IN_EXPM1F:
-    case BUILT_IN_EXPM1L:
+    CASE_FLT_FN (BUILT_IN_EXPM1):
       errno_set = true; builtin_optab = expm1_optab; break;
-    case BUILT_IN_LOGB:
-    case BUILT_IN_LOGBF:
-    case BUILT_IN_LOGBL:
+    CASE_FLT_FN (BUILT_IN_LOGB):
       errno_set = true; builtin_optab = logb_optab; break;
-    case BUILT_IN_ILOGB:
-    case BUILT_IN_ILOGBF:
-    case BUILT_IN_ILOGBL:
+    CASE_FLT_FN (BUILT_IN_ILOGB):
       errno_set = true; builtin_optab = ilogb_optab; break;
-    case BUILT_IN_LOG:
-    case BUILT_IN_LOGF:
-    case BUILT_IN_LOGL:
+    CASE_FLT_FN (BUILT_IN_LOG):
       errno_set = true; builtin_optab = log_optab; break;
-    case BUILT_IN_LOG10:
-    case BUILT_IN_LOG10F:
-    case BUILT_IN_LOG10L:
+    CASE_FLT_FN (BUILT_IN_LOG10):
       errno_set = true; builtin_optab = log10_optab; break;
-    case BUILT_IN_LOG2:
-    case BUILT_IN_LOG2F:
-    case BUILT_IN_LOG2L:
+    CASE_FLT_FN (BUILT_IN_LOG2):
       errno_set = true; builtin_optab = log2_optab; break;
-    case BUILT_IN_LOG1P:
-    case BUILT_IN_LOG1PF:
-    case BUILT_IN_LOG1PL:
+    CASE_FLT_FN (BUILT_IN_LOG1P):
       errno_set = true; builtin_optab = log1p_optab; break;
-    case BUILT_IN_ASIN:
-    case BUILT_IN_ASINF:
-    case BUILT_IN_ASINL:
+    CASE_FLT_FN (BUILT_IN_ASIN):
       builtin_optab = asin_optab; break;
-    case BUILT_IN_ACOS:
-    case BUILT_IN_ACOSF:
-    case BUILT_IN_ACOSL:
+    CASE_FLT_FN (BUILT_IN_ACOS):
       builtin_optab = acos_optab; break;
-    case BUILT_IN_TAN:
-    case BUILT_IN_TANF:
-    case BUILT_IN_TANL:
+    CASE_FLT_FN (BUILT_IN_TAN):
       builtin_optab = tan_optab; break;
-    case BUILT_IN_ATAN:
-    case BUILT_IN_ATANF:
-    case BUILT_IN_ATANL:
+    CASE_FLT_FN (BUILT_IN_ATAN):
       builtin_optab = atan_optab; break;
-    case BUILT_IN_FLOOR:
-    case BUILT_IN_FLOORF:
-    case BUILT_IN_FLOORL:
+    CASE_FLT_FN (BUILT_IN_FLOOR):
       builtin_optab = floor_optab; break;
-    case BUILT_IN_CEIL:
-    case BUILT_IN_CEILF:
-    case BUILT_IN_CEILL:
+    CASE_FLT_FN (BUILT_IN_CEIL):
       builtin_optab = ceil_optab; break;
-    case BUILT_IN_TRUNC:
-    case BUILT_IN_TRUNCF:
-    case BUILT_IN_TRUNCL:
+    CASE_FLT_FN (BUILT_IN_TRUNC):
       builtin_optab = btrunc_optab; break;
-    case BUILT_IN_ROUND:
-    case BUILT_IN_ROUNDF:
-    case BUILT_IN_ROUNDL:
+    CASE_FLT_FN (BUILT_IN_ROUND):
       builtin_optab = round_optab; break;
-    case BUILT_IN_NEARBYINT:
-    case BUILT_IN_NEARBYINTF:
-    case BUILT_IN_NEARBYINTL:
+    CASE_FLT_FN (BUILT_IN_NEARBYINT):
       builtin_optab = nearbyint_optab; break;
-    case BUILT_IN_RINT:
-    case BUILT_IN_RINTF:
-    case BUILT_IN_RINTL:
+    CASE_FLT_FN (BUILT_IN_RINT):
       builtin_optab = rint_optab; break;
-    case BUILT_IN_LRINT:
-    case BUILT_IN_LRINTF:
-    case BUILT_IN_LRINTL:
-    case BUILT_IN_LLRINT:
-    case BUILT_IN_LLRINTF:
-    case BUILT_IN_LLRINTL:
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
       builtin_optab = lrint_optab; break;
     default:
       gcc_unreachable ();
@@ -1919,25 +1974,15 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-    case BUILT_IN_POW:
-    case BUILT_IN_POWF:
-    case BUILT_IN_POWL:
+    CASE_FLT_FN (BUILT_IN_POW):
       builtin_optab = pow_optab; break;
-    case BUILT_IN_ATAN2:
-    case BUILT_IN_ATAN2F:
-    case BUILT_IN_ATAN2L:
+    CASE_FLT_FN (BUILT_IN_ATAN2):
       builtin_optab = atan2_optab; break;
-    case BUILT_IN_LDEXP:
-    case BUILT_IN_LDEXPF:
-    case BUILT_IN_LDEXPL:
+    CASE_FLT_FN (BUILT_IN_LDEXP):
       builtin_optab = ldexp_optab; break;
-    case BUILT_IN_FMOD:
-    case BUILT_IN_FMODF:
-    case BUILT_IN_FMODL:
+    CASE_FLT_FN (BUILT_IN_FMOD):
       builtin_optab = fmod_optab; break;
-    case BUILT_IN_DREM:
-    case BUILT_IN_DREMF:
-    case BUILT_IN_DREML:
+    CASE_FLT_FN (BUILT_IN_DREM):
       builtin_optab = drem_optab; break;
     default:
       gcc_unreachable ();
@@ -1979,8 +2024,8 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
   if (! stable)
     exp = build_function_call_expr (fndecl, arglist);
 
-  op0 = expand_expr (arg0, subtarget, VOIDmode, 0);
-  op1 = expand_expr (arg1, 0, VOIDmode, 0);
+  op0 = expand_expr (arg0, subtarget, VOIDmode, EXPAND_NORMAL);
+  op1 = expand_normal (arg1);
 
   start_sequence ();
 
@@ -2024,7 +2069,6 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   tree fndecl = get_callee_fndecl (exp);
   tree arglist = TREE_OPERAND (exp, 1);
   enum machine_mode mode;
-  bool errno_set = false;
   tree arg, narg;
 
   if (!validate_arglist (arglist, REAL_TYPE, VOID_TYPE))
@@ -2034,12 +2078,8 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
-    case BUILT_IN_COS:
-    case BUILT_IN_COSF:
-    case BUILT_IN_COSL:
+    CASE_FLT_FN (BUILT_IN_SIN):
+    CASE_FLT_FN (BUILT_IN_COS):
       builtin_optab = sincos_optab; break;
     default:
       gcc_unreachable ();
@@ -2048,21 +2088,14 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   /* Make a suitable register to place result in.  */
   mode = TYPE_MODE (TREE_TYPE (exp));
 
-  if (! flag_errno_math || ! HONOR_NANS (mode))
-    errno_set = false;
-
   /* Check if sincos insn is available, otherwise fallback
      to sin or cos insn.  */
   if (builtin_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing) {
     switch (DECL_FUNCTION_CODE (fndecl))
       {
-      case BUILT_IN_SIN:
-      case BUILT_IN_SINF:
-      case BUILT_IN_SINL:
+      CASE_FLT_FN (BUILT_IN_SIN):
        builtin_optab = sin_optab; break;
-      case BUILT_IN_COS:
-      case BUILT_IN_COSF:
-      case BUILT_IN_COSL:
+      CASE_FLT_FN (BUILT_IN_COS):
        builtin_optab = cos_optab; break;
       default:
        gcc_unreachable ();
@@ -2097,14 +2130,10 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 
          switch (DECL_FUNCTION_CODE (fndecl))
            {
-           case BUILT_IN_SIN:
-           case BUILT_IN_SINF:
-           case BUILT_IN_SINL:
+           CASE_FLT_FN (BUILT_IN_SIN):
              result = expand_twoval_unop (builtin_optab, op0, 0, target, 0);
              break;
-           case BUILT_IN_COS:
-           case BUILT_IN_COSF:
-           case BUILT_IN_COSL:
+           CASE_FLT_FN (BUILT_IN_COS):
              result = expand_twoval_unop (builtin_optab, op0, target, 0, 0);
              break;
            default:
@@ -2119,9 +2148,6 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
 
       if (target != 0)
        {
-         if (errno_set)
-           expand_errno_check (exp, target);
-
          /* Output the entire sequence.  */
          insns = get_insns ();
          end_sequence ();
@@ -2140,6 +2166,55 @@ expand_builtin_mathfn_3 (tree exp, rtx target, rtx subtarget)
   return target;
 }
 
+/* Expand a call to the builtin sincos math 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.  */
+
+static rtx
+expand_builtin_sincos (tree exp)
+{
+  rtx op0, op1, op2, target1, target2;
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum machine_mode mode;
+  tree arg, sinp, cosp;
+  int result;
+
+  if (!validate_arglist (arglist, REAL_TYPE,
+                        POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
+    return 0;
+
+  arg = TREE_VALUE (arglist);
+  sinp = TREE_VALUE (TREE_CHAIN (arglist));
+  cosp = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+  /* Make a suitable register to place result in.  */
+  mode = TYPE_MODE (TREE_TYPE (arg));
+
+  /* Check if sincos insn is available, otherwise emit the call.  */
+  if (sincos_optab->handlers[(int) mode].insn_code == CODE_FOR_nothing)
+    return NULL_RTX;
+
+  target1 = gen_reg_rtx (mode);
+  target2 = gen_reg_rtx (mode);
+
+  op0 = expand_normal (arg);
+  op1 = expand_normal (build_fold_indirect_ref (sinp));
+  op2 = expand_normal (build_fold_indirect_ref (cosp));
+
+  /* Compute into target1 and target2.
+     Set TARGET to wherever the result comes back.  */
+  result = expand_twoval_unop (sincos_optab, op0, target2, target1, 0);
+  gcc_assert (result);
+
+  /* Move target1 and target2 to the memory locations indicated
+     by op1 and op2.  */
+  emit_move_insn (op1, target1);
+  emit_move_insn (op2, target2);
+
+  return const0_rtx;
+}
+
 /* Expand a call to one of the builtin rounding functions (lfloor).
    If expanding via optab fails, lower expression to (int)(floor(x)).
    EXP is the expression that is a call to the builtin function;
@@ -2165,22 +2240,14 @@ expand_builtin_int_roundingfn (tree exp, rtx target, rtx subtarget)
 
   switch (DECL_FUNCTION_CODE (fndecl))
     {
-    case BUILT_IN_LCEIL:
-    case BUILT_IN_LCEILF:
-    case BUILT_IN_LCEILL:
-    case BUILT_IN_LLCEIL:
-    case BUILT_IN_LLCEILF:
-    case BUILT_IN_LLCEILL:
+    CASE_FLT_FN (BUILT_IN_LCEIL):
+    CASE_FLT_FN (BUILT_IN_LLCEIL):
       builtin_optab = lceil_optab;
       fallback_fn = BUILT_IN_CEIL;
       break;
 
-    case BUILT_IN_LFLOOR:
-    case BUILT_IN_LFLOORF:
-    case BUILT_IN_LFLOORL:
-    case BUILT_IN_LLFLOOR:
-    case BUILT_IN_LLFLOORF:
-    case BUILT_IN_LLFLOORL:
+    CASE_FLT_FN (BUILT_IN_LFLOOR):
+    CASE_FLT_FN (BUILT_IN_LLFLOOR):
       builtin_optab = lfloor_optab;
       fallback_fn = BUILT_IN_FLOOR;
       break;
@@ -2793,9 +2860,9 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
       if (src_align == 0)
        return 0;
 
-      dest_mem = get_memory_rtx (dest);
+      dest_mem = get_memory_rtx (dest, len);
       set_mem_align (dest_mem, dest_align);
-      len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+      len_rtx = expand_normal (len);
       src_str = c_getstr (src);
 
       /* If SRC is a string constant and block move would be done
@@ -2815,7 +2882,7 @@ expand_builtin_memcpy (tree exp, rtx target, enum machine_mode mode)
          return dest_mem;
        }
 
-      src_mem = get_memory_rtx (src);
+      src_mem = get_memory_rtx (src, len);
       set_mem_align (src_mem, src_align);
 
       /* Copy word part most expediently.  */
@@ -2882,7 +2949,7 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
       if (! host_integerp (len, 1))
        return 0;
 
-      len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+      len_rtx = expand_normal (len);
       src_str = c_getstr (src);
 
       /* If SRC is a string constant and block move would be done
@@ -2894,7 +2961,7 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
          && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str,
                                  (void *) src_str, dest_align))
        {
-         dest_mem = get_memory_rtx (dest);
+         dest_mem = get_memory_rtx (dest, len);
          set_mem_align (dest_mem, dest_align);
          dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx),
                                      builtin_memcpy_read_str,
@@ -2908,9 +2975,9 @@ expand_builtin_mempcpy (tree arglist, tree type, rtx target, enum machine_mode m
          && can_move_by_pieces (INTVAL (len_rtx),
                                 MIN (dest_align, src_align)))
        {
-         dest_mem = get_memory_rtx (dest);
+         dest_mem = get_memory_rtx (dest, len);
          set_mem_align (dest_mem, dest_align);
-         src_mem = get_memory_rtx (src);
+         src_mem = get_memory_rtx (src, len);
          set_mem_align (src_mem, src_align);
          dest_mem = move_by_pieces (dest_mem, src_mem, INTVAL (len_rtx),
                                     MIN (dest_align, src_align), endp);
@@ -3038,8 +3105,8 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
   if (!HAVE_movstr)
     return 0;
 
-  dest_mem = get_memory_rtx (dest);
-  src_mem = get_memory_rtx (src);
+  dest_mem = get_memory_rtx (dest, NULL);
+  src_mem = get_memory_rtx (src, NULL);
   if (!endp)
     {
       target = force_reg (Pmode, XEXP (dest_mem, 0));
@@ -3087,10 +3154,8 @@ expand_movstr (tree dest, tree src, rtx target, int endp)
    convenient).  */
 
 static rtx
-expand_builtin_strcpy (tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcpy (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
 {
-  tree fndecl = get_callee_fndecl (exp);
-  tree arglist = TREE_OPERAND (exp, 1);
   if (validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     {
       tree result = fold_builtin_strcpy (fndecl, arglist, 0);
@@ -3155,11 +3220,12 @@ expand_builtin_stpcpy (tree exp, rtx target, enum machine_mode mode)
 
       if (TREE_CODE (len) == INTEGER_CST)
        {
-         rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+         rtx len_rtx = expand_normal (len);
 
          if (GET_CODE (len_rtx) == CONST_INT)
            {
-             ret = expand_builtin_strcpy (exp, target, mode);
+             ret = expand_builtin_strcpy (get_callee_fndecl (exp), 
+                                          arglist, target, mode);
 
              if (ret)
                {
@@ -3245,7 +3311,7 @@ expand_builtin_strncpy (tree exp, rtx target, enum machine_mode mode)
                                       (void *) p, dest_align))
            return 0;
 
-         dest_mem = get_memory_rtx (dest);
+         dest_mem = get_memory_rtx (dest, len);
          store_by_pieces (dest_mem, tree_low_cst (len, 1),
                           builtin_strncpy_read_str,
                           (void *) p, dest_align, 0);
@@ -3335,15 +3401,15 @@ expand_builtin_memset (tree arglist, rtx target, enum machine_mode mode,
          return expand_expr (dest, target, mode, EXPAND_NORMAL);
        }
 
-      len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
-      dest_mem = get_memory_rtx (dest);
+      len_rtx = expand_normal (len);
+      dest_mem = get_memory_rtx (dest, len);
 
       if (TREE_CODE (val) != INTEGER_CST)
        {
          rtx val_rtx;
 
          val = fold_build1 (CONVERT_EXPR, unsigned_char_type_node, val);
-         val_rtx = expand_expr (val, NULL_RTX, VOIDmode, 0);
+         val_rtx = expand_normal (val);
 
          /* Assume that we can memset by pieces if we can store the
           * the coefficients by pieces (in the required modes).
@@ -3487,9 +3553,9 @@ expand_builtin_memcmp (tree exp ATTRIBUTE_UNUSED, tree arglist, rtx target,
           && REGNO (result) >= FIRST_PSEUDO_REGISTER))
       result = gen_reg_rtx (insn_mode);
 
-    arg1_rtx = get_memory_rtx (arg1);
-    arg2_rtx = get_memory_rtx (arg2);
-    arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+    arg1_rtx = get_memory_rtx (arg1, len);
+    arg2_rtx = get_memory_rtx (arg2, len);
+    arg3_rtx = expand_normal (len);
 
     /* Set MEM_SIZE as appropriate.  */
     if (GET_CODE (arg3_rtx) == CONST_INT)
@@ -3581,8 +3647,8 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
       arg1 = builtin_save_expr (arg1);
       arg2 = builtin_save_expr (arg2);
 
-      arg1_rtx = get_memory_rtx (arg1);
-      arg2_rtx = get_memory_rtx (arg2);
+      arg1_rtx = get_memory_rtx (arg1, NULL);
+      arg2_rtx = get_memory_rtx (arg2, NULL);
 
 #ifdef HAVE_cmpstrsi
       /* Try to call cmpstrsi.  */
@@ -3648,7 +3714,7 @@ expand_builtin_strcmp (tree exp, rtx target, enum machine_mode mode)
            return 0;
 
          /* Stabilize the arguments in case gen_cmpstrnsi fails.  */
-         arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+         arg3_rtx = expand_normal (len);
 
          /* Make a place to write the result of the instruction.  */
          result = target;
@@ -3786,9 +3852,9 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
     arg2 = builtin_save_expr (arg2);
     len = builtin_save_expr (len);
 
-    arg1_rtx = get_memory_rtx (arg1);
-    arg2_rtx = get_memory_rtx (arg2);
-    arg3_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+    arg1_rtx = get_memory_rtx (arg1, len);
+    arg2_rtx = get_memory_rtx (arg2, len);
+    arg3_rtx = expand_normal (len);
     insn = gen_cmpstrnsi (result, arg1_rtx, arg2_rtx, arg3_rtx,
                          GEN_INT (MIN (arg1_align, arg2_align)));
     if (insn)
@@ -3825,61 +3891,61 @@ expand_builtin_strncmp (tree exp, rtx target, enum machine_mode mode)
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcat (tree arglist, tree type, rtx target, enum machine_mode mode)
+expand_builtin_strcat (tree fndecl, tree arglist, rtx target, enum machine_mode mode)
 {
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
       tree dst = TREE_VALUE (arglist),
-       src = TREE_VALUE (TREE_CHAIN (arglist));
+      src = TREE_VALUE (TREE_CHAIN (arglist));
       const char *p = c_getstr (src);
 
-      if (p)
+      /* If the string length is zero, return the dst parameter.  */
+      if (p && *p == '\0')       
+       return expand_expr (dst, target, mode, EXPAND_NORMAL);
+      
+      if (!optimize_size)
        {
-         /* If the string length is zero, return the dst parameter.  */
-         if (*p == '\0')
-           return expand_expr (dst, target, mode, EXPAND_NORMAL);
-         else if (!optimize_size)
+         /* See if we can store by pieces into (dst + strlen(dst)).  */
+         tree newsrc, newdst,
+           strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+         rtx insns;
+
+         /* Stabilize the argument list.  */
+         newsrc = builtin_save_expr (src);
+         if (newsrc != src)
+           arglist = build_tree_list (NULL_TREE, newsrc);
+         else 
+           arglist = TREE_CHAIN (arglist); /* Reusing arglist if safe.  */
+
+         dst = builtin_save_expr (dst);
+
+         start_sequence ();
+
+         /* Create strlen (dst).  */
+         newdst =
+           build_function_call_expr (strlen_fn,
+                                     build_tree_list (NULL_TREE, dst));
+         /* Create (dst + (cast) strlen (dst)).  */
+         newdst = fold_convert (TREE_TYPE (dst), newdst);
+         newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
+
+         newdst = builtin_save_expr (newdst);
+         arglist = tree_cons (NULL_TREE, newdst, arglist);
+
+         if (!expand_builtin_strcpy (fndecl, arglist, target, mode))
            {
-             /* Otherwise if !optimize_size, see if we can store by
-                 pieces into (dst + strlen(dst)).  */
-             tree newdst, arglist,
-               strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
-
-             /* This is the length argument.  */
-             arglist = build_tree_list (NULL_TREE,
-                                        fold (size_binop (PLUS_EXPR,
-                                                          c_strlen (src, 0),
-                                                          ssize_int (1))));
-             /* Prepend src argument.  */
-             arglist = tree_cons (NULL_TREE, src, arglist);
-
-             /* We're going to use dst more than once.  */
-             dst = builtin_save_expr (dst);
-
-             /* Create strlen (dst).  */
-             newdst =
-               build_function_call_expr (strlen_fn,
-                                         build_tree_list (NULL_TREE, dst));
-             /* Create (dst + (cast) strlen (dst)).  */
-             newdst = fold_convert (TREE_TYPE (dst), newdst);
-             newdst = fold_build2 (PLUS_EXPR, TREE_TYPE (dst), dst, newdst);
-
-             /* Prepend the new dst argument.  */
-             arglist = tree_cons (NULL_TREE, newdst, arglist);
-
-             /* We don't want to get turned into a memcpy if the
-                 target is const0_rtx, i.e. when the return value
-                 isn't used.  That would produce pessimized code so
-                 pass in a target of zero, it should never actually be
-                 used.  If this was successful return the original
-                 dst, not the result of mempcpy.  */
-             if (expand_builtin_mempcpy (arglist, type, /*target=*/0, mode, /*endp=*/0))
-               return expand_expr (dst, target, mode, EXPAND_NORMAL);
-             else
-               return 0;
+             end_sequence (); /* Stop sequence.  */
+             return 0;
            }
+         
+         /* Output the entire sequence.  */
+         insns = get_insns ();
+         end_sequence ();
+         emit_insn (insns);
+         
+         return expand_expr (dst, target, mode, EXPAND_NORMAL);
        }
 
       return 0;
@@ -4143,7 +4209,8 @@ std_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
   /* va_list pointer is aligned to PARM_BOUNDARY.  If argument actually
      requires greater alignment, we must perform dynamic alignment.  */
-  if (boundary > align)
+  if (boundary > align
+      && !integer_zerop (TYPE_SIZE (type)))
     {
       t = fold_convert (TREE_TYPE (valist), size_int (boundary - 1));
       t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
@@ -4454,7 +4521,7 @@ expand_builtin_alloca (tree arglist, rtx target)
     return 0;
 
   /* Compute the argument.  */
-  op0 = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+  op0 = expand_normal (TREE_VALUE (arglist));
 
   /* Allocate the desired space.  */
   result = allocate_dynamic_stack_space (op0, target, BITS_PER_UNIT);
@@ -4663,7 +4730,7 @@ expand_builtin_expect_jump (tree exp, rtx if_false_label, rtx if_true_label)
   return ret;
 }
 
-static void
+void
 expand_builtin_trap (void)
 {
 #ifdef HAVE_trap
@@ -4712,17 +4779,17 @@ expand_builtin_copysign (tree arglist, rtx target, rtx subtarget)
     return 0;
 
   arg = TREE_VALUE (arglist);
-  op0 = expand_expr (arg, subtarget, VOIDmode, 0);
+  op0 = expand_expr (arg, subtarget, VOIDmode, EXPAND_NORMAL);
 
   arg = TREE_VALUE (TREE_CHAIN (arglist));
-  op1 = expand_expr (arg, NULL, VOIDmode, 0);
+  op1 = expand_normal (arg);
 
   return expand_copysign (op0, op1, target);
 }
 
 /* Create a new constant string literal and return a char* pointer to it.
    The STRING_CST value is the LEN characters at STR.  */
-static tree
+tree
 build_string_literal (int len, const char *str)
 {
   tree t, elem, index, type;
@@ -4755,11 +4822,12 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
                       bool unlocked)
 {
   tree arglist = TREE_OPERAND (exp, 1);
-  tree fn_putchar = unlocked
-                   ? implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
-                   : implicit_built_in_decls[BUILT_IN_PUTCHAR];
-  tree fn_puts = unlocked ? implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED]
-                         : implicit_built_in_decls[BUILT_IN_PUTS];
+  /* If we're using an unlocked function, assume the other unlocked
+     functions exist explicitly.  */
+  tree const fn_putchar = unlocked ? built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_PUTCHAR];
+  tree const fn_puts = unlocked ? built_in_decls[BUILT_IN_PUTS_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_PUTS];
   const char *fmt_str;
   tree fn, fmt, arg;
 
@@ -4780,8 +4848,11 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
   if (fmt_str == NULL)
     return 0;
 
+  if (!init_target_chars())
+    return 0;
+  
   /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
-  if (strcmp (fmt_str, "%s\n") == 0)
+  if (strcmp (fmt_str, target_percent_s_newline) == 0)
     {
       if (! arglist
           || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
@@ -4790,7 +4861,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
       fn = fn_puts;
     }
   /* If the format specifier was "%c", call __builtin_putchar(arg).  */
-  else if (strcmp (fmt_str, "%c") == 0)
+  else if (strcmp (fmt_str, target_percent_c) == 0)
     {
       if (! arglist
          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
@@ -4801,7 +4872,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
   else
     {
       /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, '%'))
+      if (strchr (fmt_str, target_percent))
         return 0;
 
       if (arglist)
@@ -4824,7 +4895,7 @@ expand_builtin_printf (tree exp, rtx target, enum machine_mode mode,
        {
          /* If the format specifier was "string\n", call puts("string").  */
          size_t len = strlen (fmt_str);
-         if (fmt_str[len - 1] == '\n')
+         if ((unsigned char)fmt_str[len - 1] == target_newline)
            {
              /* Create a NUL-terminated string that's one char shorter
                 than the original, stripping off the trailing '\n'.  */
@@ -4861,10 +4932,12 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
                        bool unlocked)
 {
   tree arglist = TREE_OPERAND (exp, 1);
-  tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
-                          : implicit_built_in_decls[BUILT_IN_FPUTC];
-  tree fn_fputs = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
-                          : implicit_built_in_decls[BUILT_IN_FPUTS];
+  /* If we're using an unlocked function, assume the other unlocked
+     functions exist explicitly.  */
+  tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_FPUTC];
+  tree const fn_fputs = unlocked ? built_in_decls[BUILT_IN_FPUTS_UNLOCKED]
+    : implicit_built_in_decls[BUILT_IN_FPUTS];
   const char *fmt_str;
   tree fn, fmt, fp, arg;
 
@@ -4891,8 +4964,11 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
   if (fmt_str == NULL)
     return 0;
 
+  if (!init_target_chars())
+    return 0;
+  
   /* If the format specifier was "%s", call __builtin_fputs(arg,fp).  */
-  if (strcmp (fmt_str, "%s") == 0)
+  if (strcmp (fmt_str, target_percent_s) == 0)
     {
       if (! arglist
           || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
@@ -4904,7 +4980,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
       fn = fn_fputs;
     }
   /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
-  else if (strcmp (fmt_str, "%c") == 0)
+  else if (strcmp (fmt_str, target_percent_c) == 0)
     {
       if (! arglist
          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
@@ -4918,7 +4994,7 @@ expand_builtin_fprintf (tree exp, rtx target, enum machine_mode mode,
   else
     {
       /* We can't handle anything else with % args or %% ... yet.  */
-      if (strchr (fmt_str, '%'))
+      if (strchr (fmt_str, target_percent))
         return 0;
 
       if (arglist)
@@ -4980,8 +5056,11 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
   if (fmt_str == NULL)
     return 0;
 
+  if (!init_target_chars())
+    return 0;
+
   /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, '%') == 0)
+  if (strchr (fmt_str, target_percent) == 0)
     {
       tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
       tree exp;
@@ -4996,7 +5075,7 @@ expand_builtin_sprintf (tree arglist, rtx target, enum machine_mode mode)
       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)
+  else if (strcmp (fmt_str, target_percent_s) == 0)
     {
       tree fn, arg, len;
       fn = implicit_built_in_decls[BUILT_IN_STRCPY];
@@ -5100,9 +5179,9 @@ expand_builtin_init_trampoline (tree arglist)
   arglist = TREE_CHAIN (arglist);
   t_chain = TREE_VALUE (arglist);
 
-  r_tramp = expand_expr (t_tramp, NULL_RTX, VOIDmode, 0);
-  r_func = expand_expr (t_func, NULL_RTX, VOIDmode, 0);
-  r_chain = expand_expr (t_chain, NULL_RTX, VOIDmode, 0);
+  r_tramp = expand_normal (t_tramp);
+  r_func = expand_normal (t_func);
+  r_chain = expand_normal (t_chain);
 
   /* Generate insns to initialize the trampoline.  */
   r_tramp = round_trampoline_addr (r_tramp);
@@ -5126,7 +5205,7 @@ expand_builtin_adjust_trampoline (tree arglist)
   if (!validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
 
-  tramp = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+  tramp = expand_normal (TREE_VALUE (arglist));
   tramp = round_trampoline_addr (tramp);
 #ifdef TRAMPOLINE_ADJUST_ADDRESS
   TRAMPOLINE_ADJUST_ADDRESS (tramp);
@@ -5173,7 +5252,7 @@ expand_builtin_signbit (tree exp, rtx target)
     return expand_expr (arg, target, VOIDmode, EXPAND_NORMAL);
   }
 
-  temp = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+  temp = expand_normal (arg);
   if (GET_MODE_SIZE (fmode) <= UNITS_PER_WORD)
     {
       imode = int_mode_for_mode (fmode);
@@ -5300,6 +5379,44 @@ expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
 }
 
 \f
+/* Reconstitute a mode for a __sync intrinsic operation.  Since the type of
+   the pointer in these functions is void*, the tree optimizers may remove
+   casts.  The mode computed in expand_builtin isn't reliable either, due
+   to __sync_bool_compare_and_swap.
+
+   FCODE_DIFF should be fcode - base, where base is the FOO_1 code for the
+   group of builtins.  This gives us log2 of the mode size.  */
+
+static inline enum machine_mode
+get_builtin_sync_mode (int fcode_diff)
+{
+  /* The size is not negotiable, so ask not to get BLKmode in return
+     if the target indicates that a smaller size would be better.  */
+  return mode_for_size (BITS_PER_UNIT << fcode_diff, MODE_INT, 0);
+}
+
+/* Expand the memory expression LOC and return the appropriate memory operand
+   for the builtin_sync operations.  */
+
+static rtx
+get_builtin_sync_mem (tree loc, enum machine_mode mode)
+{
+  rtx addr, mem;
+
+  addr = expand_expr (loc, NULL, Pmode, EXPAND_SUM);
+
+  /* Note that we explicitly do not want any alias information for this
+     memory, so that we kill all other live memories.  Otherwise we don't
+     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));
+  set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (mem) = 1;
+
+  return mem;
+}
+
 /* Expand the __sync_xxx_and_fetch and __sync_fetch_and_xxx intrinsics.
    ARGLIST is the operands list to the function.  CODE is the rtx code 
    that corresponds to the arithmetic or logical operation from the name;
@@ -5309,25 +5426,18 @@ expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
    the result of the operation at all.  */
 
 static rtx
-expand_builtin_sync_operation (tree arglist, enum rtx_code code, bool after,
+expand_builtin_sync_operation (enum machine_mode mode, tree arglist,
+                              enum rtx_code code, bool after,
                               rtx target, bool ignore)
 {
-  enum machine_mode mode;
-  rtx addr, val, mem;
+  rtx val, mem;
 
   /* Expand the operands.  */
-  addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
-  mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+  mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
 
   arglist = TREE_CHAIN (arglist);
   val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
 
-  /* Note that we explicitly do not want any alias information for this
-     memory, so that we kill all other live memories.  Otherwise we don't
-     satisfy the full barrier semantics of the intrinsic.  */
-  mem = validize_mem (gen_rtx_MEM (mode, addr));
-  MEM_VOLATILE_P (mem) = 1;
-
   if (ignore)
     return expand_sync_operation (mem, val, code);
   else
@@ -5340,14 +5450,13 @@ expand_builtin_sync_operation (tree arglist, enum rtx_code code, bool after,
    results; this is NOT optional if IS_BOOL is true.  */
 
 static rtx
-expand_builtin_compare_and_swap (tree arglist, bool is_bool, rtx target)
+expand_builtin_compare_and_swap (enum machine_mode mode, tree arglist,
+                                bool is_bool, rtx target)
 {
-  enum machine_mode mode;
-  rtx addr, old_val, new_val, mem;
+  rtx old_val, new_val, mem;
 
   /* Expand the operands.  */
-  addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_SUM);
-  mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+  mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
 
   arglist = TREE_CHAIN (arglist);
   old_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
@@ -5355,12 +5464,6 @@ expand_builtin_compare_and_swap (tree arglist, bool is_bool, rtx target)
   arglist = TREE_CHAIN (arglist);
   new_val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
 
-  /* Note that we explicitly do not want any alias information for this
-     memory, so that we kill all other live memories.  Otherwise we don't
-     satisfy the full barrier semantics of the intrinsic.  */
-  mem = validize_mem (gen_rtx_MEM (mode, addr));
-  MEM_VOLATILE_P (mem) = 1;
-
   if (is_bool)
     return expand_bool_compare_and_swap (mem, old_val, new_val, target);
   else
@@ -5374,24 +5477,17 @@ expand_builtin_compare_and_swap (tree arglist, bool is_bool, rtx target)
    place for us to store the results.  */
 
 static rtx
-expand_builtin_lock_test_and_set (tree arglist, rtx target)
+expand_builtin_lock_test_and_set (enum machine_mode mode, tree arglist,
+                                 rtx target)
 {
-  enum machine_mode mode;
-  rtx addr, val, mem;
+  rtx val, mem;
 
   /* Expand the operands.  */
-  addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
-  mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
+  mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
 
   arglist = TREE_CHAIN (arglist);
   val = expand_expr (TREE_VALUE (arglist), NULL, mode, EXPAND_NORMAL);
 
-  /* Note that we explicitly do not want any alias information for this
-     memory, so that we kill all other live memories.  Otherwise we don't
-     satisfy the barrier semantics of the intrinsic.  */
-  mem = validize_mem (gen_rtx_MEM (mode, addr));
-  MEM_VOLATILE_P (mem) = 1;
-
   return expand_sync_lock_test_and_set (mem, val, target);
 }
 
@@ -5400,7 +5496,7 @@ expand_builtin_lock_test_and_set (tree arglist, rtx target)
 static void
 expand_builtin_synchronize (void)
 {
-  rtx body;
+  tree x;
 
 #ifdef HAVE_memory_barrier
   if (HAVE_memory_barrier)
@@ -5410,33 +5506,26 @@ expand_builtin_synchronize (void)
     }
 #endif
 
-  /* If no explicit memory barrier instruction is available, create an empty
-     asm stmt that will prevent compiler movement across the barrier.  */
-  body = gen_rtx_ASM_INPUT (VOIDmode, "");
-  MEM_VOLATILE_P (body) = 1;
-  emit_insn (body);
+  /* If no explicit memory barrier instruction is available, create an
+     empty asm stmt with a memory clobber.  */
+  x = build4 (ASM_EXPR, void_type_node, build_string (0, ""), NULL, NULL,
+             tree_cons (NULL, build_string (6, "memory"), NULL));
+  ASM_VOLATILE_P (x) = 1;
+  expand_asm_expr (x);
 }
 
 /* Expand the __sync_lock_release intrinsic.  ARGLIST is the operands list
    to the function.  */
 
 static void
-expand_builtin_lock_release (tree arglist)
+expand_builtin_lock_release (enum machine_mode mode, tree arglist)
 {
-  enum machine_mode mode;
   enum insn_code icode;
-  rtx addr, val, mem, insn;
+  rtx mem, insn;
+  rtx val = const0_rtx;
 
   /* Expand the operands.  */
-  addr = expand_expr (TREE_VALUE (arglist), NULL, Pmode, EXPAND_NORMAL);
-  mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (TREE_VALUE (arglist))));
-  val = const0_rtx;
-
-  /* Note that we explicitly do not want any alias information for this
-     memory, so that we kill all other live memories.  Otherwise we don't
-     satisfy the barrier semantics of the intrinsic.  */
-  mem = validize_mem (gen_rtx_MEM (mode, addr));
-  MEM_VOLATILE_P (mem) = 1;
+  mem = get_builtin_sync_mem (TREE_VALUE (arglist), mode);
 
   /* If there is an explicit operation in the md file, use it.  */
   icode = sync_lock_release[mode];
@@ -5476,6 +5565,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 
   if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
     return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
+  else
+    {
+      /* Try expanding the builtin via the generic target hook.  */
+      rtx tmp = targetm.expand_library_builtin (exp, target, subtarget,
+                                               mode, ignore);
+      if (tmp != NULL_RTX)
+       return tmp;
+    }
 
   /* When not optimizing, generate calls to library functions for a certain
      set of builtins.  */
@@ -5517,17 +5614,13 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 
   switch (fcode)
     {
-    case BUILT_IN_FABS:
-    case BUILT_IN_FABSF:
-    case BUILT_IN_FABSL:
+    CASE_FLT_FN (BUILT_IN_FABS):
       target = expand_builtin_fabs (arglist, target, subtarget);
       if (target)
         return target;
       break;
 
-    case BUILT_IN_COPYSIGN:
-    case BUILT_IN_COPYSIGNF:
-    case BUILT_IN_COPYSIGNL:
+    CASE_FLT_FN (BUILT_IN_COPYSIGN):
       target = expand_builtin_copysign (arglist, target, subtarget);
       if (target)
        return target;
@@ -5535,137 +5628,67 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
 
       /* Just do a normal library call if we were unable to fold
         the values.  */
-    case BUILT_IN_CABS:
-    case BUILT_IN_CABSF:
-    case BUILT_IN_CABSL:
+    CASE_FLT_FN (BUILT_IN_CABS):
       break;
 
-    case BUILT_IN_EXP:
-    case BUILT_IN_EXPF:
-    case BUILT_IN_EXPL:
-    case BUILT_IN_EXP10:
-    case BUILT_IN_EXP10F:
-    case BUILT_IN_EXP10L:
-    case BUILT_IN_POW10:
-    case BUILT_IN_POW10F:
-    case BUILT_IN_POW10L:
-    case BUILT_IN_EXP2:
-    case BUILT_IN_EXP2F:
-    case BUILT_IN_EXP2L:
-    case BUILT_IN_EXPM1:
-    case BUILT_IN_EXPM1F:
-    case BUILT_IN_EXPM1L:
-    case BUILT_IN_LOGB:
-    case BUILT_IN_LOGBF:
-    case BUILT_IN_LOGBL:
-    case BUILT_IN_ILOGB:
-    case BUILT_IN_ILOGBF:
-    case BUILT_IN_ILOGBL:
-    case BUILT_IN_LOG:
-    case BUILT_IN_LOGF:
-    case BUILT_IN_LOGL:
-    case BUILT_IN_LOG10:
-    case BUILT_IN_LOG10F:
-    case BUILT_IN_LOG10L:
-    case BUILT_IN_LOG2:
-    case BUILT_IN_LOG2F:
-    case BUILT_IN_LOG2L:
-    case BUILT_IN_LOG1P:
-    case BUILT_IN_LOG1PF:
-    case BUILT_IN_LOG1PL:
-    case BUILT_IN_TAN:
-    case BUILT_IN_TANF:
-    case BUILT_IN_TANL:
-    case BUILT_IN_ASIN:
-    case BUILT_IN_ASINF:
-    case BUILT_IN_ASINL:
-    case BUILT_IN_ACOS:
-    case BUILT_IN_ACOSF:
-    case BUILT_IN_ACOSL:
-    case BUILT_IN_ATAN:
-    case BUILT_IN_ATANF:
-    case BUILT_IN_ATANL:
+    CASE_FLT_FN (BUILT_IN_EXP):
+    CASE_FLT_FN (BUILT_IN_EXP10):
+    CASE_FLT_FN (BUILT_IN_POW10):
+    CASE_FLT_FN (BUILT_IN_EXP2):
+    CASE_FLT_FN (BUILT_IN_EXPM1):
+    CASE_FLT_FN (BUILT_IN_LOGB):
+    CASE_FLT_FN (BUILT_IN_ILOGB):
+    CASE_FLT_FN (BUILT_IN_LOG):
+    CASE_FLT_FN (BUILT_IN_LOG10):
+    CASE_FLT_FN (BUILT_IN_LOG2):
+    CASE_FLT_FN (BUILT_IN_LOG1P):
+    CASE_FLT_FN (BUILT_IN_TAN):
+    CASE_FLT_FN (BUILT_IN_ASIN):
+    CASE_FLT_FN (BUILT_IN_ACOS):
+    CASE_FLT_FN (BUILT_IN_ATAN):
       /* Treat these like sqrt only if unsafe math optimizations are allowed,
         because of possible accuracy problems.  */
       if (! flag_unsafe_math_optimizations)
        break;
-    case BUILT_IN_SQRT:
-    case BUILT_IN_SQRTF:
-    case BUILT_IN_SQRTL:
-    case BUILT_IN_FLOOR:
-    case BUILT_IN_FLOORF:
-    case BUILT_IN_FLOORL:
-    case BUILT_IN_CEIL:
-    case BUILT_IN_CEILF:
-    case BUILT_IN_CEILL:
-    case BUILT_IN_TRUNC:
-    case BUILT_IN_TRUNCF:
-    case BUILT_IN_TRUNCL:
-    case BUILT_IN_ROUND:
-    case BUILT_IN_ROUNDF:
-    case BUILT_IN_ROUNDL:
-    case BUILT_IN_NEARBYINT:
-    case BUILT_IN_NEARBYINTF:
-    case BUILT_IN_NEARBYINTL:
-    case BUILT_IN_RINT:
-    case BUILT_IN_RINTF:
-    case BUILT_IN_RINTL:
-    case BUILT_IN_LRINT:
-    case BUILT_IN_LRINTF:
-    case BUILT_IN_LRINTL:
-    case BUILT_IN_LLRINT:
-    case BUILT_IN_LLRINTF:
-    case BUILT_IN_LLRINTL:
+    CASE_FLT_FN (BUILT_IN_SQRT):
+    CASE_FLT_FN (BUILT_IN_FLOOR):
+    CASE_FLT_FN (BUILT_IN_CEIL):
+    CASE_FLT_FN (BUILT_IN_TRUNC):
+    CASE_FLT_FN (BUILT_IN_ROUND):
+    CASE_FLT_FN (BUILT_IN_NEARBYINT):
+    CASE_FLT_FN (BUILT_IN_RINT):
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
       target = expand_builtin_mathfn (exp, target, subtarget);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_LCEIL:
-    case BUILT_IN_LCEILF:
-    case BUILT_IN_LCEILL:
-    case BUILT_IN_LLCEIL:
-    case BUILT_IN_LLCEILF:
-    case BUILT_IN_LLCEILL:
-    case BUILT_IN_LFLOOR:
-    case BUILT_IN_LFLOORF:
-    case BUILT_IN_LFLOORL:
-    case BUILT_IN_LLFLOOR:
-    case BUILT_IN_LLFLOORF:
-    case BUILT_IN_LLFLOORL:
+    CASE_FLT_FN (BUILT_IN_LCEIL):
+    CASE_FLT_FN (BUILT_IN_LLCEIL):
+    CASE_FLT_FN (BUILT_IN_LFLOOR):
+    CASE_FLT_FN (BUILT_IN_LLFLOOR):
       target = expand_builtin_int_roundingfn (exp, target, subtarget);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_POW:
-    case BUILT_IN_POWF:
-    case BUILT_IN_POWL:
+    CASE_FLT_FN (BUILT_IN_POW):
       target = expand_builtin_pow (exp, target, subtarget);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_POWI:
-    case BUILT_IN_POWIF:
-    case BUILT_IN_POWIL:
+    CASE_FLT_FN (BUILT_IN_POWI):
       target = expand_builtin_powi (exp, target, subtarget);
       if (target)
        return target;
       break;
 
-    case BUILT_IN_ATAN2:
-    case BUILT_IN_ATAN2F:
-    case BUILT_IN_ATAN2L:
-    case BUILT_IN_LDEXP:
-    case BUILT_IN_LDEXPF:
-    case BUILT_IN_LDEXPL:
-    case BUILT_IN_FMOD:
-    case BUILT_IN_FMODF:
-    case BUILT_IN_FMODL:
-    case BUILT_IN_DREM:
-    case BUILT_IN_DREMF:
-    case BUILT_IN_DREML:
+    CASE_FLT_FN (BUILT_IN_ATAN2):
+    CASE_FLT_FN (BUILT_IN_LDEXP):
+    CASE_FLT_FN (BUILT_IN_FMOD):
+    CASE_FLT_FN (BUILT_IN_DREM):
       if (! flag_unsafe_math_optimizations)
        break;
       target = expand_builtin_mathfn_2 (exp, target, subtarget);
@@ -5673,12 +5696,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
-    case BUILT_IN_COS:
-    case BUILT_IN_COSF:
-    case BUILT_IN_COSL:
+    CASE_FLT_FN (BUILT_IN_SIN):
+    CASE_FLT_FN (BUILT_IN_COS):
       if (! flag_unsafe_math_optimizations)
        break;
       target = expand_builtin_mathfn_3 (exp, target, subtarget);
@@ -5686,6 +5705,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
+    CASE_FLT_FN (BUILT_IN_SINCOS):
+      if (! flag_unsafe_math_optimizations)
+       break;
+      target = expand_builtin_sincos (exp);
+      if (target)
+       return target;
+      break;
+
     case BUILT_IN_APPLY_ARGS:
       return expand_builtin_apply_args ();
 
@@ -5712,7 +5739,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
          rtx ops[3];
 
          for (t = arglist, i = 0; t; t = TREE_CHAIN (t), i++)
-           ops[i] = expand_expr (TREE_VALUE (t), NULL_RTX, VOIDmode, 0);
+           ops[i] = expand_normal (TREE_VALUE (t));
 
          return expand_builtin_apply (ops[0], ops[1], ops[2]);
        }
@@ -5722,8 +5749,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
         memory returned by __builtin_apply.  */
     case BUILT_IN_RETURN:
       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
-       expand_builtin_return (expand_expr (TREE_VALUE (arglist),
-                                           NULL_RTX, VOIDmode, 0));
+       expand_builtin_return (expand_normal (TREE_VALUE (arglist)));
       return const0_rtx;
 
     case BUILT_IN_SAVEREGS:
@@ -5771,9 +5797,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       expand_stack_restore (TREE_VALUE (arglist));
       return const0_rtx;
 
-    case BUILT_IN_FFS:
-    case BUILT_IN_FFSL:
-    case BUILT_IN_FFSLL:
+    CASE_INT_FN (BUILT_IN_FFS):
     case BUILT_IN_FFSIMAX:
       target = expand_builtin_unop (target_mode, arglist, target,
                                    subtarget, ffs_optab);
@@ -5781,9 +5805,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_CLZ:
-    case BUILT_IN_CLZL:
-    case BUILT_IN_CLZLL:
+    CASE_INT_FN (BUILT_IN_CLZ):
     case BUILT_IN_CLZIMAX:
       target = expand_builtin_unop (target_mode, arglist, target,
                                    subtarget, clz_optab);
@@ -5791,9 +5813,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_CTZ:
-    case BUILT_IN_CTZL:
-    case BUILT_IN_CTZLL:
+    CASE_INT_FN (BUILT_IN_CTZ):
     case BUILT_IN_CTZIMAX:
       target = expand_builtin_unop (target_mode, arglist, target,
                                    subtarget, ctz_optab);
@@ -5801,9 +5821,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_POPCOUNT:
-    case BUILT_IN_POPCOUNTL:
-    case BUILT_IN_POPCOUNTLL:
+    CASE_INT_FN (BUILT_IN_POPCOUNT):
     case BUILT_IN_POPCOUNTIMAX:
       target = expand_builtin_unop (target_mode, arglist, target,
                                    subtarget, popcount_optab);
@@ -5811,9 +5829,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_PARITY:
-    case BUILT_IN_PARITYL:
-    case BUILT_IN_PARITYLL:
+    CASE_INT_FN (BUILT_IN_PARITY):
     case BUILT_IN_PARITYIMAX:
       target = expand_builtin_unop (target_mode, arglist, target,
                                    subtarget, parity_optab);
@@ -5828,7 +5844,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_STRCPY:
-      target = expand_builtin_strcpy (exp, target, mode);
+      target = expand_builtin_strcpy (fndecl, arglist, target, mode);
       if (target)
        return target;
       break;
@@ -5846,7 +5862,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       break;
 
     case BUILT_IN_STRCAT:
-      target = expand_builtin_strcat (arglist, TREE_TYPE (exp), target, mode);
+      target = expand_builtin_strcat (fndecl, arglist, target, mode);
       if (target)
        return target;
       break;
@@ -5966,9 +5982,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       else
        {
          rtx buf_addr = expand_expr (TREE_VALUE (arglist), subtarget,
-                                     VOIDmode, 0);
-         rtx value = expand_expr (TREE_VALUE (TREE_CHAIN (arglist)),
-                                  NULL_RTX, VOIDmode, 0);
+                                     VOIDmode, EXPAND_NORMAL);
+         rtx value = expand_normal (TREE_VALUE (TREE_CHAIN (arglist)));
 
          if (value != const1_rtx)
            {
@@ -5992,7 +6007,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
       if (validate_arglist (arglist, POINTER_TYPE, VOID_TYPE))
        {
          rtx buf_addr
-           = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+           = expand_normal (TREE_VALUE (arglist));
 
          expand_builtin_update_setjmp_buf (buf_addr);
          return const0_rtx;
@@ -6044,9 +6059,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
        return target;
       break;
 
-    case BUILT_IN_SIGNBIT:
-    case BUILT_IN_SIGNBITF:
-    case BUILT_IN_SIGNBITL:
+    CASE_FLT_FN (BUILT_IN_SIGNBIT):
       target = expand_builtin_signbit (exp, target);
       if (target)
        return target;
@@ -6119,7 +6132,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_ADD_2:
     case BUILT_IN_FETCH_AND_ADD_4:
     case BUILT_IN_FETCH_AND_ADD_8:
-      target = expand_builtin_sync_operation (arglist, PLUS,
+    case BUILT_IN_FETCH_AND_ADD_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_ADD_1);
+      target = expand_builtin_sync_operation (mode, arglist, PLUS,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6129,7 +6144,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_SUB_2:
     case BUILT_IN_FETCH_AND_SUB_4:
     case BUILT_IN_FETCH_AND_SUB_8:
-      target = expand_builtin_sync_operation (arglist, MINUS,
+    case BUILT_IN_FETCH_AND_SUB_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_SUB_1);
+      target = expand_builtin_sync_operation (mode, arglist, MINUS,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6139,7 +6156,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_OR_2:
     case BUILT_IN_FETCH_AND_OR_4:
     case BUILT_IN_FETCH_AND_OR_8:
-      target = expand_builtin_sync_operation (arglist, IOR,
+    case BUILT_IN_FETCH_AND_OR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_OR_1);
+      target = expand_builtin_sync_operation (mode, arglist, IOR,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6149,7 +6168,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_AND_2:
     case BUILT_IN_FETCH_AND_AND_4:
     case BUILT_IN_FETCH_AND_AND_8:
-      target = expand_builtin_sync_operation (arglist, AND,
+    case BUILT_IN_FETCH_AND_AND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_AND_1);
+      target = expand_builtin_sync_operation (mode, arglist, AND,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6159,7 +6180,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_XOR_2:
     case BUILT_IN_FETCH_AND_XOR_4:
     case BUILT_IN_FETCH_AND_XOR_8:
-      target = expand_builtin_sync_operation (arglist, XOR,
+    case BUILT_IN_FETCH_AND_XOR_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_XOR_1);
+      target = expand_builtin_sync_operation (mode, arglist, XOR,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6169,7 +6192,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_FETCH_AND_NAND_2:
     case BUILT_IN_FETCH_AND_NAND_4:
     case BUILT_IN_FETCH_AND_NAND_8:
-      target = expand_builtin_sync_operation (arglist, NOT,
+    case BUILT_IN_FETCH_AND_NAND_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_FETCH_AND_NAND_1);
+      target = expand_builtin_sync_operation (mode, arglist, NOT,
                                              false, target, ignore);
       if (target)
        return target;
@@ -6179,7 +6204,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_ADD_AND_FETCH_2:
     case BUILT_IN_ADD_AND_FETCH_4:
     case BUILT_IN_ADD_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, PLUS,
+    case BUILT_IN_ADD_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_ADD_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, PLUS,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6189,7 +6216,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_SUB_AND_FETCH_2:
     case BUILT_IN_SUB_AND_FETCH_4:
     case BUILT_IN_SUB_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, MINUS,
+    case BUILT_IN_SUB_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_SUB_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, MINUS,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6199,7 +6228,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_OR_AND_FETCH_2:
     case BUILT_IN_OR_AND_FETCH_4:
     case BUILT_IN_OR_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, IOR,
+    case BUILT_IN_OR_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_OR_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, IOR,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6209,7 +6240,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_AND_AND_FETCH_2:
     case BUILT_IN_AND_AND_FETCH_4:
     case BUILT_IN_AND_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, AND,
+    case BUILT_IN_AND_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_AND_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, AND,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6219,7 +6252,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_XOR_AND_FETCH_2:
     case BUILT_IN_XOR_AND_FETCH_4:
     case BUILT_IN_XOR_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, XOR,
+    case BUILT_IN_XOR_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_XOR_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, XOR,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6229,7 +6264,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_NAND_AND_FETCH_2:
     case BUILT_IN_NAND_AND_FETCH_4:
     case BUILT_IN_NAND_AND_FETCH_8:
-      target = expand_builtin_sync_operation (arglist, NOT,
+    case BUILT_IN_NAND_AND_FETCH_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_NAND_AND_FETCH_1);
+      target = expand_builtin_sync_operation (mode, arglist, NOT,
                                              true, target, ignore);
       if (target)
        return target;
@@ -6239,11 +6276,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_BOOL_COMPARE_AND_SWAP_2:
     case BUILT_IN_BOOL_COMPARE_AND_SWAP_4:
     case BUILT_IN_BOOL_COMPARE_AND_SWAP_8:
+    case BUILT_IN_BOOL_COMPARE_AND_SWAP_16:
       if (mode == VOIDmode)
        mode = TYPE_MODE (boolean_type_node);
       if (!target || !register_operand (target, mode))
        target = gen_reg_rtx (mode);
-      target = expand_builtin_compare_and_swap (arglist, true, target);
+
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_BOOL_COMPARE_AND_SWAP_1);
+      target = expand_builtin_compare_and_swap (mode, arglist, true, target);
       if (target)
        return target;
       break;
@@ -6252,7 +6292,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_VAL_COMPARE_AND_SWAP_2:
     case BUILT_IN_VAL_COMPARE_AND_SWAP_4:
     case BUILT_IN_VAL_COMPARE_AND_SWAP_8:
-      target = expand_builtin_compare_and_swap (arglist, false, target);
+    case BUILT_IN_VAL_COMPARE_AND_SWAP_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_VAL_COMPARE_AND_SWAP_1);
+      target = expand_builtin_compare_and_swap (mode, arglist, false, target);
       if (target)
        return target;
       break;
@@ -6261,7 +6303,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_LOCK_TEST_AND_SET_2:
     case BUILT_IN_LOCK_TEST_AND_SET_4:
     case BUILT_IN_LOCK_TEST_AND_SET_8:
-      target = expand_builtin_lock_test_and_set (arglist, target);
+    case BUILT_IN_LOCK_TEST_AND_SET_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_TEST_AND_SET_1);
+      target = expand_builtin_lock_test_and_set (mode, arglist, target);
       if (target)
        return target;
       break;
@@ -6270,7 +6314,9 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
     case BUILT_IN_LOCK_RELEASE_2:
     case BUILT_IN_LOCK_RELEASE_4:
     case BUILT_IN_LOCK_RELEASE_8:
-      expand_builtin_lock_release (arglist);
+    case BUILT_IN_LOCK_RELEASE_16:
+      mode = get_builtin_sync_mode (fcode - BUILT_IN_LOCK_RELEASE_1);
+      expand_builtin_lock_release (mode, arglist);
       return const0_rtx;
 
     case BUILT_IN_SYNCHRONIZE:
@@ -6587,6 +6633,7 @@ integer_valued_real_p (tree t)
        real_trunc (&cint, TYPE_MODE (TREE_TYPE (t)), &c);
        return real_identical (&c, &cint);
       }
+      break;
 
     case NOP_EXPR:
       {
@@ -6601,24 +6648,12 @@ integer_valued_real_p (tree t)
     case CALL_EXPR:
       switch (builtin_mathfn_code (t))
        {
-       case BUILT_IN_CEIL:
-       case BUILT_IN_CEILF:
-       case BUILT_IN_CEILL:
-       case BUILT_IN_FLOOR:
-       case BUILT_IN_FLOORF:
-       case BUILT_IN_FLOORL:
-       case BUILT_IN_NEARBYINT:
-       case BUILT_IN_NEARBYINTF:
-       case BUILT_IN_NEARBYINTL:
-       case BUILT_IN_RINT:
-       case BUILT_IN_RINTF:
-       case BUILT_IN_RINTL:
-       case BUILT_IN_ROUND:
-       case BUILT_IN_ROUNDF:
-       case BUILT_IN_ROUNDL:
-       case BUILT_IN_TRUNC:
-       case BUILT_IN_TRUNCF:
-       case BUILT_IN_TRUNCL:
+       CASE_FLT_FN (BUILT_IN_CEIL):
+       CASE_FLT_FN (BUILT_IN_FLOOR):
+       CASE_FLT_FN (BUILT_IN_NEARBYINT):
+       CASE_FLT_FN (BUILT_IN_RINT):
+       CASE_FLT_FN (BUILT_IN_ROUND):
+       CASE_FLT_FN (BUILT_IN_TRUNC):
          return true;
 
        default:
@@ -7209,30 +7244,18 @@ fold_builtin_int_roundingfn (tree fndecl, tree arglist)
 
          switch (DECL_FUNCTION_CODE (fndecl))
            {
-           case BUILT_IN_LFLOOR:
-           case BUILT_IN_LFLOORF:
-           case BUILT_IN_LFLOORL:
-           case BUILT_IN_LLFLOOR:
-           case BUILT_IN_LLFLOORF:
-           case BUILT_IN_LLFLOORL:
+           CASE_FLT_FN (BUILT_IN_LFLOOR):
+           CASE_FLT_FN (BUILT_IN_LLFLOOR):
              real_floor (&r, TYPE_MODE (ftype), &x);
              break;
 
-           case BUILT_IN_LCEIL:
-           case BUILT_IN_LCEILF:
-           case BUILT_IN_LCEILL:
-           case BUILT_IN_LLCEIL:
-           case BUILT_IN_LLCEILF:
-           case BUILT_IN_LLCEILL:
+           CASE_FLT_FN (BUILT_IN_LCEIL):
+           CASE_FLT_FN (BUILT_IN_LLCEIL):
              real_ceil (&r, TYPE_MODE (ftype), &x);
              break;
 
-           case BUILT_IN_LROUND:
-           case BUILT_IN_LROUNDF:
-           case BUILT_IN_LROUNDL:
-           case BUILT_IN_LLROUND:
-           case BUILT_IN_LLROUNDF:
-           case BUILT_IN_LLROUNDL:
+           CASE_FLT_FN (BUILT_IN_LROUND):
+           CASE_FLT_FN (BUILT_IN_LLROUND):
              real_round (&r, TYPE_MODE (ftype), &x);
              break;
 
@@ -7290,9 +7313,7 @@ fold_builtin_bitop (tree fndecl, tree arglist)
 
       switch (DECL_FUNCTION_CODE (fndecl))
        {
-       case BUILT_IN_FFS:
-       case BUILT_IN_FFSL:
-       case BUILT_IN_FFSLL:
+       CASE_INT_FN (BUILT_IN_FFS):
          if (lo != 0)
            result = exact_log2 (lo & -lo) + 1;
          else if (hi != 0)
@@ -7301,9 +7322,7 @@ fold_builtin_bitop (tree fndecl, tree arglist)
            result = 0;
          break;
 
-       case BUILT_IN_CLZ:
-       case BUILT_IN_CLZL:
-       case BUILT_IN_CLZLL:
+       CASE_INT_FN (BUILT_IN_CLZ):
          if (hi != 0)
            result = width - floor_log2 (hi) - 1 - HOST_BITS_PER_WIDE_INT;
          else if (lo != 0)
@@ -7312,9 +7331,7 @@ fold_builtin_bitop (tree fndecl, tree arglist)
            result = width;
          break;
 
-       case BUILT_IN_CTZ:
-       case BUILT_IN_CTZL:
-       case BUILT_IN_CTZLL:
+       CASE_INT_FN (BUILT_IN_CTZ):
          if (lo != 0)
            result = exact_log2 (lo & -lo);
          else if (hi != 0)
@@ -7323,9 +7340,7 @@ fold_builtin_bitop (tree fndecl, tree arglist)
            result = width;
          break;
 
-       case BUILT_IN_POPCOUNT:
-       case BUILT_IN_POPCOUNTL:
-       case BUILT_IN_POPCOUNTLL:
+       CASE_INT_FN (BUILT_IN_POPCOUNT):
          result = 0;
          while (lo)
            result++, lo &= lo - 1;
@@ -7333,9 +7348,7 @@ fold_builtin_bitop (tree fndecl, tree arglist)
            result++, hi &= hi - 1;
          break;
 
-       case BUILT_IN_PARITY:
-       case BUILT_IN_PARITYL:
-       case BUILT_IN_PARITYLL:
+       CASE_INT_FN (BUILT_IN_PARITY):
          result = 0;
          while (lo)
            result++, lo &= lo - 1;
@@ -7420,49 +7433,35 @@ fold_builtin_logarithm (tree fndecl, tree arglist,
 
          switch (fcode)
          {
-         case BUILT_IN_EXP:
-         case BUILT_IN_EXPF:
-         case BUILT_IN_EXPL:
+         CASE_FLT_FN (BUILT_IN_EXP):
            /* Prepare to do logN(exp(exponent) -> exponent*logN(e).  */
            x = build_real (type,
                            real_value_truncate (TYPE_MODE (type), dconste));
            exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
            break;
-         case BUILT_IN_EXP2:
-         case BUILT_IN_EXP2F:
-         case BUILT_IN_EXP2L:
+         CASE_FLT_FN (BUILT_IN_EXP2):
            /* Prepare to do logN(exp2(exponent) -> exponent*logN(2).  */
            x = build_real (type, dconst2);
            exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
            break;
-         case BUILT_IN_EXP10:
-         case BUILT_IN_EXP10F:
-         case BUILT_IN_EXP10L:
-         case BUILT_IN_POW10:
-         case BUILT_IN_POW10F:
-         case BUILT_IN_POW10L:
+         CASE_FLT_FN (BUILT_IN_EXP10):
+         CASE_FLT_FN (BUILT_IN_POW10):
            /* Prepare to do logN(exp10(exponent) -> exponent*logN(10).  */
            x = build_real (type, dconst10);
            exponent = TREE_VALUE (TREE_OPERAND (arg, 1));
            break;
-         case BUILT_IN_SQRT:
-         case BUILT_IN_SQRTF:
-         case BUILT_IN_SQRTL:
+         CASE_FLT_FN (BUILT_IN_SQRT):
            /* Prepare to do logN(sqrt(x) -> 0.5*logN(x).  */
            x = TREE_VALUE (TREE_OPERAND (arg, 1));
            exponent = build_real (type, dconsthalf);
            break;
-         case BUILT_IN_CBRT:
-         case BUILT_IN_CBRTF:
-         case BUILT_IN_CBRTL:
+         CASE_FLT_FN (BUILT_IN_CBRT):
            /* Prepare to do logN(cbrt(x) -> (1/3)*logN(x).  */
            x = TREE_VALUE (TREE_OPERAND (arg, 1));
            exponent = build_real (type, real_value_truncate (TYPE_MODE (type),
                                                              dconstthird));
            break;
-         case BUILT_IN_POW:
-         case BUILT_IN_POWF:
-         case BUILT_IN_POWL:
+         CASE_FLT_FN (BUILT_IN_POW):
            /* Prepare to do logN(pow(x,exponent) -> exponent*logN(x).  */
            x = TREE_VALUE (TREE_OPERAND (arg, 1));
            exponent = TREE_VALUE (TREE_CHAIN (TREE_OPERAND (arg, 1)));
@@ -7975,7 +7974,9 @@ fold_builtin_memcmp (tree arglist)
   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       tree ind1 = fold_convert (integer_type_node,
                                build1 (INDIRECT_REF, cst_uchar_node,
                                        fold_convert (cst_uchar_ptr_node,
@@ -8027,7 +8028,9 @@ fold_builtin_strcmp (tree arglist)
   if (p2 && *p2 == '\0')
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       return fold_convert (integer_type_node,
                           build1 (INDIRECT_REF, cst_uchar_node,
                                   fold_convert (cst_uchar_ptr_node,
@@ -8038,7 +8041,9 @@ fold_builtin_strcmp (tree arglist)
   if (p1 && *p1 == '\0')
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       tree temp = fold_convert (integer_type_node,
                                build1 (INDIRECT_REF, cst_uchar_node,
                                        fold_convert (cst_uchar_ptr_node,
@@ -8096,7 +8101,9 @@ fold_builtin_strncmp (tree arglist)
       && tree_int_cst_sgn (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       return fold_convert (integer_type_node,
                           build1 (INDIRECT_REF, cst_uchar_node,
                                   fold_convert (cst_uchar_ptr_node,
@@ -8110,7 +8117,9 @@ fold_builtin_strncmp (tree arglist)
       && tree_int_cst_sgn (len) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       tree temp = fold_convert (integer_type_node,
                                build1 (INDIRECT_REF, cst_uchar_node,
                                        fold_convert (cst_uchar_ptr_node,
@@ -8123,7 +8132,9 @@ fold_builtin_strncmp (tree arglist)
   if (host_integerp (len, 1) && tree_low_cst (len, 1) == 1)
     {
       tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
-      tree cst_uchar_ptr_node = build_pointer_type (cst_uchar_node);
+      tree cst_uchar_ptr_node
+       = build_pointer_type_for_mode (cst_uchar_node, ptr_mode, true);
+
       tree ind1 = fold_convert (integer_type_node,
                                build1 (INDIRECT_REF, cst_uchar_node,
                                        fold_convert (cst_uchar_ptr_node,
@@ -8203,9 +8214,9 @@ fold_builtin_copysign (tree fndecl, tree arglist, tree type)
 
       c1 = TREE_REAL_CST (arg1);
       c2 = TREE_REAL_CST (arg2);
+      /* c1.sign := c2.sign.  */
       real_copysign (&c1, &c2);
       return build_real (type, c1);
-      c1.sign = c2.sign;
     }
 
   /* copysign(X, Y) is fabs(X) when Y is always non-negative.
@@ -8585,9 +8596,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     case BUILT_IN_STRLEN:
       return fold_builtin_strlen (arglist);
 
-    case BUILT_IN_FABS:
-    case BUILT_IN_FABSF:
-    case BUILT_IN_FABSL:
+    CASE_FLT_FN (BUILT_IN_FABS):
       return fold_builtin_fabs (arglist, type);
 
     case BUILT_IN_ABS:
@@ -8596,198 +8605,120 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     case BUILT_IN_IMAXABS:
       return fold_builtin_abs (arglist, type);
 
-    case BUILT_IN_CONJ:
-    case BUILT_IN_CONJF:
-    case BUILT_IN_CONJL:
+    CASE_FLT_FN (BUILT_IN_CONJ):
       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
        return fold_build1 (CONJ_EXPR, type, TREE_VALUE (arglist));
       break;
 
-    case BUILT_IN_CREAL:
-    case BUILT_IN_CREALF:
-    case BUILT_IN_CREALL:
+    CASE_FLT_FN (BUILT_IN_CREAL):
       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
         return non_lvalue (fold_build1 (REALPART_EXPR, type,
                                        TREE_VALUE (arglist)));
       break;
 
-    case BUILT_IN_CIMAG:
-    case BUILT_IN_CIMAGF:
-    case BUILT_IN_CIMAGL:
+    CASE_FLT_FN (BUILT_IN_CIMAG):
       if (validate_arglist (arglist, COMPLEX_TYPE, VOID_TYPE))
         return non_lvalue (fold_build1 (IMAGPART_EXPR, type,
                                        TREE_VALUE (arglist)));
       break;
 
-    case BUILT_IN_CABS:
-    case BUILT_IN_CABSF:
-    case BUILT_IN_CABSL:
+    CASE_FLT_FN (BUILT_IN_CABS):
       return fold_builtin_cabs (arglist, type);
 
-    case BUILT_IN_SQRT:
-    case BUILT_IN_SQRTF:
-    case BUILT_IN_SQRTL:
+    CASE_FLT_FN (BUILT_IN_SQRT):
       return fold_builtin_sqrt (arglist, type);
 
-    case BUILT_IN_CBRT:
-    case BUILT_IN_CBRTF:
-    case BUILT_IN_CBRTL:
+    CASE_FLT_FN (BUILT_IN_CBRT):
       return fold_builtin_cbrt (arglist, type);
 
-    case BUILT_IN_SIN:
-    case BUILT_IN_SINF:
-    case BUILT_IN_SINL:
+    CASE_FLT_FN (BUILT_IN_SIN):
       return fold_builtin_sin (arglist);
 
-    case BUILT_IN_COS:
-    case BUILT_IN_COSF:
-    case BUILT_IN_COSL:
+    CASE_FLT_FN (BUILT_IN_COS):
       return fold_builtin_cos (arglist, type, fndecl);
 
-    case BUILT_IN_EXP:
-    case BUILT_IN_EXPF:
-    case BUILT_IN_EXPL:
+    CASE_FLT_FN (BUILT_IN_EXP):
       return fold_builtin_exponent (fndecl, arglist, &dconste);
 
-    case BUILT_IN_EXP2:
-    case BUILT_IN_EXP2F:
-    case BUILT_IN_EXP2L:
+    CASE_FLT_FN (BUILT_IN_EXP2):
       return fold_builtin_exponent (fndecl, arglist, &dconst2);
 
-    case BUILT_IN_EXP10:
-    case BUILT_IN_EXP10F:
-    case BUILT_IN_EXP10L:
-    case BUILT_IN_POW10:
-    case BUILT_IN_POW10F:
-    case BUILT_IN_POW10L:
+    CASE_FLT_FN (BUILT_IN_EXP10):
+    CASE_FLT_FN (BUILT_IN_POW10):
       return fold_builtin_exponent (fndecl, arglist, &dconst10);
 
-    case BUILT_IN_LOG:
-    case BUILT_IN_LOGF:
-    case BUILT_IN_LOGL:
+    CASE_FLT_FN (BUILT_IN_LOG):
       return fold_builtin_logarithm (fndecl, arglist, &dconste);
 
-    case BUILT_IN_LOG2:
-    case BUILT_IN_LOG2F:
-    case BUILT_IN_LOG2L:
+    CASE_FLT_FN (BUILT_IN_LOG2):
       return fold_builtin_logarithm (fndecl, arglist, &dconst2);
 
-    case BUILT_IN_LOG10:
-    case BUILT_IN_LOG10F:
-    case BUILT_IN_LOG10L:
+    CASE_FLT_FN (BUILT_IN_LOG10):
       return fold_builtin_logarithm (fndecl, arglist, &dconst10);
 
-    case BUILT_IN_TAN:
-    case BUILT_IN_TANF:
-    case BUILT_IN_TANL:
+    CASE_FLT_FN (BUILT_IN_TAN):
       return fold_builtin_tan (arglist);
 
-    case BUILT_IN_ATAN:
-    case BUILT_IN_ATANF:
-    case BUILT_IN_ATANL:
+    CASE_FLT_FN (BUILT_IN_ATAN):
       return fold_builtin_atan (arglist, type);
 
-    case BUILT_IN_POW:
-    case BUILT_IN_POWF:
-    case BUILT_IN_POWL:
+    CASE_FLT_FN (BUILT_IN_POW):
       return fold_builtin_pow (fndecl, arglist, type);
 
-    case BUILT_IN_POWI:
-    case BUILT_IN_POWIF:
-    case BUILT_IN_POWIL:
+    CASE_FLT_FN (BUILT_IN_POWI):
       return fold_builtin_powi (fndecl, arglist, type);
 
-    case BUILT_IN_INF:
-    case BUILT_IN_INFF:
-    case BUILT_IN_INFL:
+    CASE_FLT_FN (BUILT_IN_INF):
+    case BUILT_IN_INFD32:
+    case BUILT_IN_INFD64:
+    case BUILT_IN_INFD128:
       return fold_builtin_inf (type, true);
 
-    case BUILT_IN_HUGE_VAL:
-    case BUILT_IN_HUGE_VALF:
-    case BUILT_IN_HUGE_VALL:
+    CASE_FLT_FN (BUILT_IN_HUGE_VAL):
       return fold_builtin_inf (type, false);
 
-    case BUILT_IN_NAN:
-    case BUILT_IN_NANF:
-    case BUILT_IN_NANL:
+    CASE_FLT_FN (BUILT_IN_NAN):
+    case BUILT_IN_NAND32:
+    case BUILT_IN_NAND64:
+    case BUILT_IN_NAND128:
       return fold_builtin_nan (arglist, type, true);
 
-    case BUILT_IN_NANS:
-    case BUILT_IN_NANSF:
-    case BUILT_IN_NANSL:
+    CASE_FLT_FN (BUILT_IN_NANS):
       return fold_builtin_nan (arglist, type, false);
 
-    case BUILT_IN_FLOOR:
-    case BUILT_IN_FLOORF:
-    case BUILT_IN_FLOORL:
+    CASE_FLT_FN (BUILT_IN_FLOOR):
       return fold_builtin_floor (fndecl, arglist);
 
-    case BUILT_IN_CEIL:
-    case BUILT_IN_CEILF:
-    case BUILT_IN_CEILL:
+    CASE_FLT_FN (BUILT_IN_CEIL):
       return fold_builtin_ceil (fndecl, arglist);
 
-    case BUILT_IN_TRUNC:
-    case BUILT_IN_TRUNCF:
-    case BUILT_IN_TRUNCL:
+    CASE_FLT_FN (BUILT_IN_TRUNC):
       return fold_builtin_trunc (fndecl, arglist);
 
-    case BUILT_IN_ROUND:
-    case BUILT_IN_ROUNDF:
-    case BUILT_IN_ROUNDL:
+    CASE_FLT_FN (BUILT_IN_ROUND):
       return fold_builtin_round (fndecl, arglist);
 
-    case BUILT_IN_NEARBYINT:
-    case BUILT_IN_NEARBYINTF:
-    case BUILT_IN_NEARBYINTL:
-    case BUILT_IN_RINT:
-    case BUILT_IN_RINTF:
-    case BUILT_IN_RINTL:
+    CASE_FLT_FN (BUILT_IN_NEARBYINT):
+    CASE_FLT_FN (BUILT_IN_RINT):
       return fold_trunc_transparent_mathfn (fndecl, arglist);
 
-    case BUILT_IN_LCEIL:
-    case BUILT_IN_LCEILF:
-    case BUILT_IN_LCEILL:
-    case BUILT_IN_LLCEIL:
-    case BUILT_IN_LLCEILF:
-    case BUILT_IN_LLCEILL:
-    case BUILT_IN_LFLOOR:
-    case BUILT_IN_LFLOORF:
-    case BUILT_IN_LFLOORL:
-    case BUILT_IN_LLFLOOR:
-    case BUILT_IN_LLFLOORF:
-    case BUILT_IN_LLFLOORL:
-    case BUILT_IN_LROUND:
-    case BUILT_IN_LROUNDF:
-    case BUILT_IN_LROUNDL:
-    case BUILT_IN_LLROUND:
-    case BUILT_IN_LLROUNDF:
-    case BUILT_IN_LLROUNDL:
+    CASE_FLT_FN (BUILT_IN_LCEIL):
+    CASE_FLT_FN (BUILT_IN_LLCEIL):
+    CASE_FLT_FN (BUILT_IN_LFLOOR):
+    CASE_FLT_FN (BUILT_IN_LLFLOOR):
+    CASE_FLT_FN (BUILT_IN_LROUND):   
+    CASE_FLT_FN (BUILT_IN_LLROUND):
       return fold_builtin_int_roundingfn (fndecl, arglist);
 
-    case BUILT_IN_LRINT:
-    case BUILT_IN_LRINTF:
-    case BUILT_IN_LRINTL:
-    case BUILT_IN_LLRINT:
-    case BUILT_IN_LLRINTF:
-    case BUILT_IN_LLRINTL:
+    CASE_FLT_FN (BUILT_IN_LRINT):
+    CASE_FLT_FN (BUILT_IN_LLRINT):
       return fold_fixed_mathfn (fndecl, arglist);
 
-    case BUILT_IN_FFS:
-    case BUILT_IN_FFSL:
-    case BUILT_IN_FFSLL:
-    case BUILT_IN_CLZ:
-    case BUILT_IN_CLZL:
-    case BUILT_IN_CLZLL:
-    case BUILT_IN_CTZ:
-    case BUILT_IN_CTZL:
-    case BUILT_IN_CTZLL:
-    case BUILT_IN_POPCOUNT:
-    case BUILT_IN_POPCOUNTL:
-    case BUILT_IN_POPCOUNTLL:
-    case BUILT_IN_PARITY:
-    case BUILT_IN_PARITYL:
-    case BUILT_IN_PARITYLL:
+    CASE_INT_FN (BUILT_IN_FFS):
+    CASE_INT_FN (BUILT_IN_CLZ):
+    CASE_INT_FN (BUILT_IN_CTZ):
+    CASE_INT_FN (BUILT_IN_POPCOUNT):
+    CASE_INT_FN (BUILT_IN_PARITY):
       return fold_builtin_bitop (fndecl, arglist);
 
     case BUILT_IN_MEMCPY:
@@ -8799,9 +8730,7 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     case BUILT_IN_MEMMOVE:
       return fold_builtin_memmove (arglist, type);
 
-    case BUILT_IN_SIGNBIT:
-    case BUILT_IN_SIGNBITF:
-    case BUILT_IN_SIGNBITL:
+    CASE_FLT_FN (BUILT_IN_SIGNBIT):
       return fold_builtin_signbit (fndecl, arglist);
 
     case BUILT_IN_ISASCII:
@@ -8813,24 +8742,25 @@ fold_builtin_1 (tree fndecl, tree arglist, bool ignore)
     case BUILT_IN_ISDIGIT:
       return fold_builtin_isdigit (arglist);
 
-    case BUILT_IN_COPYSIGN:
-    case BUILT_IN_COPYSIGNF:
-    case BUILT_IN_COPYSIGNL:
+    CASE_FLT_FN (BUILT_IN_COPYSIGN):
       return fold_builtin_copysign (fndecl, arglist, type);
 
-    case BUILT_IN_FINITE:
-    case BUILT_IN_FINITEF:
-    case BUILT_IN_FINITEL:
+    CASE_FLT_FN (BUILT_IN_FINITE):
+    case BUILT_IN_FINITED32:
+    case BUILT_IN_FINITED64:
+    case BUILT_IN_FINITED128:
       return fold_builtin_classify (fndecl, arglist, BUILT_IN_FINITE);
 
-    case BUILT_IN_ISINF:
-    case BUILT_IN_ISINFF:
-    case BUILT_IN_ISINFL:
+    CASE_FLT_FN (BUILT_IN_ISINF):
+    case BUILT_IN_ISINFD32:
+    case BUILT_IN_ISINFD64:
+    case BUILT_IN_ISINFD128:
       return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISINF);
 
-    case BUILT_IN_ISNAN:
-    case BUILT_IN_ISNANF:
-    case BUILT_IN_ISNANL:
+    CASE_FLT_FN (BUILT_IN_ISNAN):
+    case BUILT_IN_ISNAND32:
+    case BUILT_IN_ISNAND64:
+    case BUILT_IN_ISNAND128:
       return fold_builtin_classify (fndecl, arglist, BUILT_IN_ISNAN);
 
     case BUILT_IN_ISGREATER:
@@ -8910,9 +8840,7 @@ fold_builtin (tree fndecl, tree arglist, bool ignore)
   tree exp = fold_builtin_1 (fndecl, arglist, ignore);
   if (exp)
     {
-      /* ??? Don't clobber shared nodes such as integer_zero_node.  */
-      if (CONSTANT_CLASS_P (exp))
-       exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp);
+      exp = build1 (NOP_EXPR, TREE_TYPE (exp), exp);
       TREE_NO_WARNING (exp) = 1;
     }
 
@@ -8998,6 +8926,18 @@ default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
   return NULL_RTX;
 }
 
+/* Default target-specific library builtin expander that does nothing.  */
+
+rtx
+default_expand_library_builtin (tree exp ATTRIBUTE_UNUSED,
+                       rtx target ATTRIBUTE_UNUSED,
+                       rtx subtarget ATTRIBUTE_UNUSED,
+                       enum machine_mode mode ATTRIBUTE_UNUSED,
+                       int ignore ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
 /* Returns true is EXP represents data that would potentially reside
    in a readonly section.  */
 
@@ -9071,8 +9011,10 @@ fold_builtin_strstr (tree arglist, tree type)
          return fold_convert (type, tem);
        }
 
+      /* The argument is const char *, and the result is char *, so we need
+        a type conversion here to avoid a warning.  */
       if (p2[0] == '\0')
-       return s1;
+       return fold_convert (type, s1);
 
       if (p2[1] != '\0')
        return 0;
@@ -9481,14 +9423,15 @@ tree
 fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
 {
   tree fn;
-  tree fn_fputc = unlocked ? implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
+  /* If we're using an unlocked function, assume the other unlocked
+     functions exist explicitly.  */
+  tree const fn_fputc = unlocked ? built_in_decls[BUILT_IN_FPUTC_UNLOCKED]
     : implicit_built_in_decls[BUILT_IN_FPUTC];
-  tree fn_fwrite = unlocked ? implicit_built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
+  tree const fn_fwrite = unlocked ? built_in_decls[BUILT_IN_FWRITE_UNLOCKED]
     : implicit_built_in_decls[BUILT_IN_FWRITE];
 
-  /* If the return value is used, or the replacement _DECL isn't
-     initialized, don't do the transformation.  */
-  if (!ignore || !fn_fputc || !fn_fwrite)
+  /* If the return value is used, don't do the transformation.  */
+  if (!ignore)
     return 0;
 
   /* Verify the arguments in the original call.  */
@@ -9550,6 +9493,11 @@ fold_builtin_fputs (tree arglist, bool ignore, bool unlocked, tree len)
       gcc_unreachable ();
     }
 
+  /* If the replacement _DECL isn't initialized, don't do the
+     transformation.  */
+  if (!fn)
+    return 0;
+
   /* These optimizations are only performed when the result is ignored,
      hence there's no need to cast the result to integer_type_node.  */
   return build_function_call_expr (fn, arglist);
@@ -9655,8 +9603,11 @@ fold_builtin_sprintf (tree arglist, int ignored)
   call = NULL_TREE;
   retval = NULL_TREE;
 
+  if (!init_target_chars())
+    return 0;
+
   /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, '%') == NULL)
+  if (strchr (fmt_str, target_percent) == NULL)
     {
       tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
 
@@ -9673,7 +9624,7 @@ fold_builtin_sprintf (tree arglist, int ignored)
     }
 
   /* If the format is "%s", use strcpy if the result isn't used.  */
-  else if (fmt_str && strcmp (fmt_str, "%s") == 0)
+  else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
     {
       tree fn, orig;
       fn = implicit_built_in_decls[BUILT_IN_STRCPY];
@@ -9970,12 +9921,15 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode)
   if (fmt_str == NULL)
     return;
 
+  if (!init_target_chars())
+    return;
+
   /* If the format doesn't contain % args or %%, we know its size.  */
-  if (strchr (fmt_str, '%') == 0)
+  if (strchr (fmt_str, target_percent) == 0)
     len = build_int_cstu (size_type_node, strlen (fmt_str));
   /* If the format is "%s" and first ... argument is a string literal,
      we know it too.  */
-  else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0)
+  else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
     {
       tree arg;
 
@@ -10119,10 +10073,11 @@ fold_builtin_memory_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
                }
              return 0;
            }
-         len = maxlen;
        }
+      else
+       maxlen = len;
 
-      if (tree_int_cst_lt (size, len))
+      if (tree_int_cst_lt (size, maxlen))
        return 0;
     }
 
@@ -10224,10 +10179,11 @@ fold_builtin_stxcpy_chk (tree fndecl, tree arglist, tree maxlen, bool ignore,
              return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)),
                                   build_function_call_expr (fn, arglist));
            }
-         len = maxlen;
        }
-      
-      if (! tree_int_cst_lt (len, size))
+      else
+       maxlen = len;
+
+      if (! tree_int_cst_lt (maxlen, size))
        return 0;
     }
 
@@ -10272,10 +10228,11 @@ fold_builtin_strncpy_chk (tree arglist, tree maxlen)
             if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
          if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
            return 0;
-         len = maxlen;
        }
+      else
+       maxlen = len;
 
-      if (tree_int_cst_lt (size, len))
+      if (tree_int_cst_lt (size, maxlen))
        return 0;
     }
 
@@ -10427,19 +10384,22 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
 
   len = NULL_TREE;
 
+  if (!init_target_chars())
+    return 0;
+
   /* Check whether the format is a literal string constant.  */
   fmt_str = c_getstr (fmt);
   if (fmt_str != NULL)
     {
       /* If the format doesn't contain % args or %%, we know the size.  */
-      if (strchr (fmt_str, '%') == 0)
+      if (strchr (fmt_str, target_percent) == 0)
        {
          if (fcode != BUILT_IN_SPRINTF_CHK || arglist == NULL_TREE)
            len = build_int_cstu (size_type_node, strlen (fmt_str));
        }
       /* If the format is "%s" and first ... argument is a string literal,
         we know the size too.  */
-      else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, "%s") == 0)
+      else if (fcode == BUILT_IN_SPRINTF_CHK && strcmp (fmt_str, target_percent_s) == 0)
        {
          tree arg;
 
@@ -10468,7 +10428,7 @@ fold_builtin_sprintf_chk (tree arglist, enum built_in_function fcode)
     {
       if (fmt_str == NULL)
        return 0;
-      if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s"))
+      if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
        return 0;
     }
 
@@ -10541,13 +10501,17 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen,
             if SIZE is >= MAXLEN, never convert to __ocs_fail ().  */
          if (maxlen == NULL_TREE || ! host_integerp (maxlen, 1))
            return 0;
-         len = maxlen;
        }
+      else
+       maxlen = len;
 
-      if (tree_int_cst_lt (size, len))
+      if (tree_int_cst_lt (size, maxlen))
        return 0;
     }
 
+  if (!init_target_chars())
+    return 0;
+
   /* Only convert __{,v}snprintf_chk to {,v}snprintf if flag is 0
      or if format doesn't contain % chars or is "%s".  */
   if (! integer_zerop (flag))
@@ -10555,7 +10519,7 @@ fold_builtin_snprintf_chk (tree arglist, tree maxlen,
       fmt_str = c_getstr (fmt);
       if (fmt_str == NULL)
        return 0;
-      if (strchr (fmt_str, '%') != NULL && strcmp (fmt_str, "%s"))
+      if (strchr (fmt_str, target_percent) != NULL && strcmp (fmt_str, target_percent_s))
        return 0;
     }
 
@@ -10618,8 +10582,10 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
 
   if (fcode == BUILT_IN_PRINTF_UNLOCKED)
     {
-      fn_putchar = implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
-      fn_puts = implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED];
+      /* If we're using an unlocked function, assume the other
+        unlocked functions exist explicitly.  */
+      fn_putchar = built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED];
+      fn_puts = built_in_decls[BUILT_IN_PUTS_UNLOCKED];
     }
   else
     {
@@ -10627,11 +10593,14 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
       fn_puts = implicit_built_in_decls[BUILT_IN_PUTS];
     }
 
-  if (strcmp (fmt_str, "%s") == 0 || strchr (fmt_str, '%') == NULL)
+  if (!init_target_chars())
+    return 0;
+  
+  if (strcmp (fmt_str, target_percent_s) == 0 || strchr (fmt_str, target_percent) == NULL)
     {
       const char *str;
 
-      if (strcmp (fmt_str, "%s") == 0)
+      if (strcmp (fmt_str, target_percent_s) == 0)
        {
          if (fcode == BUILT_IN_VPRINTF || fcode == BUILT_IN_VPRINTF_CHK)
            return 0;
@@ -10672,7 +10641,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
        {
          /* If the string was "string\n", call puts("string").  */
          size_t len = strlen (str);
-         if (str[len - 1] == '\n')
+         if ((unsigned char)str[len - 1] == target_newline)
            {
              /* Create a NUL-terminated string that's one char shorter
                 than the original, stripping off the trailing '\n'.  */
@@ -10696,7 +10665,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
     return 0;
 
   /* If the format specifier was "%s\n", call __builtin_puts(arg).  */
-  else if (strcmp (fmt_str, "%s\n") == 0)
+  else if (strcmp (fmt_str, target_percent_s_newline) == 0)
     {
       if (! arglist
          || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
@@ -10706,7 +10675,7 @@ fold_builtin_printf (tree fndecl, tree arglist, bool ignore,
     }
 
   /* If the format specifier was "%c", call __builtin_putchar(arg).  */
-  else if (strcmp (fmt_str, "%c") == 0)
+  else if (strcmp (fmt_str, target_percent_c) == 0)
     {
       if (! arglist
          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
@@ -10774,8 +10743,10 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
 
   if (fcode == BUILT_IN_FPRINTF_UNLOCKED)
     {
-      fn_fputc = implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
-      fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
+      /* If we're using an unlocked function, assume the other
+        unlocked functions exist explicitly.  */
+      fn_fputc = built_in_decls[BUILT_IN_FPUTC_UNLOCKED];
+      fn_fputs = built_in_decls[BUILT_IN_FPUTS_UNLOCKED];
     }
   else
     {
@@ -10783,8 +10754,11 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
       fn_fputs = implicit_built_in_decls[BUILT_IN_FPUTS];
     }
 
+  if (!init_target_chars())
+    return 0;
+  
   /* If the format doesn't contain % args or %%, use strcpy.  */
-  if (strchr (fmt_str, '%') == NULL)
+  if (strchr (fmt_str, target_percent) == NULL)
     {
       if (fcode != BUILT_IN_VFPRINTF && fcode != BUILT_IN_VFPRINTF_CHK
          && arglist)
@@ -10814,7 +10788,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
     return 0;
 
   /* If the format specifier was "%s", call __builtin_fputs (arg, fp).  */
-  else if (strcmp (fmt_str, "%s") == 0)
+  else if (strcmp (fmt_str, target_percent_s) == 0)
     {
       if (! arglist
          || ! POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (arglist)))
@@ -10827,7 +10801,7 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
     }
 
   /* If the format specifier was "%c", call __builtin_fputc (arg, fp).  */
-  else if (strcmp (fmt_str, "%c") == 0)
+  else if (strcmp (fmt_str, target_percent_c) == 0)
     {
       if (! arglist
          || TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != INTEGER_TYPE
@@ -10845,3 +10819,37 @@ fold_builtin_fprintf (tree fndecl, tree arglist, bool ignore,
   call = build_function_call_expr (fn, arglist);
   return fold_convert (TREE_TYPE (TREE_TYPE (fndecl)), call);
 }
+
+/* Initialize format string characters in the target charset.  */
+
+static bool
+init_target_chars (void)
+{
+  static bool init;
+  if (!init)
+    {
+      target_newline = lang_hooks.to_target_charset ('\n');
+      target_percent = lang_hooks.to_target_charset ('%');
+      target_c = lang_hooks.to_target_charset ('c');
+      target_s = lang_hooks.to_target_charset ('s');
+      if (target_newline == 0 || target_percent == 0 || target_c == 0
+         || target_s == 0)
+       return false;
+
+      target_percent_c[0] = target_percent;
+      target_percent_c[1] = target_c;
+      target_percent_c[2] = '\0';
+
+      target_percent_s[0] = target_percent;
+      target_percent_s[1] = target_s;
+      target_percent_s[2] = '\0';
+
+      target_percent_s_newline[0] = target_percent;
+      target_percent_s_newline[1] = target_s;
+      target_percent_s_newline[2] = target_newline;
+      target_percent_s_newline[3] = '\0';
+      
+      init = true;
+    }
+  return true;
+}