OSDN Git Service

* config/rs6000/rs6000-protos.h (rs6000_field_alignment): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 6dbb7e0..ad99417 100644 (file)
@@ -80,6 +80,18 @@ int rs6000_altivec_vrsave;
 /* String from -mvrsave= option.  */
 const char *rs6000_altivec_vrsave_string;
 
+/* Nonzero if we want SPE ABI extensions.  */
+int rs6000_spe_abi;
+
+/* Whether isel instructions should be generated.  */
+int rs6000_isel;
+
+/* Nonzero if we have FPRs.  */
+int rs6000_fprs = 1;
+
+/* String from -misel=.  */
+const char *rs6000_isel_string;
+
 /* Set to non-zero once AIX common-mode calls have been defined.  */
 static int common_mode_defined;
 
@@ -117,6 +129,14 @@ const char *rs6000_debug_name;
 int rs6000_debug_stack;                /* debug stack applications */
 int rs6000_debug_arg;          /* debug argument handling */
 
+const char *rs6000_traceback_name;
+static enum {
+  traceback_default = 0,
+  traceback_none,
+  traceback_part,
+  traceback_full
+} rs6000_traceback;
+
 /* Flag to say the TOC is initialized */
 int toc_initialized;
 char toc_label_name[10];
@@ -131,6 +151,17 @@ static int rs6000_sr_alias_set;
 int rs6000_default_long_calls;
 const char *rs6000_longcall_switch;
 
+struct builtin_description
+{
+  /* mask is not const because we're going to alter it below.  This
+     nonsense will go away when we rewrite the -march infrastructure
+     to give us more target flag bits.  */
+  unsigned int mask;
+  const enum insn_code icode;
+  const char *const name;
+  const enum rs6000_builtins code;
+};
+
 static void rs6000_add_gc_roots PARAMS ((void));
 static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
 static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
@@ -140,6 +171,9 @@ static rtx rs6000_generate_compare PARAMS ((enum rtx_code));
 static void rs6000_maybe_dead PARAMS ((rtx));
 static void rs6000_emit_stack_tie PARAMS ((void));
 static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
+static void emit_frame_save PARAMS ((rtx, rtx, enum machine_mode,
+                                    unsigned int, int, int));
+static rtx gen_frame_mem_offset PARAMS ((enum machine_mode, rtx, int));
 static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int));
 static unsigned rs6000_hash_constant PARAMS ((rtx));
 static unsigned toc_hash_function PARAMS ((const void *));
@@ -191,16 +225,30 @@ static rtx rs6000_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
 static rtx rs6000_expand_ternop_builtin PARAMS ((enum insn_code, tree, rtx));
 static rtx rs6000_expand_builtin PARAMS ((tree, rtx, rtx, enum machine_mode, int));
 static void altivec_init_builtins PARAMS ((void));
+static void rs6000_common_init_builtins PARAMS ((void));
+
+static void enable_mask_for_builtins PARAMS ((struct builtin_description *,
+                                             int, enum rs6000_builtins,
+                                             enum rs6000_builtins));
+static void spe_init_builtins PARAMS ((void));
+static rtx spe_expand_builtin PARAMS ((tree, rtx, bool *));
+static rtx spe_expand_predicate_builtin PARAMS ((enum insn_code, tree, rtx));
+static rtx spe_expand_evsel_builtin PARAMS ((enum insn_code, tree, rtx));
+static int rs6000_emit_int_cmove PARAMS ((rtx, rtx, rtx, rtx));
+
 static rtx altivec_expand_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_ld_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_st_builtin PARAMS ((tree, rtx, bool *));
+static rtx altivec_expand_dst_builtin PARAMS ((tree, rtx, bool *));
 static rtx altivec_expand_abs_builtin PARAMS ((enum insn_code, tree, rtx));
 static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));
 static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));
 static void rs6000_parse_abi_options PARAMS ((void));
 static void rs6000_parse_vrsave_option PARAMS ((void));
+static void rs6000_parse_isel_option PARAMS ((void));
 static int first_altivec_reg_to_save PARAMS ((void));
 static unsigned int compute_vrsave_mask PARAMS ((void));
 static void is_altivec_return_reg PARAMS ((rtx, void *));
-int vrsave_operation PARAMS ((rtx, enum machine_mode));
 static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));
 static void altivec_frame_fixup PARAMS ((rtx, rtx, HOST_WIDE_INT));
 static int easy_vector_constant PARAMS ((rtx));
@@ -431,6 +479,9 @@ rs6000_override_options (default_cpu)
         {"7450", PROCESSOR_PPC7450,
             MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
             POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+        {"8540", PROCESSOR_PPC8540,
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"801", PROCESSOR_MPCCORE,
            MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -479,6 +530,9 @@ rs6000_override_options (default_cpu)
        }
     }
 
+  if (rs6000_cpu == PROCESSOR_PPC8540)
+    rs6000_isel = 1;
+
   /* If we are optimizing big endian systems for space, use the store
      multiple instructions.  */
   if (BYTES_BIG_ENDIAN && optimize_size)
@@ -554,6 +608,19 @@ rs6000_override_options (default_cpu)
        error ("unknown -mdebug-%s switch", rs6000_debug_name);
     }
 
+  if (rs6000_traceback_name)
+    {
+      if (! strncmp (rs6000_traceback_name, "full", 4))
+       rs6000_traceback = traceback_full;
+      else if (! strncmp (rs6000_traceback_name, "part", 4))
+       rs6000_traceback = traceback_part;
+      else if (! strncmp (rs6000_traceback_name, "no", 2))
+       rs6000_traceback = traceback_none;
+      else
+       error ("unknown -mtraceback arg `%s'; expecting `full', `partial' or `none'",
+              rs6000_traceback_name);
+    }
+
   /* Set size of long double */
   rs6000_long_double_type_size = 64;
   if (rs6000_long_double_size_string)
@@ -573,6 +640,16 @@ rs6000_override_options (default_cpu)
   /* Handle -mvrsave= option.  */
   rs6000_parse_vrsave_option ();
 
+  /* Handle -misel= option.  */
+  rs6000_parse_isel_option ();
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
+  SUBSUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
   /* Handle -m(no-)longcall option.  This is a bit of a cheap hack,
      using TARGET_OPTIONS to handle a toggle switch, but we're out of
      bits in target_flags so TARGET_SWITCHES cannot be used.
@@ -596,13 +673,6 @@ rs6000_override_options (default_cpu)
     memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
 #endif
 
-#ifdef SUBTARGET_OVERRIDE_OPTIONS
-  SUBTARGET_OVERRIDE_OPTIONS;
-#endif
-#ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
-  SUBSUBTARGET_OVERRIDE_OPTIONS;
-#endif
-
   /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
      If -maix-struct-return or -msvr4-struct-return was explicitly
      used, don't override with the ABI default.  */
@@ -635,6 +705,21 @@ rs6000_override_options (default_cpu)
   init_machine_status = rs6000_init_machine_status;
 }
 
+/* Handle -misel= option.  */
+static void
+rs6000_parse_isel_option ()
+{
+  if (rs6000_isel_string == 0)
+    return;
+  else if (! strcmp (rs6000_isel_string, "yes"))
+    rs6000_isel = 1;
+  else if (! strcmp (rs6000_isel_string, "no"))
+    rs6000_isel = 0;
+  else
+    error ("unknown -misel= option specified: '%s'",
+         rs6000_isel_string);
+}
+
 /* Handle -mvrsave= options.  */
 static void
 rs6000_parse_vrsave_option ()
@@ -660,6 +745,10 @@ rs6000_parse_abi_options ()
     rs6000_altivec_abi = 1;
   else if (! strcmp (rs6000_abi_string, "no-altivec"))
     rs6000_altivec_abi = 0;
+  else if (! strcmp (rs6000_abi_string, "spe"))
+    rs6000_spe_abi = 1;
+  else if (! strcmp (rs6000_abi_string, "no-spe"))
+    rs6000_spe_abi = 0;
   else
     error ("unknown ABI specified: '%s'", rs6000_abi_string);
 }
@@ -1203,7 +1292,8 @@ easy_fp_constant (op, mode)
     return 0;
 
   /* Consider all constants with -msoft-float to be easy.  */
-  if (TARGET_SOFT_FLOAT && mode != DImode)
+  if ((TARGET_SOFT_FLOAT || !TARGET_FPRS)
+      && mode != DImode)
     return 1;
 
   /* If we are using V.4 style PIC, consider all constants to be hard.  */
@@ -1491,64 +1581,185 @@ mask_operand (op, mode)
   return c == -lsb;
 }
 
+/* Return 1 for the PowerPC64 rlwinm corner case.  */
+
+int
+mask_operand_wrap (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  HOST_WIDE_INT c, lsb;
+
+  if (GET_CODE (op) != CONST_INT)
+    return 0;
+
+  c = INTVAL (op);
+
+  if ((c & 0x80000001) != 0x80000001)
+    return 0;
+
+  c = ~c;
+  if (c == 0)
+    return 0;
+
+  lsb = c & -c;
+  c = ~c;
+  c &= -lsb;
+  lsb = c & -c;
+  return c == -lsb;
+}
+
 /* Return 1 if the operand is a constant that is a PowerPC64 mask.
    It is if there are no more than one 1->0 or 0->1 transitions.
-   Reject all ones and all zeros, since these should have been optimized
-   away and confuse the making of MB and ME.  */
+   Reject all zeros, since zero should have been optimized away and
+   confuses the making of MB and ME.  */
 
 int
 mask64_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == CONST_INT)
     {
       HOST_WIDE_INT c, lsb;
 
-      /* We don't change the number of transitions by inverting,
-        so make sure we start with the LS bit zero.  */
       c = INTVAL (op);
-      if (c & 1)
-       c = ~c;
 
-      /* Reject all zeros or all ones.  */
+      /* Reject all zeros.  */
       if (c == 0)
        return 0;
 
+      /* We don't change the number of transitions by inverting,
+        so make sure we start with the LS bit zero.  */
+      if (c & 1)
+       c = ~c;
+
       /* Find the transition, and check that all bits above are 1's.  */
       lsb = c & -c;
       return c == -lsb;
     }
-  else if (GET_CODE (op) == CONST_DOUBLE
-          && (mode == VOIDmode || mode == DImode))
+  return 0;
+}
+
+/* Like mask64_operand, but allow up to three transitions.  This
+   predicate is used by insn patterns that generate two rldicl or
+   rldicr machine insns.  */
+
+int
+mask64_2_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  if (GET_CODE (op) == CONST_INT)
     {
-      HOST_WIDE_INT low, high, lsb;
+      HOST_WIDE_INT c, lsb;
 
-      if (HOST_BITS_PER_WIDE_INT < 64)
-       high = CONST_DOUBLE_HIGH (op);
+      c = INTVAL (op);
 
-      low = CONST_DOUBLE_LOW (op);
-      if (low & 1)
-       {
-         if (HOST_BITS_PER_WIDE_INT < 64)
-           high = ~high;
-         low = ~low;
-       }
+      /* Disallow all zeros.  */
+      if (c == 0)
+       return 0;
 
-      if (low == 0)
-       {
-         if (HOST_BITS_PER_WIDE_INT >= 64 || high == 0)
-           return 0;
+      /* We don't change the number of transitions by inverting,
+        so make sure we start with the LS bit zero.  */
+      if (c & 1)
+       c = ~c;
 
-         lsb = high & -high;
-         return high == -lsb;
-       }
+      /* Find the first transition.  */
+      lsb = c & -c;
 
-      lsb = low & -low;
-      return low == -lsb && (HOST_BITS_PER_WIDE_INT >= 64 || high == ~0);
+      /* Invert to look for a second transition.  */
+      c = ~c;
+
+      /* Erase first transition.  */
+      c &= -lsb;
+
+      /* Find the second transition.  */
+      lsb = c & -c;
+
+      /* Invert to look for a third transition.  */
+      c = ~c;
+
+      /* Erase second transition.  */
+      c &= -lsb;
+
+      /* Find the third transition (if any).  */
+      lsb = c & -c;
+
+      /* Match if all the bits above are 1's (or c is zero).  */
+      return c == -lsb;
+    }
+  return 0;
+}
+
+/* Generates shifts and masks for a pair of rldicl or rldicr insns to
+   implement ANDing by the mask IN.  */
+void
+build_mask64_2_operands (in, out)
+     rtx in;
+     rtx *out;
+{
+#if HOST_BITS_PER_WIDE_INT >= 64
+  unsigned HOST_WIDE_INT c, lsb, m1, m2;
+  int shift;
+
+  if (GET_CODE (in) != CONST_INT)
+    abort ();
+
+  c = INTVAL (in);
+  if (c & 1)
+    {
+      /* Assume c initially something like 0x00fff000000fffff.  The idea
+        is to rotate the word so that the middle ^^^^^^ group of zeros
+        is at the MS end and can be cleared with an rldicl mask.  We then
+        rotate back and clear off the MS    ^^ group of zeros with a
+        second rldicl.  */
+      c = ~c;                  /*   c == 0xff000ffffff00000 */
+      lsb = c & -c;            /* lsb == 0x0000000000100000 */
+      m1 = -lsb;               /*  m1 == 0xfffffffffff00000 */
+      c = ~c;                  /*   c == 0x00fff000000fffff */
+      c &= -lsb;               /*   c == 0x00fff00000000000 */
+      lsb = c & -c;            /* lsb == 0x0000100000000000 */
+      c = ~c;                  /*   c == 0xff000fffffffffff */
+      c &= -lsb;               /*   c == 0xff00000000000000 */
+      shift = 0;
+      while ((lsb >>= 1) != 0)
+       shift++;                /* shift == 44 on exit from loop */
+      m1 <<= 64 - shift;       /*  m1 == 0xffffff0000000000 */
+      m1 = ~m1;                        /*  m1 == 0x000000ffffffffff */
+      m2 = ~c;                 /*  m2 == 0x00ffffffffffffff */
     }
   else
-    return 0;
+    {
+      /* Assume c initially something like 0xff000f0000000000.  The idea
+        is to rotate the word so that the     ^^^  middle group of zeros
+        is at the LS end and can be cleared with an rldicr mask.  We then
+        rotate back and clear off the LS group of ^^^^^^^^^^ zeros with
+        a second rldicr.  */
+      lsb = c & -c;            /* lsb == 0x0000010000000000 */
+      m2 = -lsb;               /*  m2 == 0xffffff0000000000 */
+      c = ~c;                  /*   c == 0x00fff0ffffffffff */
+      c &= -lsb;               /*   c == 0x00fff00000000000 */
+      lsb = c & -c;            /* lsb == 0x0000100000000000 */
+      c = ~c;                  /*   c == 0xff000fffffffffff */
+      c &= -lsb;               /*   c == 0xff00000000000000 */
+      shift = 0;
+      while ((lsb >>= 1) != 0)
+       shift++;                /* shift == 44 on exit from loop */
+      m1 = ~c;                 /*  m1 == 0x00ffffffffffffff */
+      m1 >>= shift;            /*  m1 == 0x0000000000000fff */
+      m1 = ~m1;                        /*  m1 == 0xfffffffffffff000 */
+    }
+
+  /* Note that when we only have two 0->1 and 1->0 transitions, one of the
+     masks will be all 1's.  We are guaranteed more than one transition.  */
+  out[0] = GEN_INT (64 - shift);
+  out[1] = GEN_INT (m1);
+  out[2] = GEN_INT (shift);
+  out[3] = GEN_INT (m2);
+#else
+  abort ();
+#endif
 }
 
 /* Return 1 if the operand is either a non-special register or a constant
@@ -1565,6 +1776,20 @@ and64_operand (op, mode)
   return (logical_operand (op, mode) || mask64_operand (op, mode));
 }
 
+/* Like the above, but also match constants that can be implemented
+   with two rldicl or rldicr insns.  */
+
+int
+and64_2_operand (op, mode)
+    rtx op;
+    enum machine_mode mode;
+{
+  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis. */
+    return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
+
+  return logical_operand (op, mode) || mask64_2_operand (op, mode);
+}
+
 /* Return 1 if the operand is either a non-special register or a
    constant that can be used as the operand of an RS/6000 logical AND insn.  */
 
@@ -1867,7 +2092,9 @@ rs6000_legitimize_address (x, oldx, mode)
           && GET_CODE (XEXP (x, 0)) == REG
           && GET_CODE (XEXP (x, 1)) != CONST_INT
           && GET_MODE_NUNITS (mode) == 1
-          && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || mode != DFmode)
+          && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+              || TARGET_POWERPC64
+              || mode != DFmode)
           && (TARGET_POWERPC64 || mode != DImode)
           && mode != TImode)
     {
@@ -1886,13 +2113,34 @@ rs6000_legitimize_address (x, oldx, mode)
       reg = force_reg (Pmode, x);
       return reg;
     }
+  else if (SPE_VECTOR_MODE (mode))
+    {
+      /* We accept [reg + reg] and [reg + OFFSET].  */
+
+      if (GET_CODE (x) == PLUS)
+      {
+        rtx op1 = XEXP (x, 0);
+        rtx op2 = XEXP (x, 1);
+
+        op1 = force_reg (Pmode, op1);
+
+        if (GET_CODE (op2) != REG
+            && (GET_CODE (op2) != CONST_INT
+                || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
+          op2 = force_reg (Pmode, op2);
+
+        return gen_rtx_PLUS (Pmode, op1, op2);
+      }
+
+      return force_reg (Pmode, x);
+    }
   else if (TARGET_ELF && TARGET_32BIT && TARGET_NO_TOC && ! flag_pic
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE 
           && CONSTANT_P (x)
           && GET_MODE_NUNITS (mode) == 1
           && (GET_MODE_BITSIZE (mode) <= 32
-              || (TARGET_HARD_FLOAT && mode == DFmode)))
+              || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
     {
       rtx reg = gen_reg_rtx (Pmode);
       emit_insn (gen_elf_high (reg, (x)));
@@ -1903,7 +2151,7 @@ rs6000_legitimize_address (x, oldx, mode)
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE 
           && CONSTANT_P (x)
-          && (TARGET_HARD_FLOAT || mode != DFmode)
+          && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
           && mode != DImode 
           && mode != TImode)
     {
@@ -1990,6 +2238,7 @@ rs6000_legitimize_reload_address (x, mode, opnum, type, ind_levels, win)
       && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
       && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
       && GET_CODE (XEXP (x, 1)) == CONST_INT
+       && !SPE_VECTOR_MODE (mode)
       && !ALTIVEC_VECTOR_MODE (mode))
     {
       HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
@@ -2078,6 +2327,7 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
     return 1;
   if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
       && !ALTIVEC_VECTOR_MODE (mode)
+      && !SPE_VECTOR_MODE (mode)
       && TARGET_UPDATE
       && LEGITIMATE_INDIRECT_ADDRESS_P (XEXP (x, 0), reg_ok_strict))
     return 1;
@@ -2095,7 +2345,9 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
   if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x, reg_ok_strict))
     return 1;
   if (mode != TImode
-      && (TARGET_HARD_FLOAT || TARGET_POWERPC64 || mode != DFmode)
+      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+         || TARGET_POWERPC64
+         || mode != DFmode)
       && (TARGET_POWERPC64 || mode != DImode)
       && LEGITIMATE_INDEXED_ADDRESS_P (x, reg_ok_strict))
     return 1;
@@ -2290,7 +2542,8 @@ rs6000_emit_move (dest, source, mode)
   if (! no_new_pseudos && GET_CODE (operands[0]) != REG)
     operands[1] = force_reg (mode, operands[1]);
 
-  if (mode == SFmode && ! TARGET_POWERPC && TARGET_HARD_FLOAT
+  if (mode == SFmode && ! TARGET_POWERPC
+      && TARGET_HARD_FLOAT && TARGET_FPRS
       && GET_CODE (operands[0]) == MEM)
     {
       int regnum;
@@ -2349,6 +2602,9 @@ rs6000_emit_move (dest, source, mode)
     case V8HImode:
     case V4SFmode:
     case V4SImode:
+    case V4HImode:
+    case V2SFmode:
+    case V2SImode:
       if (CONSTANT_P (operands[1])
          && !easy_vector_constant (operands[1]))
        operands[1] = force_const_mem (mode, operands[1]);
@@ -2634,6 +2890,8 @@ function_arg_boundary (mode, type)
 {
   if (DEFAULT_ABI == ABI_V4 && (mode == DImode || mode == DFmode))
     return 64;
+   else if (SPE_VECTOR_MODE (mode))
+     return 64;
   else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     return 128;
   else
@@ -2660,9 +2918,12 @@ function_arg_advance (cum, mode, type, named)
       else
        cum->words += RS6000_ARG_SIZE (mode, type);
     }
+  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
+          && named && cum->sysv_gregno <= GP_ARG_MAX_REG)
+    cum->sysv_gregno++;
   else if (DEFAULT_ABI == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT
+      if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode))
        {
          if (cum->fregno <= FP_ARG_V4_MAX_REG)
@@ -2686,11 +2947,12 @@ function_arg_advance (cum, mode, type, named)
          else 
            n_words = RS6000_ARG_SIZE (mode, type);
 
-         /* Long long is put in odd registers.  */
+         /* Long long and SPE vectors are put in odd registers.  */
          if (n_words == 2 && (gregno & 1) == 0)
            gregno += 1;
 
-         /* Long long is not split between registers and stack.  */
+         /* Long long and SPE vectors are not split between registers
+            and stack.  */
          if (gregno + n_words - 1 > GP_ARG_MAX_REG)
            {
              /* Long long is aligned on the stack.  */
@@ -2722,7 +2984,8 @@ function_arg_advance (cum, mode, type, named)
 
       cum->words += align + RS6000_ARG_SIZE (mode, type);
 
-      if (GET_MODE_CLASS (mode) == MODE_FLOAT && TARGET_HARD_FLOAT)
+      if (GET_MODE_CLASS (mode) == MODE_FLOAT
+         && TARGET_HARD_FLOAT && TARGET_FPRS)
        cum->fregno++;
 
       if (TARGET_DEBUG_ARG)
@@ -2775,14 +3038,17 @@ function_arg (cum, mode, type, named)
   if (mode == VOIDmode)
     {
       if (abi == ABI_V4
-         && TARGET_HARD_FLOAT
          && cum->nargs_prototype < 0
          && type && (cum->prototype || TARGET_NO_PROTOTYPE))
        {
-         return GEN_INT (cum->call_cookie
-                         | ((cum->fregno == FP_ARG_MIN_REG)
-                            ? CALL_V4_SET_FP_ARGS
-                            : CALL_V4_CLEAR_FP_ARGS));
+         /* For the SPE, we need to crxor CR6 always.  */
+         if (TARGET_SPE_ABI)
+           return GEN_INT (cum->call_cookie | CALL_V4_SET_FP_ARGS);
+         else if (TARGET_HARD_FLOAT && TARGET_FPRS)
+           return GEN_INT (cum->call_cookie
+                           | ((cum->fregno == FP_ARG_MIN_REG)
+                              ? CALL_V4_SET_FP_ARGS
+                              : CALL_V4_CLEAR_FP_ARGS));
        }
 
       return GEN_INT (cum->call_cookie);
@@ -2795,9 +3061,16 @@ function_arg (cum, mode, type, named)
       else
        return NULL;
     }
+  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode) && named)
+    {
+      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
+       return gen_rtx_REG (mode, cum->sysv_gregno);
+      else
+       return NULL;
+    }
   else if (abi == ABI_V4)
     {
-      if (TARGET_HARD_FLOAT
+      if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode))
        {
          if (cum->fregno <= FP_ARG_V4_MAX_REG)
@@ -2817,13 +3090,29 @@ function_arg (cum, mode, type, named)
          else 
            n_words = RS6000_ARG_SIZE (mode, type);
 
-         /* Long long is put in odd registers.  */
+         /* Long long and SPE vectors are put in odd registers.  */
          if (n_words == 2 && (gregno & 1) == 0)
            gregno += 1;
 
-         /* Long long is not split between registers and stack.  */
+         /* Long long and SPE vectors are not split between registers
+            and stack.  */
          if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
-           return gen_rtx_REG (mode, gregno);
+           {
+             /* SPE vectors in ... get split into 2 registers.  */
+             if (TARGET_SPE && TARGET_SPE_ABI
+                 && SPE_VECTOR_MODE (mode) && !named)
+               {
+                 rtx r1, r2;
+                 enum machine_mode m = GET_MODE_INNER (mode);
+
+                 r1 = gen_rtx_REG (m, gregno);
+                 r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
+                 r2 = gen_rtx_REG (m, gregno + 1);
+                 r2 = gen_rtx_EXPR_LIST (m, r2, GEN_INT (4));
+                 return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
+               }
+             return gen_rtx_REG (mode, gregno);
+           }
          else
            return NULL;
        }
@@ -3019,7 +3308,8 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
 
   /* Save FP registers if needed.  */
   if (DEFAULT_ABI == ABI_V4
-      && TARGET_HARD_FLOAT && ! no_rtl
+      && TARGET_HARD_FLOAT && TARGET_FPRS
+      && ! no_rtl
       && next_cum.fregno <= FP_ARG_V4_MAX_REG)
     {
       int fregno = next_cum.fregno;
@@ -3093,8 +3383,7 @@ rs6000_build_va_list ()
 /* Implement va_start.  */
 
 void
-rs6000_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+rs6000_va_start (valist, nextarg)
      tree valist;
      rtx nextarg;
 {
@@ -3105,7 +3394,7 @@ rs6000_va_start (stdarg_p, valist, nextarg)
   /* Only SVR4 needs something special.  */
   if (DEFAULT_ABI != ABI_V4)
     {
-      std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+      std_expand_builtin_va_start (valist, nextarg);
       return;
     }
 
@@ -3201,7 +3490,7 @@ rs6000_va_arg (valist, type)
       size = UNITS_PER_WORD;
       rsize = 1;
     }
-  else if (FLOAT_TYPE_P (type) && ! TARGET_SOFT_FLOAT)
+  else if (FLOAT_TYPE_P (type) && TARGET_HARD_FLOAT && TARGET_FPRS)
     {
       /* FP args go in FP registers, if present.  */
       indirect_p = 0;
@@ -3330,20 +3619,13 @@ rs6000_va_arg (valist, type)
 
 /* Builtins.  */
 
-#define def_builtin(MASK, NAME, TYPE, CODE)                            \
-do {                                                                   \
-  if ((MASK) & target_flags)                                           \
-    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL);      \
+#define def_builtin(MASK, NAME, TYPE, CODE)                    \
+do {                                                           \
+  if ((MASK) & target_flags)                                   \
+    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,     \
+                     NULL, NULL_TREE);                         \
 } while (0)
 
-struct builtin_description
-{
-  const unsigned int mask;
-  const enum insn_code icode;
-  const char *const name;
-  const enum rs6000_builtins code;
-};
-
 /* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
 
 static const struct builtin_description bdesc_3arg[] =
@@ -3385,7 +3667,7 @@ static const struct builtin_description bdesc_dst[] =
 
 /* Simple binary operations: VECc = foo (VECa, VECb).  */
 
-static const struct builtin_description bdesc_2arg[] =
+static struct builtin_description bdesc_2arg[] =
 {
   { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
   { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
@@ -3500,6 +3782,158 @@ static const struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
   { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
+
+  /* Place holder, leave as first spe builtin.  */
+  { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
+  { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
+  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
+  { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
+  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
+  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
+  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
+  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
+  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
+  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
+  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
+  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
+  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
+  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
+  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
+  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
+  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
+  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
+  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
+  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
+  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
+  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
+  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
+  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
+  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
+  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
+  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
+  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
+  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
+  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
+  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
+  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
+  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
+  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
+  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
+  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
+  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
+  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
+  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
+  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
+  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
+  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
+  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
+  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
+  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
+  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
+  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
+  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
+  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
+  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
+  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
+  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
+  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
+  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
+  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
+  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
+  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
+  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
+  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
+  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
+  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
+  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
+  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
+  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
+  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
+  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
+  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
+  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
+  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
+  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
+  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
+  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
+  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
+  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
+  { 0, CODE_FOR_spe_evmwlsmf, "__builtin_spe_evmwlsmf", SPE_BUILTIN_EVMWLSMF },
+  { 0, CODE_FOR_spe_evmwlsmfa, "__builtin_spe_evmwlsmfa", SPE_BUILTIN_EVMWLSMFA },
+  { 0, CODE_FOR_spe_evmwlsmfaaw, "__builtin_spe_evmwlsmfaaw", SPE_BUILTIN_EVMWLSMFAAW },
+  { 0, CODE_FOR_spe_evmwlsmfanw, "__builtin_spe_evmwlsmfanw", SPE_BUILTIN_EVMWLSMFANW },
+  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
+  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
+  { 0, CODE_FOR_spe_evmwlssf, "__builtin_spe_evmwlssf", SPE_BUILTIN_EVMWLSSF },
+  { 0, CODE_FOR_spe_evmwlssfa, "__builtin_spe_evmwlssfa", SPE_BUILTIN_EVMWLSSFA },
+  { 0, CODE_FOR_spe_evmwlssfaaw, "__builtin_spe_evmwlssfaaw", SPE_BUILTIN_EVMWLSSFAAW },
+  { 0, CODE_FOR_spe_evmwlssfanw, "__builtin_spe_evmwlssfanw", SPE_BUILTIN_EVMWLSSFANW },
+  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
+  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
+  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
+  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
+  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
+  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
+  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
+  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
+  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
+  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
+  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
+  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
+  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
+  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
+  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
+  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
+  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
+  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
+  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
+  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
+  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
+  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
+  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
+  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
+  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
+  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
+  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
+  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
+  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
+  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
+  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
+  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
+  { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
+
+  /* SPE binary operations expecting a 5-bit unsigned literal.  */
+  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
+
+  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
+  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
+  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
+  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
+  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
+  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
+  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
+  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
+  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
+  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
+  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
+  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
+  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
+  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
+  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
+  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
+  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
+  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
+  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
+  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
+  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
+  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
+  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
+  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
+  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
+  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
+
+  /* Place-holder.  Leave as last binary SPE builtin.  */
+  { 0, CODE_FOR_spe_evxor, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
 };
 
 /* AltiVec predicates.  */
@@ -3530,6 +3964,42 @@ static const struct builtin_description_predicates bdesc_altivec_preds[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
 };
 
+/* SPE predicates.  */
+static struct builtin_description bdesc_spe_predicates[] =
+{
+  /* Place-holder.  Leave as first.  */
+  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
+  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
+  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
+  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
+  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
+  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
+  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
+  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
+  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
+  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
+  /* Place-holder.  Leave as last.  */
+  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
+};
+
+/* SPE evsel predicates.  */
+static struct builtin_description bdesc_spe_evsel[] =
+{
+  /* Place-holder.  Leave as first.  */
+  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
+  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
+  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
+  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
+  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
+  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
+  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
+  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
+  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
+  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
+  /* Place-holder.  Leave as last.  */
+  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
+};
+
 /* ABS* opreations.  */
 
 static const struct builtin_description bdesc_abs[] =
@@ -3546,7 +4016,7 @@ static const struct builtin_description bdesc_abs[] =
 /* Simple unary operations: VECb = foo (unsigned literal) or VECb =
    foo (VECa).  */
 
-static const struct builtin_description bdesc_1arg[] =
+static struct builtin_description bdesc_1arg[] =
 {
   { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
   { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
@@ -3565,6 +4035,42 @@ static const struct builtin_description bdesc_1arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
   { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
+
+  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
+     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
+  { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
+  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
+  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
+  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
+  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
+  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
+  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
+  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
+  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
+  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
+  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
+  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
+  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
+  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
+  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
+  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
+  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
+  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
+  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
+  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
+  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
+  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
+  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
+  { 0, CODE_FOR_spe_evneg, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
+  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
+  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
+  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
+  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
+  { 0, CODE_FOR_spe_evsplatfi, "__builtin_spe_evsplatfi", SPE_BUILTIN_EVSPLATFI },
+  { 0, CODE_FOR_spe_evsplati, "__builtin_spe_evsplati", SPE_BUILTIN_EVSPLATI },
+
+  /* Place-holder.  Leave as last unary SPE builtin.  */
+  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
 };
 
 static rtx
@@ -3579,16 +4085,21 @@ rs6000_expand_unop_builtin (icode, arglist, target)
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
 
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
   /* If we got invalid arguments bail out before generating bad rtl.  */
   if (arg0 == error_mark_node)
     return const0_rtx;
 
-  switch (icode)
+  if (icode == CODE_FOR_altivec_vspltisb
+      || icode == CODE_FOR_altivec_vspltish
+      || icode == CODE_FOR_altivec_vspltisw
+      || icode == CODE_FOR_spe_evsplatfi
+      || icode == CODE_FOR_spe_evsplati)
     {
       /* Only allow 5-bit *signed* literals.  */
-    case CODE_FOR_altivec_vspltisb:
-    case CODE_FOR_altivec_vspltish:
-    case CODE_FOR_altivec_vspltisw:
       if (GET_CODE (op0) != CONST_INT
          || INTVAL (op0) > 0x1f
          || INTVAL (op0) < -0x1f)
@@ -3596,9 +4107,6 @@ rs6000_expand_unop_builtin (icode, arglist, target)
          error ("argument 1 must be a 5-bit signed literal");
          return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3667,29 +4175,45 @@ rs6000_expand_binop_builtin (icode, arglist, target)
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
 
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
   /* If we got invalid arguments bail out before generating bad rtl.  */
   if (arg0 == error_mark_node || arg1 == error_mark_node)
     return const0_rtx;
 
-  switch (icode)
+  if (icode == CODE_FOR_altivec_vcfux
+      || icode == CODE_FOR_altivec_vcfsx
+      || icode == CODE_FOR_altivec_vctsxs
+      || icode == CODE_FOR_altivec_vctuxs
+      || icode == CODE_FOR_altivec_vspltb
+      || icode == CODE_FOR_altivec_vsplth
+      || icode == CODE_FOR_altivec_vspltw
+      || icode == CODE_FOR_spe_evaddiw
+      || icode == CODE_FOR_spe_evldd
+      || icode == CODE_FOR_spe_evldh
+      || icode == CODE_FOR_spe_evldw
+      || icode == CODE_FOR_spe_evlhhesplat
+      || icode == CODE_FOR_spe_evlhhossplat
+      || icode == CODE_FOR_spe_evlhhousplat
+      || icode == CODE_FOR_spe_evlwhe
+      || icode == CODE_FOR_spe_evlwhos
+      || icode == CODE_FOR_spe_evlwhou
+      || icode == CODE_FOR_spe_evlwhsplat
+      || icode == CODE_FOR_spe_evlwwsplat
+      || icode == CODE_FOR_spe_evrlwi
+      || icode == CODE_FOR_spe_evslwi
+      || icode == CODE_FOR_spe_evsrwis
+      || icode == CODE_FOR_spe_evsrwiu)
     {
       /* Only allow 5-bit unsigned literals.  */
-    case CODE_FOR_altivec_vcfux:
-    case CODE_FOR_altivec_vcfsx:
-    case CODE_FOR_altivec_vctsxs:
-    case CODE_FOR_altivec_vctuxs:
-    case CODE_FOR_altivec_vspltb:
-    case CODE_FOR_altivec_vsplth:
-    case CODE_FOR_altivec_vspltw:
       if (TREE_CODE (arg1) != INTEGER_CST
          || TREE_INT_CST_LOW (arg1) & ~0x1f)
        {
          error ("argument 2 must be a 5-bit unsigned literal");
          return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3844,28 +4368,28 @@ rs6000_expand_ternop_builtin (icode, arglist, target)
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
   enum machine_mode mode2 = insn_data[icode].operand[3].mode;
 
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
   /* If we got invalid arguments bail out before generating bad rtl.  */
   if (arg0 == error_mark_node
       || arg1 == error_mark_node
       || arg2 == error_mark_node)
     return const0_rtx;
 
-  switch (icode)
+  if (icode == CODE_FOR_altivec_vsldoi_4sf
+      || icode == CODE_FOR_altivec_vsldoi_4si
+      || icode == CODE_FOR_altivec_vsldoi_8hi
+      || icode == CODE_FOR_altivec_vsldoi_16qi)
     {
       /* Only allow 4-bit unsigned literals.  */
-    case CODE_FOR_altivec_vsldoi_4sf:
-    case CODE_FOR_altivec_vsldoi_4si:
-    case CODE_FOR_altivec_vsldoi_8hi:
-    case CODE_FOR_altivec_vsldoi_16qi:
       if (TREE_CODE (arg2) != INTEGER_CST
          || TREE_INT_CST_LOW (arg2) & ~0xf)
        {
          error ("argument 3 must be a 4-bit unsigned literal");
          return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3888,189 +4412,213 @@ rs6000_expand_ternop_builtin (icode, arglist, target)
   return target;
 }
 
-/* Expand the builtin in EXP and store the result in TARGET.  Store
-   true in *EXPANDEDP if we found a builtin to expand.  */
+/* Expand the lvx builtins.  */
 static rtx
-altivec_expand_builtin (exp, target, expandedp)
+altivec_expand_ld_builtin (exp, target, expandedp)
      tree exp;
      rtx target;
      bool *expandedp;
 {
-  struct builtin_description *d;
-  struct builtin_description_predicates *dp;
-  size_t i;
-  enum insn_code icode;
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
-  tree arg0, arg1, arg2;
-  rtx op0, op1, op2, pat;
-  enum machine_mode tmode, mode0, mode1, mode2;
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
-
-  *expandedp = true;
+  tree arg0;
+  enum machine_mode tmode, mode0;
+  rtx pat, op0;
+  enum insn_code icode;
 
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
       icode = CODE_FOR_altivec_lvx_16qi;
-      arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      tmode = insn_data[icode].operand[0].mode;
-      mode0 = insn_data[icode].operand[1].mode;
-
-      if (target == 0
-         || GET_MODE (target) != tmode
-         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
-
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
-
+      break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
       icode = CODE_FOR_altivec_lvx_8hi;
-      arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      tmode = insn_data[icode].operand[0].mode;
-      mode0 = insn_data[icode].operand[1].mode;
-
-      if (target == 0
-         || GET_MODE (target) != tmode
-         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
-
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
-
+      break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
       icode = CODE_FOR_altivec_lvx_4si;
-      arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      tmode = insn_data[icode].operand[0].mode;
-      mode0 = insn_data[icode].operand[1].mode;
+      break;
+    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
+      icode = CODE_FOR_altivec_lvx_4sf;
+      break;
+    default:
+      *expandedp = false;
+      return NULL_RTX;
+    }
 
-      if (target == 0
-         || GET_MODE (target) != tmode
-         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
+  *expandedp = true;
 
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+  arg0 = TREE_VALUE (arglist);
+  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  tmode = insn_data[icode].operand[0].mode;
+  mode0 = insn_data[icode].operand[1].mode;
 
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
-
-    case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
-      icode = CODE_FOR_altivec_lvx_4sf;
-      arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      tmode = insn_data[icode].operand[0].mode;
-      mode0 = insn_data[icode].operand[1].mode;
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
 
-      if (target == 0
-         || GET_MODE (target) != tmode
-         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
 
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
 
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
+/* Expand the stvx builtins.  */
+static rtx
+altivec_expand_st_builtin (exp, target, expandedp)
+     tree exp;
+     rtx target ATTRIBUTE_UNUSED;
+     bool *expandedp;
+{
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  tree arg0, arg1;
+  enum machine_mode mode0, mode1;
+  rtx pat, op0, op1;
+  enum insn_code icode;
 
+  switch (fcode)
+    {
     case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
       icode = CODE_FOR_altivec_stvx_16qi;
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-      mode0 = insn_data[icode].operand[0].mode;
-      mode1 = insn_data[icode].operand[1].mode;
+      break;
+    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
+      icode = CODE_FOR_altivec_stvx_8hi;
+      break;
+    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
+      icode = CODE_FOR_altivec_stvx_4si;
+      break;
+    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
+      icode = CODE_FOR_altivec_stvx_4sf;
+      break;
+    default:
+      *expandedp = false;
+      return NULL_RTX;
+    }
 
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-      if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
-       op1 = copy_to_mode_reg (mode1, op1);
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  mode0 = insn_data[icode].operand[0].mode;
+  mode1 = insn_data[icode].operand[1].mode;
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_RTX;
+  if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
 
-    case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
-      icode = CODE_FOR_altivec_stvx_8hi;
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-      mode0 = insn_data[icode].operand[0].mode;
-      mode1 = insn_data[icode].operand[1].mode;
+  pat = GEN_FCN (icode) (op0, op1);
+  if (pat)
+    emit_insn (pat);
 
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-      if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
-       op1 = copy_to_mode_reg (mode1, op1);
+  *expandedp = true;
+  return NULL_RTX;
+}
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_RTX;
+/* Expand the dst builtins.  */
+static rtx
+altivec_expand_dst_builtin (exp, target, expandedp)
+     tree exp;
+     rtx target ATTRIBUTE_UNUSED;
+     bool *expandedp;
+{
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  tree arg0, arg1, arg2;
+  enum machine_mode mode0, mode1, mode2;
+  rtx pat, op0, op1, op2;
+  struct builtin_description *d;
+  size_t i;
 
-    case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
-      icode = CODE_FOR_altivec_stvx_4si;
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-      mode0 = insn_data[icode].operand[0].mode;
-      mode1 = insn_data[icode].operand[1].mode;
+  *expandedp = false;
 
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-      if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
-       op1 = copy_to_mode_reg (mode1, op1);
+  /* Handle DST variants.  */
+  d = (struct builtin_description *) bdesc_dst;
+  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
+    if (d->code == fcode)
+      {
+       arg0 = TREE_VALUE (arglist);
+       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+       mode0 = insn_data[d->icode].operand[0].mode;
+       mode1 = insn_data[d->icode].operand[1].mode;
+       mode2 = insn_data[d->icode].operand[2].mode;
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_RTX;
+       /* Invalid arguments, bail out before generating bad rtl.  */
+       if (arg0 == error_mark_node
+           || arg1 == error_mark_node
+           || arg2 == error_mark_node)
+         return const0_rtx;
 
-    case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
-      icode = CODE_FOR_altivec_stvx_4sf;
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-      mode0 = insn_data[icode].operand[0].mode;
-      mode1 = insn_data[icode].operand[1].mode;
+       if (TREE_CODE (arg2) != INTEGER_CST
+           || TREE_INT_CST_LOW (arg2) & ~0x3)
+         {
+           error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
+           return const0_rtx;
+         }
 
-      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
-      if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
-       op1 = copy_to_mode_reg (mode1, op1);
+       if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
+         op0 = copy_to_mode_reg (mode0, op0);
+       if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
+         op1 = copy_to_mode_reg (mode1, op1);
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_RTX;
+       pat = GEN_FCN (d->icode) (op0, op1, op2);
+       if (pat != 0)
+         emit_insn (pat);
+
+       *expandedp = true;
+       return NULL_RTX;
+      }
+
+  return NULL_RTX;
+}
+
+/* Expand the builtin in EXP and store the result in TARGET.  Store
+   true in *EXPANDEDP if we found a builtin to expand.  */
+static rtx
+altivec_expand_builtin (exp, target, expandedp)
+     tree exp;
+     rtx target;
+     bool *expandedp;
+{
+  struct builtin_description *d;
+  struct builtin_description_predicates *dp;
+  size_t i;
+  enum insn_code icode;
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0;
+  rtx op0, pat;
+  enum machine_mode tmode, mode0;
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+
+  target = altivec_expand_ld_builtin (exp, target, expandedp);
+  if (*expandedp)
+    return target;
 
+  target = altivec_expand_st_builtin (exp, target, expandedp);
+  if (*expandedp)
+    return target;
+
+  target = altivec_expand_dst_builtin (exp, target, expandedp);
+  if (*expandedp)
+    return target;
+
+  *expandedp = true;
+
+  switch (fcode)
+    {
     case ALTIVEC_BUILTIN_STVX:
       return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
     case ALTIVEC_BUILTIN_STVEBX:
@@ -4081,7 +4629,7 @@ altivec_expand_builtin (exp, target, expandedp)
       return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
     case ALTIVEC_BUILTIN_STVXL:
       return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
-  
+
     case ALTIVEC_BUILTIN_MFVSCR:
       icode = CODE_FOR_altivec_mfvscr;
       tmode = insn_data[icode].operand[0].mode;
@@ -4114,7 +4662,7 @@ altivec_expand_builtin (exp, target, expandedp)
       if (pat)
        emit_insn (pat);
       return NULL_RTX;
-      
+
     case ALTIVEC_BUILTIN_DSSALL:
       emit_insn (gen_altivec_dssall ());
       return NULL_RTX;
@@ -4143,46 +4691,6 @@ altivec_expand_builtin (exp, target, expandedp)
       return NULL_RTX;
     }
 
-  /* Handle DST variants.  */
-  d = (struct builtin_description *) bdesc_dst;
-  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
-    if (d->code == fcode)
-      {
-       arg0 = TREE_VALUE (arglist);
-       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
-       mode0 = insn_data[d->icode].operand[0].mode;
-       mode1 = insn_data[d->icode].operand[1].mode;
-       mode2 = insn_data[d->icode].operand[2].mode;
-
-       /* Invalid arguments, bail out before generating bad rtl.  */
-       if (arg0 == error_mark_node
-           || arg1 == error_mark_node
-           || arg2 == error_mark_node)
-         return const0_rtx;
-
-      if (TREE_CODE (arg2) != INTEGER_CST
-         || TREE_INT_CST_LOW (arg2) & ~0x3)
-       {
-         error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
-         return const0_rtx;
-       }
-
-       if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
-         op0 = copy_to_mode_reg (mode0, op0);
-       if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
-         op1 = copy_to_mode_reg (mode1, op1);
-
-       pat = GEN_FCN (d->icode) (op0, op1, op2);
-       if (pat != 0)
-         emit_insn (pat);
-
-       return NULL_RTX;
-      }
-
   /* Expand abs* operations.  */
   d = (struct builtin_description *) bdesc_abs;
   for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
@@ -4228,523 +4736,1003 @@ altivec_expand_builtin (exp, target, expandedp)
   return NULL_RTX;
 }
 
-/* Expand an expression EXP that calls a built-in function,
-   with result going to TARGET if that's convenient
-   (and in mode MODE if that's convenient).
-   SUBTARGET may be used as the target for computing one of EXP's operands.
-   IGNORE is nonzero if the value is to be ignored.  */
+/* Binops that need to be initialized manually, but can be expanded
+   automagically by rs6000_expand_binop_builtin.  */
+static struct builtin_description bdesc_2arg_spe[] =
+{
+  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
+  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
+  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
+  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
+  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
+  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
+  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
+  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
+  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
+  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
+  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
+  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
+  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
+  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
+  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
+  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
+  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
+  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
+  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
+  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
+  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
+  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
+};
+
+/* Expand the builtin in EXP and store the result in TARGET.  Store
+   true in *EXPANDEDP if we found a builtin to expand.
 
+   This expands the SPE builtins that are not simple unary and binary
+   operations.  */
 static rtx
-rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
+spe_expand_builtin (exp, target, expandedp)
      tree exp;
      rtx target;
-     rtx subtarget ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     int ignore ATTRIBUTE_UNUSED;
+     bool *expandedp;
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
+  tree arg1, arg0;
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  enum insn_code icode;
+  enum machine_mode tmode, mode0;
+  rtx pat, op0;
   struct builtin_description *d;
   size_t i;
-  rtx ret;
-  bool success;
-  
-  if (TARGET_ALTIVEC)
-    {
-      ret = altivec_expand_builtin (exp, target, &success);
 
-      if (success)
-       return ret;
-    }
+  *expandedp = true;
 
-  /* Handle simple unary operations.  */
-  d = (struct builtin_description *) bdesc_1arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
-    if (d->code == fcode)
-      return rs6000_expand_unop_builtin (d->icode, arglist, target);
+  /* Syntax check for a 5-bit unsigned immediate.  */
+  switch (fcode)
+    {
+    case SPE_BUILTIN_EVSTDD:
+    case SPE_BUILTIN_EVSTDH:
+    case SPE_BUILTIN_EVSTDW:
+    case SPE_BUILTIN_EVSTWHE:
+    case SPE_BUILTIN_EVSTWHO:
+    case SPE_BUILTIN_EVSTWWE:
+    case SPE_BUILTIN_EVSTWWO:
+      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      if (TREE_CODE (arg1) != INTEGER_CST
+         || TREE_INT_CST_LOW (arg1) & ~0x1f)
+       {
+         error ("argument 2 must be a 5-bit unsigned literal");
+         return const0_rtx;
+       }
+      break;
+    default:
+      break;
+    }
 
-  /* Handle simple binary operations.  */
-  d = (struct builtin_description *) bdesc_2arg;
-  for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+  d = (struct builtin_description *) bdesc_2arg_spe;
+  for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
     if (d->code == fcode)
       return rs6000_expand_binop_builtin (d->icode, arglist, target);
 
-  /* Handle simple ternary operations.  */
-  d = (struct builtin_description *) bdesc_3arg;
-  for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
+  d = (struct builtin_description *) bdesc_spe_predicates;
+  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
     if (d->code == fcode)
-      return rs6000_expand_ternop_builtin (d->icode, arglist, target);
+      return spe_expand_predicate_builtin (d->icode, arglist, target);
 
-  abort ();
-  return NULL_RTX;
-}
+  d = (struct builtin_description *) bdesc_spe_evsel;
+  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
+    if (d->code == fcode)
+      return spe_expand_evsel_builtin (d->icode, arglist, target);
 
-static void
-rs6000_init_builtins ()
-{
-  if (TARGET_ALTIVEC)
-    altivec_init_builtins ();
-}
+  switch (fcode)
+    {
+    case SPE_BUILTIN_EVSTDDX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
+    case SPE_BUILTIN_EVSTDHX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
+    case SPE_BUILTIN_EVSTDWX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
+    case SPE_BUILTIN_EVSTWHEX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
+    case SPE_BUILTIN_EVSTWHOX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
+    case SPE_BUILTIN_EVSTWWEX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
+    case SPE_BUILTIN_EVSTWWOX:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
+    case SPE_BUILTIN_EVSTDD:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
+    case SPE_BUILTIN_EVSTDH:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
+    case SPE_BUILTIN_EVSTDW:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
+    case SPE_BUILTIN_EVSTWHE:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
+    case SPE_BUILTIN_EVSTWHO:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
+    case SPE_BUILTIN_EVSTWWE:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
+    case SPE_BUILTIN_EVSTWWO:
+      return altivec_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
+    case SPE_BUILTIN_MFSPEFSCR:
+      icode = CODE_FOR_spe_mfspefscr;
+      tmode = insn_data[icode].operand[0].mode;
 
-static void
-altivec_init_builtins (void)
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+      
+      pat = GEN_FCN (icode) (target);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+    case SPE_BUILTIN_MTSPEFSCR:
+      icode = CODE_FOR_spe_mtspefscr;
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      mode0 = insn_data[icode].operand[0].mode;
+
+      if (arg0 == error_mark_node)
+       return const0_rtx;
+
+      if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
+
+      pat = GEN_FCN (icode) (op0);
+      if (pat)
+       emit_insn (pat);
+      return NULL_RTX;
+    default:
+      break;
+    }
+
+  *expandedp = false;
+  return NULL_RTX;
+}
+
+static rtx
+spe_expand_predicate_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
+{
+  rtx pat, scratch, tmp;
+  tree form = TREE_VALUE (arglist);
+  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+  int form_int;
+  enum rtx_code code;
+
+  if (TREE_CODE (form) != INTEGER_CST)
+    {
+      error ("argument 1 of __builtin_spe_predicate must be a constant");
+      return const0_rtx;
+    }
+  else
+    form_int = TREE_INT_CST_LOW (form);
+
+  if (mode0 != mode1)
+    abort ();
+
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return const0_rtx;
+
+  if (target == 0
+      || GET_MODE (target) != SImode
+      || ! (*insn_data[icode].operand[0].predicate) (target, SImode))
+    target = gen_reg_rtx (SImode);
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+
+  scratch = gen_reg_rtx (CCmode);
+
+  pat = GEN_FCN (icode) (scratch, op0, op1);
+  if (! pat)
+    return const0_rtx;
+  emit_insn (pat);
+
+  /* There are 4 variants for each predicate: _any_, _all_, _upper_,
+     _lower_.  We use one compare, but look in different bits of the
+     CR for each variant.
+
+     There are 2 elements in each SPE simd type (upper/lower).  The CR
+     bits are set as follows:
+
+     BIT0  | BIT 1  | BIT 2   | BIT 3
+     U     |   L    | (U | L) | (U & L)
+
+     So, for an "all" relationship, BIT 3 would be set.
+     For an "any" relationship, BIT 2 would be set.  Etc.
+
+     Following traditional nomenclature, these bits map to:
+
+     BIT0  | BIT 1  | BIT 2   | BIT 3
+     LT    | GT     | EQ      | OV
+
+     Later, we will generate rtl to look in the LT/EQ/EQ/OV bits.
+  */
+
+  switch (form_int)
+    {
+      /* All variant.  OV bit.  */
+    case 0:
+      /* We need to get to the OV bit, which is the ORDERED bit.  We
+        could generate (ordered:SI (reg:CC xx) (const_int 0)), but
+        that's ugly and will trigger a validate_condition_mode abort.
+        So let's just use another pattern.  */
+      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
+      return target;
+      /* Any variant.  EQ bit.  */
+    case 1:
+      code = EQ;
+      break;
+      /* Upper variant.  LT bit.  */
+    case 2:
+      code = LT;
+      break;
+      /* Lower variant.  GT bit.  */
+    case 3:
+      code = GT;
+      break;
+    default:
+      error ("argument 1 of __builtin_spe_predicate is out of range");
+      return const0_rtx;
+    }
+
+  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
+  emit_move_insn (target, tmp);
+
+  return target;
+}
+
+/* The evsel builtins look like this:
+
+     e = __builtin_spe_evsel_OP (a, b, c, d);
+
+   and work like this:
+
+     e[upper] = a[upper] *OP* b[upper] ? c[upper] : d[upper];
+     e[lower] = a[lower] *OP* b[lower] ? c[lower] : d[lower];
+*/
+
+static rtx
+spe_expand_evsel_builtin (icode, arglist, target)
+     enum insn_code icode;
+     tree arglist;
+     rtx target;
 {
+  rtx pat, scratch;
+  tree arg0 = TREE_VALUE (arglist);
+  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+
+  if (mode0 != mode1)
+    abort ();
+
+  if (arg0 == error_mark_node || arg1 == error_mark_node
+      || arg2 == error_mark_node || arg3 == error_mark_node)
+    return const0_rtx;
+
+  if (target == 0
+      || GET_MODE (target) != mode0
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode0))
+    target = gen_reg_rtx (mode0);
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[1].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode0, op1);
+  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
+    op2 = copy_to_mode_reg (mode0, op2);
+  if (! (*insn_data[icode].operand[1].predicate) (op3, mode1))
+    op3 = copy_to_mode_reg (mode0, op3);
+
+  /* Generate the compare.  */
+  scratch = gen_reg_rtx (CCmode);
+  pat = GEN_FCN (icode) (scratch, op0, op1);
+  if (! pat)
+    return const0_rtx;
+  emit_insn (pat);
+
+  if (mode0 == V2SImode)
+    emit_insn (gen_spe_evsel (target, op2, op3, scratch));
+  else
+    emit_insn (gen_spe_evsel_fs (target, op2, op3, scratch));
+
+  return target;
+}
+
+/* Expand an expression EXP that calls a built-in function,
+   with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
+
+static rtx
+rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
+     tree exp;
+     rtx target;
+     rtx subtarget ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int ignore ATTRIBUTE_UNUSED;
+{
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   struct builtin_description *d;
-  struct builtin_description_predicates *dp;
   size_t i;
+  rtx ret;
+  bool success;
+  
+  if (TARGET_ALTIVEC)
+    {
+      ret = altivec_expand_builtin (exp, target, &success);
 
-  tree endlink = void_list_node;
+      if (success)
+       return ret;
+    }
+  if (TARGET_SPE)
+    {
+      ret = spe_expand_builtin (exp, target, &success);
 
-  tree pint_type_node = build_pointer_type (integer_type_node);
-  tree pvoid_type_node = build_pointer_type (void_type_node);
-  tree pshort_type_node = build_pointer_type (short_integer_type_node);
-  tree pchar_type_node = build_pointer_type (char_type_node);
-  tree pfloat_type_node = build_pointer_type (float_type_node);
+      if (success)
+       return ret;
+    }
 
-  tree v4sf_ftype_v4sf_v4sf_v16qi
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V16QI_type_node,
-                                                           endlink))));
-  tree v4si_ftype_v4si_v4si_v16qi
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V16QI_type_node,
-                                                           endlink))));
-  tree v8hi_ftype_v8hi_v8hi_v16qi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V16QI_type_node,
-                                                           endlink))));
-  tree v16qi_ftype_v16qi_v16qi_v16qi
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V16QI_type_node,
-                                                           endlink))));
+  if (TARGET_ALTIVEC || TARGET_SPE)
+    {
+      /* Handle simple unary operations.  */
+      d = (struct builtin_description *) bdesc_1arg;
+      for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+       if (d->code == fcode)
+         return rs6000_expand_unop_builtin (d->icode, arglist, target);
 
-  /* V4SI foo (char).  */
-  tree v4si_ftype_char
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, char_type_node, endlink));
+      /* Handle simple binary operations.  */
+      d = (struct builtin_description *) bdesc_2arg;
+      for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+       if (d->code == fcode)
+         return rs6000_expand_binop_builtin (d->icode, arglist, target);
 
-  /* V8HI foo (char).  */
-  tree v8hi_ftype_char
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, char_type_node, endlink));
+      /* Handle simple ternary operations.  */
+      d = (struct builtin_description *) bdesc_3arg;
+      for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
+       if (d->code == fcode)
+         return rs6000_expand_ternop_builtin (d->icode, arglist, target);
+    }
 
-  /* V16QI foo (char).  */
-  tree v16qi_ftype_char
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, char_type_node, endlink));
-  /* V4SF foo (V4SF).  */
-  tree v4sf_ftype_v4sf
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node, endlink));
+  abort ();
+  return NULL_RTX;
+}
 
-  /* V4SI foo (int *).  */
-  tree v4si_ftype_pint
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, pint_type_node, endlink));
-  /* V8HI foo (short *).  */
-  tree v8hi_ftype_pshort
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, pshort_type_node, endlink));
-  /* V16QI foo (char *).  */
-  tree v16qi_ftype_pchar
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, pchar_type_node, endlink));
-  /* V4SF foo (float *).  */
-  tree v4sf_ftype_pfloat
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, pfloat_type_node, endlink));
+static void
+rs6000_init_builtins ()
+{
+  if (TARGET_SPE)
+    spe_init_builtins ();
+  if (TARGET_ALTIVEC)
+    altivec_init_builtins ();
+  if (TARGET_ALTIVEC || TARGET_SPE)
+    rs6000_common_init_builtins ();
+}
 
-  /* V8HI foo (V16QI).  */
-  tree v8hi_ftype_v16qi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node, endlink));
+/* Search through a set of builtins and enable the mask bits.
+   DESC is an array of builtins.
+   SIZE is the totaly number of builtins.
+   START is the builtin enum at which to start.
+   END is the builtin enum at which to end.  */
+static void
+enable_mask_for_builtins (desc, size, start, end)
+     struct builtin_description *desc;
+     int size;
+     enum rs6000_builtins start, end;
+{
+  int i;
 
-  /* void foo (void *, int, char/literal).  */
-  tree void_ftype_pvoid_int_char
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, pvoid_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
+  for (i = 0; i < size; ++i)
+    if (desc[i].code == start)
+      break;
 
-  /* void foo (int *, V4SI).  */
-  tree void_ftype_pint_v4si
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, pint_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
-  /* void foo (short *, V8HI).  */
-  tree void_ftype_pshort_v8hi
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, pshort_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                endlink)));
-  /* void foo (char *, V16QI).  */
-  tree void_ftype_pchar_v16qi
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, pchar_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                endlink)));
-  /* void foo (float *, V4SF).  */
-  tree void_ftype_pfloat_v4sf
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, pfloat_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                endlink)));
+  if (i == size)
+    return;
 
-  /* void foo (V4SI).  */
-  tree void_ftype_v4si
+  for (; i < size; ++i)
+    {
+      /* Flip all the bits on.  */
+      desc[i].mask = target_flags;
+      if (desc[i].code == end)
+       break;
+    }
+}
+
+static void
+spe_init_builtins ()
+{
+  tree endlink = void_list_node;
+  tree puint_type_node = build_pointer_type (unsigned_type_node);
+  tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
+  tree pv2si_type_node = build_pointer_type (V2SI_type_node);
+  struct builtin_description *d;
+  size_t i;
+
+  tree v2si_ftype_4_v2si
+    = build_function_type
+    (V2SI_type_node,
+     tree_cons (NULL_TREE, V2SI_type_node,
+               tree_cons (NULL_TREE, V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, V2SI_type_node,
+                                                endlink)))));
+
+  tree v2sf_ftype_4_v2sf
+    = build_function_type
+    (V2SF_type_node,
+     tree_cons (NULL_TREE, V2SF_type_node,
+               tree_cons (NULL_TREE, V2SF_type_node,
+                          tree_cons (NULL_TREE, V2SF_type_node,
+                                     tree_cons (NULL_TREE, V2SF_type_node,
+                                                endlink)))));
+
+  tree int_ftype_int_v2si_v2si
+    = build_function_type
+    (integer_type_node,
+     tree_cons (NULL_TREE, integer_type_node,
+               tree_cons (NULL_TREE, V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     endlink))));
+
+  tree int_ftype_int_v2sf_v2sf
+    = build_function_type
+    (integer_type_node,
+     tree_cons (NULL_TREE, integer_type_node,
+               tree_cons (NULL_TREE, V2SF_type_node,
+                          tree_cons (NULL_TREE, V2SF_type_node,
+                                     endlink))));
+
+  tree void_ftype_v2si_puint_int
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     endlink));
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, puint_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
 
-  /* void foo (vint, int, void *).  */
-  tree void_ftype_v4si_int_pvoid
+  tree void_ftype_v2si_puint_char
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, puint_type_node,
                                                 tree_cons (NULL_TREE,
-                                                           pvoid_type_node,
+                                                           char_type_node,
                                                            endlink))));
 
-  /* void foo (vchar, int, void *).  */
-  tree void_ftype_v16qi_int_pvoid
+  tree void_ftype_v2si_pv2si_int
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, pv2si_type_node,
                                                 tree_cons (NULL_TREE,
-                                                           pvoid_type_node,
+                                                           integer_type_node,
                                                            endlink))));
 
-  /* void foo (vshort, int, void *).  */
-  tree void_ftype_v8hi_int_pvoid
+  tree void_ftype_v2si_pv2si_char
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, pv2si_type_node,
                                                 tree_cons (NULL_TREE,
-                                                           pvoid_type_node,
+                                                           char_type_node,
                                                            endlink))));
 
-  /* void foo (char).  */
-  tree void_ftype_qi
+  tree void_ftype_int
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, char_type_node,
-                                     endlink));
+                          tree_cons (NULL_TREE, integer_type_node, endlink));
 
-  /* void foo (void).  */
-  tree void_ftype_void
-    = build_function_type (void_type_node, void_list_node);
+  tree int_ftype_void
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, void_type_node, endlink));
+
+  tree v2si_ftype_pv2si_int
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, pv2si_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+
+  tree v2si_ftype_puint_int
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, puint_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+
+  tree v2si_ftype_pushort_int
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, pushort_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+
+  /* The initialization of the simple binary and unary builtins is
+     done in rs6000_common_init_builtins, but we have to enable the
+     mask bits here manually because we have run out of `target_flags'
+     bits.  We really need to redesign this mask business.  */
+
+  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
+                           ARRAY_SIZE (bdesc_2arg),
+                           SPE_BUILTIN_EVADDW,
+                           SPE_BUILTIN_EVXOR);
+  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
+                           ARRAY_SIZE (bdesc_1arg),
+                           SPE_BUILTIN_EVABS,
+                           SPE_BUILTIN_EVSUBFUSIAAW);
+  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
+                           ARRAY_SIZE (bdesc_spe_predicates),
+                           SPE_BUILTIN_EVCMPEQ,
+                           SPE_BUILTIN_EVFSTSTLT);
+  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
+                           ARRAY_SIZE (bdesc_spe_evsel),
+                           SPE_BUILTIN_EVSEL_CMPGTS,
+                           SPE_BUILTIN_EVSEL_FSTSTEQ);
+
+  /* Initialize irregular SPE builtins.  */
+  
+  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
+  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
+  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
+  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
+  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
+  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
+  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
+  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
+  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
+  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
+  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
+  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
+  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
+  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
+  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
+  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
+
+  /* Loads.  */
+  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
+  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
+  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
+  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
+  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
+  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
+  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
+  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
+  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
+  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
+  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
+  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
+  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
+  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
+  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
+  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
+  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
+  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
+  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
+  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
+  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
+  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
+
+  /* Predicates.  */
+  d = (struct builtin_description *) bdesc_spe_predicates;
+  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
+    {
+      tree type;
+
+      switch (insn_data[d->icode].operand[1].mode)
+       {
+       case V2SImode:
+         type = int_ftype_int_v2si_v2si;
+         break;
+       case V2SFmode:
+         type = int_ftype_int_v2sf_v2sf;
+         break;
+       default:
+         abort ();
+       }
 
-  /* vshort foo (void).  */
+      def_builtin (d->mask, d->name, type, d->code);
+    }
+
+  /* Evsel predicates.  */
+  d = (struct builtin_description *) bdesc_spe_evsel;
+  for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
+    {
+      tree type;
+
+      switch (insn_data[d->icode].operand[1].mode)
+       {
+       case V2SImode:
+         type = v2si_ftype_4_v2si;
+         break;
+       case V2SFmode:
+         type = v2sf_ftype_4_v2sf;
+         break;
+       default:
+         abort ();
+       }
+
+      def_builtin (d->mask, d->name, type, d->code);
+    }
+}
+
+static void
+altivec_init_builtins ()
+{
+  struct builtin_description *d;
+  struct builtin_description_predicates *dp;
+  size_t i;
+  tree pfloat_type_node = build_pointer_type (float_type_node);
+  tree pint_type_node = build_pointer_type (integer_type_node);
+  tree pshort_type_node = build_pointer_type (short_integer_type_node);
+  tree pchar_type_node = build_pointer_type (char_type_node);
+
+  tree pvoid_type_node = build_pointer_type (void_type_node);
+
+  tree int_ftype_int_v4si_v4si
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, V4SI_type_node,
+                               V4SI_type_node, NULL_TREE);
+  tree v4sf_ftype_pfloat
+    = build_function_type_list (V4SF_type_node, pfloat_type_node, NULL_TREE);
+  tree void_ftype_pfloat_v4sf
+    = build_function_type_list (void_type_node,
+                               pfloat_type_node, V4SF_type_node, NULL_TREE);
+  tree v4si_ftype_pint
+    = build_function_type_list (V4SI_type_node, pint_type_node, NULL_TREE);  tree void_ftype_pint_v4si
+    = build_function_type_list (void_type_node,
+                               pint_type_node, V4SI_type_node, NULL_TREE);
+  tree v8hi_ftype_pshort
+    = build_function_type_list (V8HI_type_node, pshort_type_node, NULL_TREE);
+  tree void_ftype_pshort_v8hi
+    = build_function_type_list (void_type_node,
+                               pshort_type_node, V8HI_type_node, NULL_TREE);
+  tree v16qi_ftype_pchar
+    = build_function_type_list (V16QI_type_node, pchar_type_node, NULL_TREE);
+  tree void_ftype_pchar_v16qi
+    = build_function_type_list (void_type_node,
+                               pchar_type_node, V16QI_type_node, NULL_TREE);
+  tree void_ftype_v4si
+    = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
   tree v8hi_ftype_void
     = build_function_type (V8HI_type_node, void_list_node);
+  tree void_ftype_void
+    = build_function_type (void_type_node, void_list_node);
+  tree void_ftype_qi
+    = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
+  tree v16qi_ftype_int_pvoid
+    = build_function_type_list (V16QI_type_node,
+                               integer_type_node, pvoid_type_node, NULL_TREE);
+  tree v8hi_ftype_int_pvoid
+    = build_function_type_list (V8HI_type_node,
+                               integer_type_node, pvoid_type_node, NULL_TREE);
+  tree v4si_ftype_int_pvoid
+    = build_function_type_list (V4SI_type_node,
+                               integer_type_node, pvoid_type_node, NULL_TREE);
+  tree void_ftype_v4si_int_pvoid
+    = build_function_type_list (void_type_node,
+                               V4SI_type_node, integer_type_node,
+                               pvoid_type_node, NULL_TREE);
+  tree void_ftype_v16qi_int_pvoid
+    = build_function_type_list (void_type_node,
+                               V16QI_type_node, integer_type_node,
+                               pvoid_type_node, NULL_TREE);
+  tree void_ftype_v8hi_int_pvoid
+    = build_function_type_list (void_type_node,
+                               V8HI_type_node, integer_type_node,
+                               pvoid_type_node, NULL_TREE);
+  tree int_ftype_int_v8hi_v8hi
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, V8HI_type_node,
+                               V8HI_type_node, NULL_TREE);
+  tree int_ftype_int_v16qi_v16qi
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, V16QI_type_node,
+                               V16QI_type_node, NULL_TREE);
+  tree int_ftype_int_v4sf_v4sf
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, V4SF_type_node,
+                               V4SF_type_node, NULL_TREE);
+  tree v4si_ftype_v4si
+    = build_function_type_list (V4SI_type_node, V4SI_type_node, NULL_TREE);
+  tree v8hi_ftype_v8hi
+    = build_function_type_list (V8HI_type_node, V8HI_type_node, NULL_TREE);
+  tree v16qi_ftype_v16qi
+    = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
+  tree v4sf_ftype_v4sf
+    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
+  tree void_ftype_pvoid_int_char
+    = build_function_type_list (void_type_node,
+                               pvoid_type_node, integer_type_node,
+                               char_type_node, NULL_TREE);
+
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pfloat, ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf, ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pint, ALTIVEC_BUILTIN_LD_INTERNAL_4si);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL_4si);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pshort, ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi, ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pchar, ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi, ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSR);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEHX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVXL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_int_pvoid, ALTIVEC_BUILTIN_STVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_int_pvoid, ALTIVEC_BUILTIN_STVEHX);
+
+  /* Add the DST variants.  */
+  d = (struct builtin_description *) bdesc_dst;
+  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
+    def_builtin (d->mask, d->name, void_ftype_pvoid_int_char, d->code);
+
+  /* Initialize the predicates.  */
+  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
+  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
+    {
+      enum machine_mode mode1;
+      tree type;
+
+      mode1 = insn_data[dp->icode].operand[1].mode;
+
+      switch (mode1)
+       {
+       case V4SImode:
+         type = int_ftype_int_v4si_v4si;
+         break;
+       case V8HImode:
+         type = int_ftype_int_v8hi_v8hi;
+         break;
+       case V16QImode:
+         type = int_ftype_int_v16qi_v16qi;
+         break;
+       case V4SFmode:
+         type = int_ftype_int_v4sf_v4sf;
+         break;
+       default:
+         abort ();
+       }
+      
+      def_builtin (dp->mask, dp->name, type, dp->code);
+    }
+
+  /* Initialize the abs* operators.  */
+  d = (struct builtin_description *) bdesc_abs;
+  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
+    {
+      enum machine_mode mode0;
+      tree type;
+
+      mode0 = insn_data[d->icode].operand[0].mode;
+
+      switch (mode0)
+       {
+       case V4SImode:
+         type = v4si_ftype_v4si;
+         break;
+       case V8HImode:
+         type = v8hi_ftype_v8hi;
+         break;
+       case V16QImode:
+         type = v16qi_ftype_v16qi;
+         break;
+       case V4SFmode:
+         type = v4sf_ftype_v4sf;
+         break;
+       default:
+         abort ();
+       }
+      
+      def_builtin (d->mask, d->name, type, d->code);
+    }
+}
+
+static void
+rs6000_common_init_builtins ()
+{
+  struct builtin_description *d;
+  size_t i;
+
+  tree v4sf_ftype_v4sf_v4sf_v16qi
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SF_type_node,
+                               V16QI_type_node, NULL_TREE);
+  tree v4si_ftype_v4si_v4si_v16qi
+    = build_function_type_list (V4SI_type_node,
+                               V4SI_type_node, V4SI_type_node,
+                               V16QI_type_node, NULL_TREE);
+  tree v8hi_ftype_v8hi_v8hi_v16qi
+    = build_function_type_list (V8HI_type_node,
+                               V8HI_type_node, V8HI_type_node,
+                               V16QI_type_node, NULL_TREE);
+  tree v16qi_ftype_v16qi_v16qi_v16qi
+    = build_function_type_list (V16QI_type_node,
+                               V16QI_type_node, V16QI_type_node,
+                               V16QI_type_node, NULL_TREE);
+  tree v4si_ftype_char
+    = build_function_type_list (V4SI_type_node, char_type_node, NULL_TREE);
+  tree v8hi_ftype_char
+    = build_function_type_list (V8HI_type_node, char_type_node, NULL_TREE);
+  tree v16qi_ftype_char
+    = build_function_type_list (V16QI_type_node, char_type_node, NULL_TREE);
+  tree v8hi_ftype_v16qi
+    = build_function_type_list (V8HI_type_node, V16QI_type_node, NULL_TREE);
+  tree v4sf_ftype_v4sf
+    = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
+
+  tree v2si_ftype_v2si_v2si
+    = build_function_type_list (V2SI_type_node,
+                               V2SI_type_node, V2SI_type_node, NULL_TREE);
+
+  tree v2sf_ftype_v2sf_v2sf
+    = build_function_type_list (V2SF_type_node,
+                               V2SF_type_node, V2SF_type_node, NULL_TREE);
+
+  tree v2si_ftype_int_int
+    = build_function_type_list (V2SI_type_node,
+                               integer_type_node, integer_type_node,
+                               NULL_TREE);
+
+  tree v2si_ftype_v2si
+    = build_function_type_list (V2SI_type_node, V2SI_type_node, NULL_TREE);
+
+  tree v2sf_ftype_v2sf
+    = build_function_type_list (V2SF_type_node,
+                               V2SF_type_node, NULL_TREE);
+  
+  tree v2sf_ftype_v2si
+    = build_function_type_list (V2SF_type_node,
+                               V2SI_type_node, NULL_TREE);
+
+  tree v2si_ftype_v2sf
+    = build_function_type_list (V2SI_type_node,
+                               V2SF_type_node, NULL_TREE);
+
+  tree v2si_ftype_v2si_char
+    = build_function_type_list (V2SI_type_node,
+                               V2SI_type_node, char_type_node, NULL_TREE);
+
+  tree v2si_ftype_int_char
+    = build_function_type_list (V2SI_type_node,
+                               integer_type_node, char_type_node, NULL_TREE);
 
-  tree v4si_ftype_v4si_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
+  tree v2si_ftype_char
+    = build_function_type_list (V2SI_type_node, char_type_node, NULL_TREE);
 
-  /* These are for the unsigned 5 bit literals.  */
+  tree int_ftype_int_int
+    = build_function_type_list (integer_type_node,
+                               integer_type_node, integer_type_node,
+                               NULL_TREE);
 
+  tree v4si_ftype_v4si_v4si
+    = build_function_type_list (V4SI_type_node,
+                               V4SI_type_node, V4SI_type_node, NULL_TREE);
   tree v4sf_ftype_v4si_char
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, char_type_node,
-                                                endlink)));
+    = build_function_type_list (V4SF_type_node,
+                               V4SI_type_node, char_type_node, NULL_TREE);
   tree v4si_ftype_v4sf_char
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, char_type_node,
-                                                endlink)));
+    = build_function_type_list (V4SI_type_node,
+                               V4SF_type_node, char_type_node, NULL_TREE);
   tree v4si_ftype_v4si_char
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, char_type_node,
-                                                endlink)));
+    = build_function_type_list (V4SI_type_node,
+                               V4SI_type_node, char_type_node, NULL_TREE);
   tree v8hi_ftype_v8hi_char
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, char_type_node,
-                                                endlink)));
+    = build_function_type_list (V8HI_type_node,
+                               V8HI_type_node, char_type_node, NULL_TREE);
   tree v16qi_ftype_v16qi_char
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, char_type_node,
-                                                endlink)));
-
-  /* These are for the unsigned 4 bit literals.  */
-
+    = build_function_type_list (V16QI_type_node,
+                               V16QI_type_node, char_type_node, NULL_TREE);
   tree v16qi_ftype_v16qi_v16qi_char
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
-
+    = build_function_type_list (V16QI_type_node,
+                               V16QI_type_node, V16QI_type_node,
+                               char_type_node, NULL_TREE);
   tree v8hi_ftype_v8hi_v8hi_char
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
-
+    = build_function_type_list (V8HI_type_node,
+                               V8HI_type_node, V8HI_type_node,
+                               char_type_node, NULL_TREE);
   tree v4si_ftype_v4si_v4si_char
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
-
+    = build_function_type_list (V4SI_type_node,
+                               V4SI_type_node, V4SI_type_node,
+                               char_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf_v4sf_char
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
-
-  /* End of 4 bit literals.  */
-
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SF_type_node,
+                               char_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf_v4sf
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                endlink)));
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SF_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf_v4sf_v4si
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           V4SI_type_node,
-                                                           endlink))));
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SF_type_node,
+                               V4SI_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf_v4sf_v4sf
-    = build_function_type (V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V4SF_type_node,
-                                                           endlink))));
+    = build_function_type_list (V4SF_type_node,
+                               V4SF_type_node, V4SF_type_node,
+                               V4SF_type_node, NULL_TREE);
   tree v4si_ftype_v4si_v4si_v4si 
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           V4SI_type_node,
-                                                           endlink))));
-
+    = build_function_type_list (V4SI_type_node,
+                               V4SI_type_node, V4SI_type_node,
+                               V4SI_type_node, NULL_TREE);
   tree v8hi_ftype_v8hi_v8hi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                endlink)));
+    = build_function_type_list (V8HI_type_node,
+                               V8HI_type_node, V8HI_type_node, NULL_TREE);
   tree v8hi_ftype_v8hi_v8hi_v8hi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                tree_cons (NULL_TREE, 
-                                                           V8HI_type_node,
-                                                           endlink))));
+    = build_function_type_list (V8HI_type_node,
+                               V8HI_type_node, V8HI_type_node,
+                               V8HI_type_node, NULL_TREE);
  tree v4si_ftype_v8hi_v8hi_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           V4SI_type_node,
-                                                           endlink))));
+    = build_function_type_list (V4SI_type_node,
+                               V8HI_type_node, V8HI_type_node,
+                               V4SI_type_node, NULL_TREE);
  tree v4si_ftype_v16qi_v16qi_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           V4SI_type_node,
-                                                           endlink))));
-  
+    = build_function_type_list (V4SI_type_node,
+                               V16QI_type_node, V16QI_type_node,
+                               V4SI_type_node, NULL_TREE);
   tree v16qi_ftype_v16qi_v16qi
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                endlink)));
-  
+    = build_function_type_list (V16QI_type_node,
+                               V16QI_type_node, V16QI_type_node, NULL_TREE);
   tree v4si_ftype_v4sf_v4sf
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                endlink)));
-
-  tree v4si_ftype_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node, endlink));
-
-  tree v8hi_ftype_v8hi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node, endlink));
-
-  tree v16qi_ftype_v16qi
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node, endlink));
-
+    = build_function_type_list (V4SI_type_node,
+                               V4SF_type_node, V4SF_type_node, NULL_TREE);
   tree v8hi_ftype_v16qi_v16qi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V8HI_type_node,
+                               V16QI_type_node, V16QI_type_node, NULL_TREE);
   tree v4si_ftype_v8hi_v8hi
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V4SI_type_node,
+                               V8HI_type_node, V8HI_type_node, NULL_TREE);
   tree v8hi_ftype_v4si_v4si
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V8HI_type_node,
+                               V4SI_type_node, V4SI_type_node, NULL_TREE);
   tree v16qi_ftype_v8hi_v8hi
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V16QI_type_node,
+                               V8HI_type_node, V8HI_type_node, NULL_TREE);
   tree v4si_ftype_v16qi_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V4SI_type_node,
+                               V16QI_type_node, V4SI_type_node, NULL_TREE);
   tree v4si_ftype_v16qi_v16qi
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V4SI_type_node,
+                               V16QI_type_node, V16QI_type_node, NULL_TREE);
   tree v4si_ftype_v8hi_v4si
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (V4SI_type_node,
+                               V8HI_type_node, V4SI_type_node, NULL_TREE);
   tree v4si_ftype_v8hi
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node, endlink));
-
+    = build_function_type_list (V4SI_type_node, V8HI_type_node, NULL_TREE);
   tree int_ftype_v4si_v4si
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     tree_cons (NULL_TREE, V4SI_type_node,
-                                                endlink)));
-
+    = build_function_type_list (integer_type_node,
+                               V4SI_type_node, V4SI_type_node, NULL_TREE);
   tree int_ftype_v4sf_v4sf
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     tree_cons (NULL_TREE, V4SF_type_node,
-                                                endlink)));
-
+    = build_function_type_list (integer_type_node,
+                               V4SF_type_node, V4SF_type_node, NULL_TREE);
   tree int_ftype_v16qi_v16qi
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     tree_cons (NULL_TREE, V16QI_type_node,
-                                                endlink)));
-
-  tree int_ftype_int_v4si_v4si
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, V4SI_type_node,
-                          tree_cons (NULL_TREE, V4SI_type_node,
-                                     endlink))));
-
-  tree int_ftype_int_v4sf_v4sf
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, V4SF_type_node,
-                          tree_cons (NULL_TREE, V4SF_type_node,
-                                     endlink))));
-
-  tree int_ftype_int_v8hi_v8hi
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-                tree_cons (NULL_TREE, V8HI_type_node,
-                           tree_cons (NULL_TREE, V8HI_type_node,
-                                      endlink))));
-
-  tree int_ftype_int_v16qi_v16qi
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, V16QI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node,
-                                     endlink))));
-
-  tree v16qi_ftype_int_pvoid
-    = build_function_type (V16QI_type_node,
-                          tree_cons (NULL_TREE, integer_type_node,
-                                     tree_cons (NULL_TREE, pvoid_type_node,
-                                                endlink)));
-
-  tree v4si_ftype_int_pvoid
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, integer_type_node,
-                                     tree_cons (NULL_TREE, pvoid_type_node,
-                                                endlink)));
-
-  tree v8hi_ftype_int_pvoid
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, integer_type_node,
-                                     tree_cons (NULL_TREE, pvoid_type_node,
-                                                endlink)));
-
+    = build_function_type_list (integer_type_node,
+                               V16QI_type_node, V16QI_type_node, NULL_TREE);
   tree int_ftype_v8hi_v8hi
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, V8HI_type_node,
-                                     tree_cons (NULL_TREE, V8HI_type_node,
-                                                endlink)));
-
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pfloat, ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf, ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pint, ALTIVEC_BUILTIN_LD_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pshort, ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi, ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pchar, ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi, ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEHX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVXL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_int_pvoid, ALTIVEC_BUILTIN_STVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_int_pvoid, ALTIVEC_BUILTIN_STVEHX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
+    = build_function_type_list (integer_type_node,
+                               V8HI_type_node, V8HI_type_node, NULL_TREE);
 
   /* Add the simple ternary operators.  */
   d = (struct builtin_description *) bdesc_3arg;
@@ -4754,7 +5742,7 @@ altivec_init_builtins (void)
       enum machine_mode mode0, mode1, mode2, mode3;
       tree type;
 
-      if (d->name == 0)
+      if (d->name == 0 || d->icode == CODE_FOR_nothing)
        continue;
       
       mode0 = insn_data[d->icode].operand[0].mode;
@@ -4839,41 +5827,6 @@ altivec_init_builtins (void)
       def_builtin (d->mask, d->name, type, d->code);
     }
 
-  /* Add the DST variants.  */
-  d = (struct builtin_description *) bdesc_dst;
-  for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
-    def_builtin (d->mask, d->name, void_ftype_pvoid_int_char, d->code);
-
-  /* Initialize the predicates.  */
-  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
-  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
-    {
-      enum machine_mode mode1;
-      tree type;
-
-      mode1 = insn_data[dp->icode].operand[1].mode;
-
-      switch (mode1)
-       {
-       case V4SImode:
-         type = int_ftype_int_v4si_v4si;
-         break;
-       case V8HImode:
-         type = int_ftype_int_v8hi_v8hi;
-         break;
-       case V16QImode:
-         type = int_ftype_int_v16qi_v16qi;
-         break;
-       case V4SFmode:
-         type = int_ftype_int_v4sf_v4sf;
-         break;
-       default:
-         abort ();
-       }
-      
-      def_builtin (dp->mask, dp->name, type, dp->code);
-    }
-
   /* Add the simple binary operators.  */
   d = (struct builtin_description *) bdesc_2arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
@@ -4881,7 +5834,7 @@ altivec_init_builtins (void)
       enum machine_mode mode0, mode1, mode2;
       tree type;
 
-      if (d->name == 0)
+      if (d->name == 0 || d->icode == CODE_FOR_nothing)
        continue;
       
       mode0 = insn_data[d->icode].operand[0].mode;
@@ -4905,6 +5858,15 @@ altivec_init_builtins (void)
            case V8HImode:
              type = v8hi_ftype_v8hi_v8hi;
              break;
+           case V2SImode:
+             type = v2si_ftype_v2si_v2si;
+             break;
+           case V2SFmode:
+             type = v2sf_ftype_v2sf_v2sf;
+             break;
+           case SImode:
+             type = int_ftype_int_int;
+             break;
            default:
              abort ();
            }
@@ -4964,6 +5926,15 @@ altivec_init_builtins (void)
       else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
        type = v4si_ftype_v4sf_char;
 
+      else if (mode0 == V2SImode && mode1 == SImode && mode2 == SImode)
+       type = v2si_ftype_int_int;
+
+      else if (mode0 == V2SImode && mode1 == V2SImode && mode2 == QImode)
+       type = v2si_ftype_v2si_char;
+
+      else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
+       type = v2si_ftype_int_char;
+
       /* int, x, x.  */
       else if (mode0 == SImode)
        {
@@ -4992,36 +5963,6 @@ altivec_init_builtins (void)
       def_builtin (d->mask, d->name, type, d->code);
     }
 
-  /* Initialize the abs* operators.  */
-  d = (struct builtin_description *) bdesc_abs;
-  for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
-    {
-      enum machine_mode mode0;
-      tree type;
-
-      mode0 = insn_data[d->icode].operand[0].mode;
-
-      switch (mode0)
-       {
-       case V4SImode:
-         type = v4si_ftype_v4si;
-         break;
-       case V8HImode:
-         type = v8hi_ftype_v8hi;
-         break;
-       case V16QImode:
-         type = v16qi_ftype_v16qi;
-         break;
-       case V4SFmode:
-         type = v4sf_ftype_v4sf;
-         break;
-       default:
-         abort ();
-       }
-      
-      def_builtin (d->mask, d->name, type, d->code);
-    }
-
   /* Add the simple unary operators.  */
   d = (struct builtin_description *) bdesc_1arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
@@ -5029,7 +5970,7 @@ altivec_init_builtins (void)
       enum machine_mode mode0, mode1;
       tree type;
 
-      if (d->name == 0)
+      if (d->name == 0 || d->icode == CODE_FOR_nothing)
        continue;
       
       mode0 = insn_data[d->icode].operand[0].mode;
@@ -5047,6 +5988,16 @@ altivec_init_builtins (void)
        type = v8hi_ftype_v16qi;
       else if (mode0 == V4SImode && mode1 == V8HImode)
        type = v4si_ftype_v8hi;
+      else if (mode0 == V2SImode && mode1 == V2SImode)
+       type = v2si_ftype_v2si;
+      else if (mode0 == V2SFmode && mode1 == V2SFmode)
+       type = v2sf_ftype_v2sf;
+      else if (mode0 == V2SFmode && mode1 == V2SImode)
+       type = v2sf_ftype_v2si;
+      else if (mode0 == V2SImode && mode1 == V2SFmode)
+       type = v2si_ftype_v2sf;
+      else if (mode0 == V2SImode && mode1 == QImode)
+       type = v2si_ftype_char;
       else
        abort ();
 
@@ -5054,7 +6005,6 @@ altivec_init_builtins (void)
     }
 }
 
-\f
 /* Generate a memory reference for expand_block_move, copying volatile,
    and other bits from an original memory reference.  */
 
@@ -5724,9 +6674,10 @@ validate_condition_mode (code, mode)
     abort ();
   
   /* These should never be generated except for 
-     flag_unsafe_math_optimizations.  */
+     flag_unsafe_math_optimizations and flag_finite_math_only.  */
   if (mode == CCFPmode
       && ! flag_unsafe_math_optimizations
+      && ! flag_finite_math_only
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -5777,6 +6728,7 @@ branch_positive_comparison_operator (op, mode)
 
   code = GET_CODE (op);
   return (code == EQ || code == LT || code == GT
+         || (TARGET_SPE && TARGET_HARD_FLOAT && !TARGET_FPRS && code == NE)
          || code == LTU || code == GTU
          || code == UNORDERED);
 }
@@ -6228,8 +7180,12 @@ ccr_bit (op, scc_p)
   switch (code)
     {
     case NE:
+      if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+       return base_bit + 1;
       return scc_p ? base_bit + 3 : base_bit + 2;
     case EQ:
+      if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+       return base_bit + 1;
       return base_bit + 2;
     case GT:  case GTU:  case UNLE:
       return base_bit + 1;
@@ -6279,6 +7235,83 @@ rs6000_init_machine_status ()
   return ggc_alloc_cleared (sizeof (machine_function));
 }
 \f
+/* These macros test for integers and extract the low-order bits.  */
+#define INT_P(X)  \
+((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)   \
+ && GET_MODE (X) == VOIDmode)
+
+#define INT_LOWPART(X) \
+  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
+
+int
+extract_MB (op)
+     rtx op;
+{
+  int i;
+  unsigned long val = INT_LOWPART (op);
+
+  /* If the high bit is zero, the value is the first 1 bit we find
+     from the left.  */
+  if ((val & 0x80000000) == 0)
+    {
+      if ((val & 0xffffffff) == 0)
+       abort ();
+
+      i = 1;
+      while (((val <<= 1) & 0x80000000) == 0)
+       ++i;
+      return i;
+    }
+
+  /* If the high bit is set and the low bit is not, or the mask is all
+     1's, the value is zero.  */
+  if ((val & 1) == 0 || (val & 0xffffffff) == 0xffffffff)
+    return 0;
+
+  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
+     from the right.  */
+  i = 31;
+  while (((val >>= 1) & 1) != 0)
+    --i;
+
+  return i;
+}
+
+int
+extract_ME (op)
+     rtx op;
+{
+  int i;
+  unsigned long val = INT_LOWPART (op);
+
+  /* If the low bit is zero, the value is the first 1 bit we find from
+     the right.  */
+  if ((val & 1) == 0)
+    {
+      if ((val & 0xffffffff) == 0)
+       abort ();
+
+      i = 30;
+      while (((val >>= 1) & 1) == 0)
+       --i;
+
+      return i;
+    }
+
+  /* If the low bit is set and the high bit is not, or the mask is all
+     1's, the value is 31.  */
+  if ((val & 0x80000000) == 0 || (val & 0xffffffff) == 0xffffffff)
+    return 31;
+
+  /* Otherwise we have a wrap-around mask.  Look for the first 0 bit
+     from the left.  */
+  i = 0;
+  while (((val <<= 1) & 0x80000000) != 0)
+    ++i;
+
+  return i;
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -6297,14 +7330,7 @@ print_operand (file, x, code)
 {
   int i;
   HOST_WIDE_INT val;
-
-  /* These macros test for integers and extract the low-order bits.  */
-#define INT_P(X)  \
-((GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST_DOUBLE)   \
- && GET_MODE (X) == VOIDmode)
-
-#define INT_LOWPART(X) \
-  (GET_CODE (X) == CONST_INT ? INTVAL (X) : CONST_DOUBLE_LOW (X))
+  unsigned HOST_WIDE_INT uval;
 
   switch (code)
     {
@@ -6370,6 +7396,15 @@ print_operand (file, x, code)
          fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3,
                   base_bit + 2, base_bit + 2);
        }
+      else if (TARGET_SPE && TARGET_HARD_FLOAT
+              && GET_CODE (x) == EQ
+              && GET_MODE (XEXP (x, 0)) == CCFPmode)
+       {
+         int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
+
+         fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 1,
+                  base_bit + 1, base_bit + 1);
+       }
       return;
 
     case 'E':
@@ -6480,6 +7515,11 @@ print_operand (file, x, code)
            output_operand_lossage ("invalid %%K value");
          print_operand_address (file, XEXP (XEXP (x, 0), 0));
          fputs ("@l", file);
+         /* For GNU as, there must be a non-alphanumeric character
+            between 'l' and the number.  The '-' is added by
+            print_operand() already.  */
+         if (INTVAL (XEXP (XEXP (x, 0), 1)) >= 0)
+           fputs ("+", file);
          print_operand (file, XEXP (XEXP (x, 0), 1), 0);
        }
       return;
@@ -6515,34 +7555,7 @@ print_operand (file, x, code)
       if (! mask_operand (x, SImode))
        output_operand_lossage ("invalid %%m value");
 
-      val = INT_LOWPART (x);
-
-      /* If the high bit is set and the low bit is not, the value is zero.
-        If the high bit is zero, the value is the first 1 bit we find from
-        the left.  */
-      if ((val & 0x80000000) && ((val & 1) == 0))
-       {
-         putc ('0', file);
-         return;
-       }
-      else if ((val & 0x80000000) == 0)
-       {
-         for (i = 1; i < 32; i++)
-           if ((val <<= 1) & 0x80000000)
-             break;
-         fprintf (file, "%d", i);
-         return;
-       }
-         
-      /* Otherwise, look for the first 0 bit from the right.  The result is its
-        number plus 1. We know the low-order bit is one.  */
-      for (i = 0; i < 32; i++)
-       if (((val >>= 1) & 1) == 0)
-         break;
-
-      /* If we ended in ...01, i would be 0.  The correct value is 31, so
-        we want 31 - i.  */
-      fprintf (file, "%d", 31 - i);
+      fprintf (file, "%d", extract_MB (x));
       return;
 
     case 'M':
@@ -6550,35 +7563,7 @@ print_operand (file, x, code)
       if (! mask_operand (x, SImode))
        output_operand_lossage ("invalid %%M value");
 
-      val = INT_LOWPART (x);
-
-      /* If the low bit is set and the high bit is not, the value is 31.
-        If the low bit is zero, the value is the first 1 bit we find from
-        the right.  */
-      if ((val & 1) && ((val & 0x80000000) == 0))
-       {
-         fputs ("31", file);
-         return;
-       }
-      else if ((val & 1) == 0)
-       {
-         for (i = 0; i < 32; i++)
-           if ((val >>= 1) & 1)
-             break;
-
-         /* If we had ....10, i would be 0.  The result should be
-            30, so we need 30 - i.  */
-         fprintf (file, "%d", 30 - i);
-         return;
-       }
-         
-      /* Otherwise, look for the first 0 bit from the left.  The result is its
-        number minus 1. We know the high-order bit is one.  */
-      for (i = 0; i < 32; i++)
-       if (((val <<= 1) & 0x80000000) == 0)
-         break;
-
-      fprintf (file, "%d", i);
+      fprintf (file, "%d", extract_ME (x));
       return;
 
       /* %n outputs the negative of its operand.  */
@@ -6674,68 +7659,43 @@ print_operand (file, x, code)
       return;
 
     case 'S':
-      /* PowerPC64 mask position.  All 0's and all 1's are excluded.
+      /* PowerPC64 mask position.  All 0's is excluded.
         CONST_INT 32-bit mask is considered sign-extended so any
         transition must occur within the CONST_INT, not on the boundary.  */
       if (! mask64_operand (x, DImode))
        output_operand_lossage ("invalid %%S value");
 
-      val = INT_LOWPART (x);
+      uval = INT_LOWPART (x);
 
-      if (val & 1)      /* Clear Left */
+      if (uval & 1)    /* Clear Left */
        {
-         for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
-           if (!((val >>= 1) & 1))
-             break;
-
-#if HOST_BITS_PER_WIDE_INT == 32
-         if (GET_CODE (x) == CONST_DOUBLE && i == 32)
-           {
-             val = CONST_DOUBLE_HIGH (x);
-
-             if (val == 0)
-               --i;
-             else
-               for (i = 32; i < 64; i++)
-                 if (!((val >>= 1) & 1))
-                   break;
-           }
-#endif
-       /* i = index of last set bit from right
-          mask begins at 63 - i from left */
-         if (i > 63)
-           output_operand_lossage ("%%S computed all 1's mask");
-
-         fprintf (file, "%d", 63 - i);
-         return;
+         uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+         i = 64;
        }
-      else     /* Clear Right */
+      else             /* Clear Right */
        {
-         for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
-           if ((val >>= 1) & 1)
-             break;
+         uval = ~uval;
+         uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+         i = 63;
+       }
+      while (uval != 0)
+       --i, uval >>= 1;
+      if (i < 0)
+       abort ();
+      fprintf (file, "%d", i);
+      return;
 
-#if HOST_BITS_PER_WIDE_INT == 32
-       if (GET_CODE (x) == CONST_DOUBLE && i == 32)
-         {
-           val = CONST_DOUBLE_HIGH (x);
+    case 't':
+      /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
+      if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
+       abort ();
 
-           if (val == (HOST_WIDE_INT) -1)
-             --i;
-           else
-             for (i = 32; i < 64; i++)
-               if ((val >>= 1) & 1)
-                 break;
-         }
-#endif
-       /* i = index of last clear bit from right
-          mask ends at 62 - i from left */
-         if (i > 62)
-           output_operand_lossage ("%%S computed all 0's mask");
+      /* Bit 3 is OV bit.  */
+      i = 4 * (REGNO (x) - CR0_REGNO) + 3;
 
-         fprintf (file, "%d", 62 - i);
-         return;
-       }
+      /* If we want bit 31, write a shift count of zero, not 32.  */
+      fprintf (file, "%d", i == 31 ? 0 : i + 1);
+      return;
 
     case 'T':
       /* Print the symbolic name of a branch target register.  */
@@ -6929,7 +7889,7 @@ print_operand (file, x, code)
        }
       return;
 
-      /* Print AltiVec memory operand.  */
+      /* Print AltiVec or SPE memory operand.  */
     case 'y':
       {
        rtx tmp;
@@ -6939,6 +7899,30 @@ print_operand (file, x, code)
 
        tmp = XEXP (x, 0);
 
+       if (TARGET_SPE)
+         {
+           /* Handle [reg].  */
+           if (GET_CODE (tmp) == REG)
+             {
+               fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
+               break;
+             }
+           /* Handle [reg+UIMM].  */
+           else if (GET_CODE (tmp) == PLUS &&
+                    GET_CODE (XEXP (tmp, 1)) == CONST_INT)
+             {
+               int x;
+
+               if (GET_CODE (XEXP (tmp, 0)) != REG)
+                 abort ();
+
+               x = INTVAL (XEXP (tmp, 1));
+               fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
+               break;
+             }
+
+           /* Fall through.  Must be [reg+reg].  */
+         }
        if (GET_CODE (tmp) == REG)
          fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
        else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
@@ -7167,15 +8151,134 @@ rs6000_generate_compare (code)
 
   /* First, the compare.  */
   compare_result = gen_reg_rtx (comp_mode);
-  emit_insn (gen_rtx_SET (VOIDmode, compare_result,
-                         gen_rtx_COMPARE (comp_mode,
-                                          rs6000_compare_op0, 
-                                          rs6000_compare_op1)));
+
+  /* SPE FP compare instructions on the GPRs.  Yuck!  */
+  if ((TARGET_SPE && TARGET_HARD_FLOAT) && rs6000_compare_fp_p)
+    {
+      rtx cmp, or1, or2, or_result, compare_result2;
+
+      switch (code)
+       {
+       case EQ:
+       case UNEQ:
+       case NE:
+       case LTGT:
+         cmp = flag_unsafe_math_optimizations
+           ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1)
+           : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1);
+         break;
+       case GT:
+       case GTU:
+       case UNGT:
+       case UNGE:
+       case GE:
+       case GEU:
+         cmp = flag_unsafe_math_optimizations
+           ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1)
+           : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1);
+         break;
+       case LT:
+       case LTU:
+       case UNLT:
+       case UNLE:
+       case LE:
+       case LEU:
+         cmp = flag_unsafe_math_optimizations
+           ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1)
+           : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
+                              rs6000_compare_op1);
+         break;
+       default:
+         abort ();
+       }
+
+      /* Synthesize LE and GE from LT/GT || EQ.  */
+      if (code == LE || code == GE || code == LEU || code == GEU)
+       {
+         /* Synthesize GE/LE frome GT/LT || EQ.  */
+
+         emit_insn (cmp);
+
+         switch (code)
+           {
+           case LE: code = LT; break;
+           case GE: code = GT; break;
+           case LEU: code = LT; break;
+           case GEU: code = GT; break;
+           default: abort ();
+           }
+
+         or1 = gen_reg_rtx (SImode);
+         or2 = gen_reg_rtx (SImode);
+         or_result = gen_reg_rtx (CCEQmode);
+         compare_result2 = gen_reg_rtx (CCFPmode);
+
+         /* Do the EQ.  */
+         cmp = flag_unsafe_math_optimizations
+           ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
+                              rs6000_compare_op1)
+           : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
+                              rs6000_compare_op1);
+         emit_insn (cmp);
+
+         /* The MC8540 FP compare instructions set the CR bits
+            differently than other PPC compare instructions.  For
+            that matter, there is no generic test instruction, but a
+            testgt, testlt, and testeq.  For a true condition, bit 2
+            is set (x1xx) in the CR.  Following the traditional CR
+            values:
+
+            LT    GT    EQ    OV
+            bit3  bit2  bit1  bit0
+
+            ... bit 2 would be a GT CR alias, so later on we
+            look in the GT bits for the branch instructins.
+            However, we must be careful to emit correct RTL in
+            the meantime, so optimizations don't get confused.  */
+
+         or1 = gen_rtx (NE, SImode, compare_result, const0_rtx);
+         or2 = gen_rtx (NE, SImode, compare_result2, const0_rtx);
+
+         /* OR them together.  */
+         cmp = gen_rtx_SET (VOIDmode, or_result,
+                            gen_rtx_COMPARE (CCEQmode,
+                                             gen_rtx_IOR (SImode, or1, or2),
+                                             const_true_rtx));
+         compare_result = or_result;
+         code = EQ;
+       }
+      else
+       {
+         /* We only care about 1 bit (x1xx), so map everything to NE to
+            maintain rtl sanity.  We'll get to the right bit (x1xx) at
+            code output time.  */
+         if (code == NE || code == LTGT)
+           /* Do the inverse here because we have no cmpne
+              instruction.  We use the cmpeq instruction and expect
+              to get a 0 instead.  */
+           code = EQ;
+         else
+           code = NE;
+       }
+
+      emit_insn (cmp);
+    }
+  else
+    emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+                           gen_rtx_COMPARE (comp_mode,
+                                            rs6000_compare_op0, 
+                                            rs6000_compare_op1)));
   
   /* Some kinds of FP comparisons need an OR operation;
      except for flag_unsafe_math_optimizations we don't bother.  */
   if (rs6000_compare_fp_p
       && ! flag_unsafe_math_optimizations
+      && ! (TARGET_HARD_FLOAT && TARGET_SPE)
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -7296,6 +8399,19 @@ output_cbranch (op, label, reversed, insn)
   if (really_reversed)
     code = rs6000_reverse_condition (mode, code);
 
+  if ((TARGET_SPE && TARGET_HARD_FLOAT) && mode == CCFPmode)
+    {
+      /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
+        to the GT bit.  */
+      if (code == EQ)
+       /* Opposite of GT.  */
+       code = UNLE;
+      else if (code == NE)
+       code = GT;
+      else
+       abort ();
+    }
+
   switch (code)
     {
       /* Not all of these are actually distinct opcodes, but
@@ -7322,21 +8438,30 @@ output_cbranch (op, label, reversed, insn)
   
   /* Maybe we have a guess as to how likely the branch is.  
      The old mnemonics don't have a way to specify this information.  */
+  pred = "";
   note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
   if (note != NULL_RTX)
     {
       /* PROB is the difference from 50%.  */
       int prob = INTVAL (XEXP (note, 0)) - REG_BR_PROB_BASE / 2;
-      
-      /* For branches that are very close to 50%, assume not-taken.  */
-      if (abs (prob) > REG_BR_PROB_BASE / 20
-         && ((prob > 0) ^ need_longbranch))
-       pred = "+";
-      else
-       pred = "-";
+      bool always_hint = rs6000_cpu != PROCESSOR_POWER4;
+
+      /* Only hint for highly probable/improbable branches on newer
+        cpus as static prediction overrides processor dynamic
+        prediction.  For older cpus we may as well always hint, but
+        assume not taken for branches that are very close to 50% as a
+        mispredicted taken branch is more expensive than a
+        mispredicted not-taken branch.  */ 
+      if (always_hint
+         || abs (prob) > REG_BR_PROB_BASE / 100 * 48)
+       {
+         if (abs (prob) > REG_BR_PROB_BASE / 20
+             && ((prob > 0) ^ need_longbranch))
+           pred = "+";
+         else
+           pred = "-";
+       }
     }
-  else
-    pred = "";
 
   if (label == NULL)
     s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
@@ -7382,7 +8507,10 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
   rtx temp;
 
   /* These modes should always match. */
-  if (GET_MODE (op1) != compare_mode)
+  if (GET_MODE (op1) != compare_mode
+      /* In the isel case however, we can use a compare immediate, so
+        op1 may be a small constant.  */
+      && (!TARGET_ISEL || !short_cint_operand (op1, VOIDmode)))
     return 0;
   if (GET_MODE (true_cond) != result_mode)
     return 0;
@@ -7391,10 +8519,12 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
 
   /* First, work out if the hardware can do this at all, or
      if it's too slow...  */
-  /* If the comparison is an integer one, since we only have fsel
-     it'll be cheaper to use a branch.  */
   if (! rs6000_compare_fp_p)
-    return 0;
+    {
+      if (TARGET_ISEL)
+       return rs6000_emit_int_cmove (dest, op, true_cond, false_cond);
+      return 0;
+    }
 
   /* Eliminate half of the comparisons by switching operands, this
      makes the remaining code simpler.  */
@@ -7526,6 +8656,53 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
   return 1;
 }
 
+/* Same as above, but for ints (isel).  */
+
+static int
+rs6000_emit_int_cmove (dest, op, true_cond, false_cond)
+     rtx dest;
+     rtx op;
+     rtx true_cond;
+     rtx false_cond;
+{
+  rtx condition_rtx, cr;
+
+  /* All isel implementations thus far are 32-bits.  */
+  if (GET_MODE (rs6000_compare_op0) != SImode)
+    return 0;
+
+  /* We still have to do the compare, because isel doesn't do a
+     compare, it just looks at the CRx bits set by a previous compare
+     instruction.  */
+  condition_rtx = rs6000_generate_compare (GET_CODE (op));
+  cr = XEXP (condition_rtx, 0);
+
+  if (GET_MODE (cr) == CCmode)
+    emit_insn (gen_isel_signed (dest, condition_rtx,
+                               true_cond, false_cond, cr));
+  else
+    emit_insn (gen_isel_unsigned (dest, condition_rtx,
+                                 true_cond, false_cond, cr));
+
+  return 1;
+}
+
+const char *
+output_isel (operands)
+     rtx *operands;
+{
+  enum rtx_code code;
+
+  code = GET_CODE (operands[1]);
+  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
+    {
+      PUT_CODE (operands[1], reverse_condition (code));
+      return "isel %0,%3,%2,%j1";
+    }
+  else
+    return "isel %0,%2,%3,%j1";
+}
+
 void
 rs6000_emit_minmax (dest, code, op0, op1)
      rtx dest;
@@ -7534,12 +8711,19 @@ rs6000_emit_minmax (dest, code, op0, op1)
      rtx op1;
 {
   enum machine_mode mode = GET_MODE (op0);
+  enum rtx_code c;
   rtx target;
+
+  if (code == SMAX || code == SMIN)
+    c = GE;
+  else
+    c = GEU;
+
   if (code == SMAX || code == UMAX)
-    target = emit_conditional_move (dest, GE, op0, op1, mode, 
+    target = emit_conditional_move (dest, c, op0, op1, mode, 
                                    op0, op1, mode, 0);
   else
-    target = emit_conditional_move (dest, GE, op0, op1, mode, 
+    target = emit_conditional_move (dest, c, op0, op1, mode, 
                                    op1, op0, mode, 0);
   if (target == NULL_RTX)
     abort ();
@@ -7567,53 +8751,6 @@ first_reg_to_save ()
                    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
       break;
 
-  if (current_function_profile)
-    {
-      /* AIX must save/restore every register that contains a parameter
-        before/after the .__mcount call plus an additional register
-        for the static chain, if needed; use registers from 30 down to 22
-        to do this.  */
-      if (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
-       {
-         int last_parm_reg, profile_first_reg;
-
-         /* Figure out last used parameter register.  The proper thing
-            to do is to walk incoming args of the function.  A function
-            might have live parameter registers even if it has no
-            incoming args.  */
-         for (last_parm_reg = 10;
-              last_parm_reg > 2 && ! regs_ever_live [last_parm_reg];
-              last_parm_reg--)
-           ;
-
-         /* Calculate first reg for saving parameter registers
-            and static chain.
-            Skip reg 31 which may contain the frame pointer.  */
-         profile_first_reg = (33 - last_parm_reg
-                              - (current_function_needs_context ? 1 : 0));
-#if TARGET_MACHO
-          /* Need to skip another reg to account for R31 being PICBASE
-             (when flag_pic is set) or R30 being used as the frame
-             pointer (when flag_pic is not set).  */
-          --profile_first_reg;
-#endif
-         /* Do not save frame pointer if no parameters needs to be saved.  */
-         if (profile_first_reg == 31)
-           profile_first_reg = 32;
-
-         if (first_reg > profile_first_reg)
-           first_reg = profile_first_reg;
-       }
-
-      /* SVR4 may need one register to preserve the static chain.  */
-      else if (current_function_needs_context)
-       {
-         /* Skip reg 31 which may contain the frame pointer.  */
-         if (first_reg > 30)
-           first_reg = 30;
-       }
-    }
-
 #if TARGET_MACHO
   if (flag_pic && current_function_uses_pic_offset_table &&
       (first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM))
@@ -7784,6 +8921,10 @@ is_altivec_return_reg (reg, xyes)
                +---------------------------------------+
                | Save area for VRSAVE register (Z)     | 8+P+A+V+L+X+W+Y
                +---------------------------------------+
+                | SPE: area for 64-bit GP registers     |
+                +---------------------------------------+
+                | SPE alignment padding                 |
+                +---------------------------------------+
                | saved CR (C)                          | 8+P+A+V+L+X+W+Y+Z
                +---------------------------------------+    
                | Save area for GP registers (G)        | 8+P+A+V+L+X+W+Y+Z+C
@@ -7839,6 +8980,20 @@ rs6000_stack_info ()
   else
     info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
 
+  /* For the SPE, we have an additional upper 32-bits on each GPR.
+     Ideally we should save the entire 64-bits only when the upper
+     half is used in SIMD instructions.  Since we only record
+     registers live (not the size they are used in), this proves
+     difficult because we'd have to traverse the instruction chain at
+     the right time, taking reload into account.  This is a real pain,
+     so we opt to save the GPRs in 64-bits always.  Anyone overly
+     concerned with frame size can fix this.  ;-).
+
+     So... since we save all GPRs (except the SP) in 64-bits, the
+     traditional GP save area will be empty.  */
+  if (TARGET_SPE_ABI)
+    info_ptr->gp_size = 0;
+
   info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
   info_ptr->fp_size = 8 * (64 - info_ptr->first_fp_reg_save);
 
@@ -7887,7 +9042,9 @@ rs6000_stack_info ()
       unsigned int i;
       for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
        continue;
-      ehrd_size = i * UNITS_PER_WORD;
+
+      /* SPE saves EH registers in 64-bits.  */
+      ehrd_size = i * (TARGET_SPE_ABI ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
     }
   else
     ehrd_size = 0;
@@ -7900,6 +9057,11 @@ rs6000_stack_info ()
   info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
                                         8);
 
+  if (TARGET_SPE_ABI)
+    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
+  else
+    info_ptr->spe_gp_size = 0;
+
   if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE)
     {
       info_ptr->vrsave_mask = compute_vrsave_mask ();
@@ -7955,7 +9117,26 @@ rs6000_stack_info ()
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
       info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
 
-      if (TARGET_ALTIVEC_ABI)
+      if (TARGET_SPE_ABI)
+      {
+        /* Align stack so SPE GPR save area is aligned on a
+           double-word boundary.  */
+        if (info_ptr->spe_gp_size != 0)
+          info_ptr->spe_padding_size
+            = 8 - (-info_ptr->cr_save_offset % 8);
+        else
+          info_ptr->spe_padding_size = 0;
+
+        info_ptr->spe_gp_save_offset
+          = info_ptr->cr_save_offset
+          - info_ptr->spe_padding_size
+          - info_ptr->spe_gp_size;
+
+        /* Adjust for SPE case.  */
+        info_ptr->toc_save_offset
+          = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
+      }
+      else if (TARGET_ALTIVEC_ABI)
        {
          info_ptr->vrsave_save_offset
            = info_ptr->cr_save_offset - info_ptr->vrsave_size;
@@ -7988,6 +9169,8 @@ rs6000_stack_info ()
                                         + info_ptr->altivec_size
                                         + info_ptr->altivec_padding_size
                                         + info_ptr->vrsave_size
+                                        + info_ptr->spe_gp_size
+                                        + info_ptr->spe_padding_size
                                         + ehrd_size
                                         + info_ptr->cr_size
                                         + info_ptr->lr_size
@@ -8042,6 +9225,9 @@ rs6000_stack_info ()
   if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
     info_ptr->vrsave_save_offset = 0;
 
+  if (! TARGET_SPE_ABI || info_ptr->spe_gp_size == 0)
+    info_ptr->spe_gp_save_offset = 0;
+
   if (! info_ptr->lr_save_p)
     info_ptr->lr_save_offset = 0;
 
@@ -8083,6 +9269,9 @@ debug_stack_info (info)
   if (TARGET_ALTIVEC_ABI)
     fprintf (stderr, "\tALTIVEC ABI extensions enabled.\n");
 
+  if (TARGET_SPE_ABI)
+    fprintf (stderr, "\tSPE ABI extensions enabled.\n");
+
   if (info->first_gp_reg_save != 32)
     fprintf (stderr, "\tfirst_gp_reg_save   = %5d\n", info->first_gp_reg_save);
 
@@ -8121,6 +9310,10 @@ debug_stack_info (info)
     fprintf (stderr, "\taltivec_save_offset = %5d\n",
             info->altivec_save_offset);
 
+  if (info->spe_gp_save_offset)
+    fprintf (stderr, "\tspe_gp_save_offset  = %5d\n",
+            info->spe_gp_save_offset);
+
   if (info->vrsave_save_offset)
     fprintf (stderr, "\tvrsave_save_offset  = %5d\n",
             info->vrsave_save_offset);
@@ -8155,6 +9348,9 @@ debug_stack_info (info)
   if (info->gp_size)
     fprintf (stderr, "\tgp_size             = %5d\n", info->gp_size);
 
+  if (info->spe_gp_size)
+    fprintf (stderr, "\tspe_gp_size         = %5d\n", info->spe_gp_size);
+
   if (info->fp_size)
     fprintf (stderr, "\tfp_size             = %5d\n", info->fp_size);
 
@@ -8168,6 +9364,10 @@ debug_stack_info (info)
     fprintf (stderr, "\taltivec_padding_size= %5d\n",
             info->altivec_padding_size);
 
+  if (info->spe_padding_size)
+    fprintf (stderr, "\tspe_padding_size    = %5d\n",
+            info->spe_padding_size);
+
   if (info->lr_size)
     fprintf (stderr, "\tlr_size             = %5d\n", info->lr_size);
 
@@ -8659,8 +9859,19 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
 {
   rtx real, temp;
 
+  /* copy_rtx will not make unique copies of registers, so we need to
+     ensure we don't have unwanted sharing here.  */
+  if (reg == reg2)
+    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
+
+  if (reg == rreg)
+    reg = gen_raw_REG (GET_MODE (reg), REGNO (reg));
+
   real = copy_rtx (PATTERN (insn));
 
+  if (reg2 != NULL_RTX)
+    real = replace_rtx (real, reg2, rreg);
+  
   real = replace_rtx (real, reg, 
                      gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
                                                        STACK_POINTER_REGNUM),
@@ -8713,9 +9924,6 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
   else
     abort ();
   
-  if (reg2 != NULL_RTX)
-    real = replace_rtx (real, reg2, rreg);
-  
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
                                        real,
@@ -8784,6 +9992,78 @@ generate_set_vrsave (reg, info, epiloguep)
   return insn;
 }
 
+/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
+   Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
+
+static void
+emit_frame_save (frame_reg, frame_ptr, mode, regno, offset, total_size)
+     rtx frame_reg;
+     rtx frame_ptr;
+     enum machine_mode mode;
+     unsigned int regno;
+     int offset;
+     int total_size;
+{
+  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
+  rtx replacea, replaceb;
+
+  int_rtx = GEN_INT (offset);
+
+  /* Some cases that need register indexed addressing.  */
+  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+      || (TARGET_SPE_ABI
+         && SPE_VECTOR_MODE (mode)
+         && !SPE_CONST_OFFSET_OK (offset)))
+    {
+      /* Whomever calls us must make sure r11 is available in the
+         flow path of instructions in the prologue.  */
+      offset_rtx = gen_rtx_REG (Pmode, 11);
+      emit_move_insn (offset_rtx, int_rtx);
+
+      replacea = offset_rtx;
+      replaceb = int_rtx;
+    }
+  else
+    {
+      offset_rtx = int_rtx;
+      replacea = NULL_RTX;
+      replaceb = NULL_RTX;
+    }
+
+  reg = gen_rtx_REG (mode, regno);
+  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
+  mem = gen_rtx_MEM (mode, addr);
+  set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+  insn = emit_move_insn (mem, reg);
+
+  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
+}
+
+/* Emit an offset memory reference suitable for a frame store, while
+   converting to a valid addressing mode.  */
+
+static rtx
+gen_frame_mem_offset (mode, reg, offset)
+     enum machine_mode mode;
+     rtx reg;
+     int offset;
+{
+  rtx int_rtx, offset_rtx;
+
+  int_rtx = GEN_INT (offset);
+
+  if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
+    {
+      offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+      emit_move_insn (offset_rtx, int_rtx);
+    }
+  else
+    offset_rtx = int_rtx;
+
+  return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
+}
+
 /* Emit function prologue as insns.  */
 
 void
@@ -8801,7 +10081,14 @@ rs6000_emit_prologue ()
   int using_store_multiple;
   HOST_WIDE_INT sp_offset = 0;
   
+   if (TARGET_SPE_ABI)
+     {
+       reg_mode = V2SImode;
+       reg_size = 8;
+     }
+
   using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
+                         && !TARGET_SPE_ABI
                          && info->first_gp_reg_save < 31);
   saving_FPRs_inline = (info->first_fp_reg_save == 64
                        || FP_SAVE_INLINE (info->first_fp_reg_save));
@@ -8911,20 +10198,10 @@ rs6000_emit_prologue ()
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
        if ((regs_ever_live[info->first_fp_reg_save+i] 
             && ! call_used_regs[info->first_fp_reg_save+i]))
-         {
-           rtx addr, reg, mem;
-           reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
-           addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                GEN_INT (info->fp_save_offset 
-                                         + sp_offset 
-                                         + 8 * i));
-           mem = gen_rtx_MEM (DFmode, addr);
-           set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-           insn = emit_move_insn (mem, reg);
-           rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-                                 NULL_RTX, NULL_RTX);
-         }
+         emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
+                          info->first_fp_reg_save + i,
+                          info->fp_save_offset + sp_offset + 8 * i,
+                          info->total_size);
     }
   else if (info->first_fp_reg_save != 64)
     {
@@ -8964,10 +10241,9 @@ rs6000_emit_prologue ()
      the store-multiple instructions.  */
   if (using_store_multiple)
     {
-      rtvec p, dwarfp;
+      rtvec p;
       int i;
       p = rtvec_alloc (32 - info->first_gp_reg_save);
-      dwarfp = rtvec_alloc (32 - info->first_gp_reg_save);
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
        {
          rtx addr, reg, mem;
@@ -8997,16 +10273,45 @@ rs6000_emit_prologue ()
          {
            rtx addr, reg, mem;
            reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-           addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, 
-                                GEN_INT (info->gp_save_offset 
-                                         + sp_offset 
-                                         + reg_size * i));
-           mem = gen_rtx_MEM (reg_mode, addr);
-           set_mem_alias_set (mem, rs6000_sr_alias_set);
 
-           insn = emit_move_insn (mem, reg);
-           rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-                                 NULL_RTX, NULL_RTX);
+           if (TARGET_SPE_ABI)
+             {
+               int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
+               rtx b;
+
+               if (!SPE_CONST_OFFSET_OK (offset))
+                 {
+                   b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+                   emit_move_insn (b, GEN_INT (offset));
+                 }
+               else
+                 b = GEN_INT (offset);
+
+               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
+               mem = gen_rtx_MEM (V2SImode, addr);
+               set_mem_alias_set (mem, rs6000_sr_alias_set);
+               insn = emit_move_insn (mem, reg);
+
+               if (GET_CODE (b) == CONST_INT)
+                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                       NULL_RTX, NULL_RTX);
+               else
+                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                       b, GEN_INT (offset));
+             }
+           else
+             {
+               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, 
+                                    GEN_INT (info->gp_save_offset 
+                                             + sp_offset 
+                                             + reg_size * i));
+               mem = gen_rtx_MEM (reg_mode, addr);
+               set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+               insn = emit_move_insn (mem, reg);
+               rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
+                                     NULL_RTX, NULL_RTX);
+             }
          }
     }
 
@@ -9018,22 +10323,14 @@ rs6000_emit_prologue ()
 
       for (i = 0; ; ++i)
        {
-         rtx addr, reg, mem;
-
          regno = EH_RETURN_DATA_REGNO (i);
          if (regno == INVALID_REGNUM)
            break;
 
-         reg = gen_rtx_REG (reg_mode, regno);
-         addr = plus_constant (frame_reg_rtx,
-                               info->ehrd_offset + sp_offset
-                               + reg_size * (int) i);
-         mem = gen_rtx_MEM (reg_mode, addr);
-         set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-         insn = emit_move_insn (mem, reg);
-         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-                               NULL_RTX, NULL_RTX);
+         emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
+                          info->ehrd_offset + sp_offset
+                          + reg_size * (int) i,
+                          info->total_size);
        }
     }
 
@@ -9088,7 +10385,7 @@ rs6000_emit_prologue ()
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
     {
-      insn = emit_move_insn (gen_rtx_REG (reg_mode, FRAME_POINTER_REGNUM), 
+      insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM), 
                             sp_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
@@ -9215,8 +10512,15 @@ rs6000_emit_epilogue (sibcall)
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
   int i;
 
+  if (TARGET_SPE_ABI)
+    {
+      reg_mode = V2SImode;
+      reg_size = 8;
+    }
+
   info = rs6000_stack_info ();
   using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
+                        && !TARGET_SPE_ABI
                         && info->first_gp_reg_save < 31);
   restoring_FPRs_inline = (sibcall
                           || current_function_calls_eh_return
@@ -9301,9 +10605,8 @@ rs6000_emit_epilogue (sibcall)
   /* Get the old lr if we saved it.  */
   if (info->lr_save_p)
     {
-      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->lr_save_offset + sp_offset));
-      rtx mem = gen_rtx_MEM (Pmode, addr);
+      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
+                                     info->lr_save_offset + sp_offset);
 
       set_mem_alias_set (mem, rs6000_sr_alias_set);
 
@@ -9334,16 +10637,15 @@ rs6000_emit_epilogue (sibcall)
 
       for (i = 0; ; ++i)
        {
-         rtx addr, mem;
+         rtx mem;
 
          regno = EH_RETURN_DATA_REGNO (i);
          if (regno == INVALID_REGNUM)
            break;
 
-         addr = plus_constant (frame_reg_rtx,
-                               info->ehrd_offset + sp_offset
-                               + reg_size * (int) i);
-         mem = gen_rtx_MEM (reg_mode, addr);
+         mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
+                                     info->ehrd_offset + sp_offset
+                                     + reg_size * (int) i);
          set_mem_alias_set (mem, rs6000_sr_alias_set);
 
          emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
@@ -9387,11 +10689,28 @@ rs6000_emit_epilogue (sibcall)
                                            + reg_size * i));
          rtx mem = gen_rtx_MEM (reg_mode, addr);
 
+         /* Restore 64-bit quantities for SPE.  */
+         if (TARGET_SPE_ABI)
+           {
+             int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
+             rtx b;
+
+             if (!SPE_CONST_OFFSET_OK (offset))
+               {
+                 b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
+                 emit_move_insn (b, GEN_INT (offset));
+               }
+             else
+               b = GEN_INT (offset);
+
+             addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
+             mem = gen_rtx_MEM (V2SImode, addr);
+           }
+
          set_mem_alias_set (mem, rs6000_sr_alias_set);
 
          emit_move_insn (gen_rtx_REG (reg_mode, 
-                                      info->first_gp_reg_save + i),
-                         mem);
+                                      info->first_gp_reg_save + i), mem);
        }
 
   /* Restore fpr's if we need to do it without calling a function.  */
@@ -9549,7 +10868,6 @@ rs6000_output_function_epilogue (file, size)
      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
   rs6000_stack_t *info = rs6000_stack_info ();
-  int optional_tbtab = (optimize_size || TARGET_ELF) ? 0 : 1;
 
   if (! HAVE_epilogue)
     {
@@ -9602,12 +10920,21 @@ rs6000_output_function_epilogue (file, size)
 
      System V.4 Powerpc's (and the embedded ABI derived from it) use a
      different traceback table.  */
-  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive)
+  if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
+      && rs6000_traceback != traceback_none)
     {
       const char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
       const char *language_string = lang_hooks.name;
       int fixed_parms = 0, float_parms = 0, parm_info = 0;
       int i;
+      int optional_tbtab;
+
+      if (rs6000_traceback == traceback_full)
+       optional_tbtab = 1;
+      else if (rs6000_traceback == traceback_part)
+       optional_tbtab = 0;
+      else
+       optional_tbtab = !optimize_size && !TARGET_ELF;
 
       while (*fname == '.')    /* V.4 encodes . in the name */
        fname++;
@@ -9801,7 +11128,6 @@ rs6000_output_function_epilogue (file, size)
 
       fputs ("\t.align 2\n", file);
     }
-  return;
 }
 \f
 /* A C compound statement that outputs the assembler code for a thunk
@@ -10053,7 +11379,7 @@ rs6000_hash_constant (k)
   int fidx;
   
   if (GET_CODE (k) == LABEL_REF)
-    return result * 1231 + X0INT (XEXP (k, 0), 3);
+    return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
 
   if (GET_CODE (k) == CODE_LABEL)
     fidx = 3;
@@ -10347,8 +11673,17 @@ output_toc (file, x, labelno, mode)
        abort ();/* It would be easy to make this work, but it doesn't now.  */
 
       if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
-       lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
-                      POINTER_SIZE, &low, &high, 0);
+       {
+#if HOST_BITS_PER_WIDE_INT == 32
+         lshift_double (low, high, POINTER_SIZE - GET_MODE_BITSIZE (mode),
+                        POINTER_SIZE, &low, &high, 0);
+#else
+         low |= high << 32;
+         low <<= POINTER_SIZE - GET_MODE_BITSIZE (mode);
+         high = (HOST_WIDE_INT) low >> 32;
+         low &= 0xffffffff;
+#endif
+       }
 
       if (TARGET_64BIT)
        {
@@ -10539,7 +11874,7 @@ rs6000_gen_section_name (buf, filename, section_desc)
     }
 
   len = strlen (after_last_slash) + strlen (section_desc) + 2;
-  *buf = (char *) permalloc (len);
+  *buf = (char *) xmalloc (len);
 
   p = *buf;
   *p++ = '_';
@@ -10566,10 +11901,13 @@ rs6000_gen_section_name (buf, filename, section_desc)
 
 void
 output_profile_hook (labelno)
-     int labelno;
+     int labelno ATTRIBUTE_UNUSED;
 {
   if (DEFAULT_ABI == ABI_AIX)
     {
+#ifdef NO_PROFILE_COUNTERS
+      emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 0);
+#else
       char buf[30];
       const char *label_name;
       rtx fun;
@@ -10580,6 +11918,7 @@ output_profile_hook (labelno)
 
       emit_library_call (init_one_libfunc (RS6000_MCOUNT), 0, VOIDmode, 1,
                          fun, Pmode);
+#endif
     }
   else if (DEFAULT_ABI == ABI_DARWIN)
     {
@@ -10613,6 +11952,7 @@ output_function_profiler (file, labelno)
   int labelno;
 {
   char buf[100];
+  int save_lr = 8;
 
   ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
   switch (DEFAULT_ABI)
@@ -10621,13 +11961,21 @@ output_function_profiler (file, labelno)
       abort ();
 
     case ABI_V4:
+      save_lr = 4;
+      /* Fall through.  */
+
     case ABI_AIX_NODESC:
+      if (!TARGET_32BIT)
+       {
+         warning ("no profiling of 64-bit code for this ABI");
+         return;
+       }
       fprintf (file, "\tmflr %s\n", reg_names[0]);
       if (flag_pic == 1)
        {
          fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
-                      reg_names[0], reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+                      reg_names[0], save_lr, reg_names[1]);
          asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
          asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
          assemble_name (file, buf);
@@ -10635,8 +11983,8 @@ output_function_profiler (file, labelno)
        }
       else if (flag_pic > 1)
        {
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
-                      reg_names[0], reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+                      reg_names[0], save_lr, reg_names[1]);
          /* Now, we need to get the address of the label.  */
          fputs ("\tbl 1f\n\t.long ", file);
          assemble_name (file, buf);
@@ -10652,27 +12000,32 @@ output_function_profiler (file, labelno)
          asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
          assemble_name (file, buf);
          fputs ("@ha\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
-                      reg_names[0], reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+                      reg_names[0], save_lr, reg_names[1]);
          asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@l(%s)\n", reg_names[12]);
        }
 
-      if (current_function_needs_context)
-       asm_fprintf (file, "\tmr %s,%s\n",
-                    reg_names[30], reg_names[STATIC_CHAIN_REGNUM]);
-      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
-      if (current_function_needs_context)
-       asm_fprintf (file, "\tmr %s,%s\n",
-                    reg_names[STATIC_CHAIN_REGNUM], reg_names[30]);
+      if (current_function_needs_context && DEFAULT_ABI == ABI_AIX_NODESC)
+       {
+         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
+                      reg_names[STATIC_CHAIN_REGNUM],
+                      12, reg_names[1]);
+         fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+         asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n",
+                      reg_names[STATIC_CHAIN_REGNUM],
+                      12, reg_names[1]);
+       }
+      else
+       /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
+       fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
       break;
 
     case ABI_AIX:
     case ABI_DARWIN:
       /* Don't do anything, done in output_profile_hook ().  */
       break;
-
     }
 }
 
@@ -11313,8 +12666,7 @@ output_compiler_stub ()
 {
   char tmp_buf[256];
   char label_buf[256];
-  char *label;
-  tree tmp_stub, stub;
+  tree stub;
 
   if (!flag_pic)
     for (stub = stub_list; stub; stub = TREE_CHAIN (stub))
@@ -11400,7 +12752,7 @@ output_call (insn, call_dest, operand_number)
       
       if (no_previous_def (funname))
        {
-         int line_number;
+         int line_number = 0;
          rtx label_rtx = gen_label_rtx ();
          char *label_buf, temp_buf[256];
          ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",