OSDN Git Service

* config/rs6000/rs6000-protos.h (rs6000_field_alignment): Remove.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 1a65a77..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 *));
@@ -147,8 +181,7 @@ static int toc_hash_eq PARAMS ((const void *, const void *));
 static int toc_hash_mark_entry PARAMS ((void **, void *));
 static void toc_hash_mark_table PARAMS ((void *));
 static int constant_pool_expr_1 PARAMS ((rtx, int *, int *));
-static void rs6000_free_machine_status PARAMS ((struct function *));
-static void rs6000_init_machine_status PARAMS ((struct function *));
+static struct machine_function * rs6000_init_machine_status PARAMS ((void));
 static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));
 static int rs6000_ra_ever_killed PARAMS ((void));
 static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
@@ -171,7 +204,7 @@ static void rs6000_elf_select_rtx_section PARAMS ((enum machine_mode, rtx,
 static void rs6000_elf_encode_section_info PARAMS ((tree, int));
 static const char *rs6000_elf_strip_name_encoding PARAMS ((const char *));
 #endif
-#ifdef OBJECT_FORMAT_COFF
+#if TARGET_XCOFF
 static void xcoff_asm_named_section PARAMS ((const char *, unsigned int));
 static void rs6000_xcoff_select_section PARAMS ((tree, int,
                                                 unsigned HOST_WIDE_INT));
@@ -187,21 +220,35 @@ static int rs6000_adjust_priority PARAMS ((rtx, int));
 static int rs6000_issue_rate PARAMS ((void));
 
 static void rs6000_init_builtins PARAMS ((void));
-static void altivec_init_builtins PARAMS ((void));
+static rtx rs6000_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
+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 rtx altivec_expand_builtin PARAMS ((tree, rtx));
-static rtx altivec_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
-static rtx altivec_expand_binop_builtin PARAMS ((enum insn_code, tree, rtx));
+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_ternop_builtin PARAMS ((enum insn_code, 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));
@@ -267,7 +314,7 @@ static const char alt_reg_names[][8] =
 /* Default unaligned ops are only provided for ELF.  Find the ops needed
    for non-ELF systems.  */
 #ifndef OBJECT_FORMAT_ELF
-#ifdef OBJECT_FORMAT_COFF
+#if TARGET_XCOFF
 /* For XCOFF.  rs6000_assemble_integer will handle unaligned DIs on
    64-bit targets.  */
 #undef TARGET_ASM_UNALIGNED_HI_OP
@@ -354,6 +401,9 @@ rs6000_override_options (default_cpu)
         {"power3", PROCESSOR_PPC630,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
            POWER_MASKS | MASK_PPC_GPOPT},
+        {"power4", PROCESSOR_POWER4,
+           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | MASK_PPC_GPOPT},
         {"powerpc", PROCESSOR_POWERPC,
            MASK_POWERPC | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -429,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},
@@ -477,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)
@@ -552,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)
@@ -571,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.
@@ -594,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.  */
@@ -631,7 +703,21 @@ rs6000_override_options (default_cpu)
 
   /* Arrange to save and restore machine status around nested functions.  */
   init_machine_status = rs6000_init_machine_status;
-  free_machine_status = rs6000_free_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.  */
@@ -659,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);
 }
@@ -1202,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.  */
@@ -1490,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
@@ -1564,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.  */
 
@@ -1866,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)
     {
@@ -1885,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)));
@@ -1902,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)
     {
@@ -1989,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));
@@ -2077,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;
@@ -2094,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;
@@ -2289,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;
@@ -2315,7 +2569,7 @@ rs6000_emit_move (dest, source, mode)
 
   /* Handle the case where reload calls us with an invalid address;
      and the case of CONSTANT_P_RTX.  */
-  if (!VECTOR_MODE_P (mode)
+  if (!ALTIVEC_VECTOR_MODE (mode)
       && (! general_operand (operands[1], mode)
          || ! nonimmediate_operand (operands[0], mode)
          || GET_CODE (operands[1]) == CONSTANT_P_RTX))
@@ -2348,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]);
@@ -2633,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
@@ -2659,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)
@@ -2685,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.  */
@@ -2721,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)
@@ -2774,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);
@@ -2794,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)
@@ -2816,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;
        }
@@ -3018,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;
@@ -3092,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;
 {
@@ -3104,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;
     }
 
@@ -3200,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;
@@ -3225,8 +3515,8 @@ rs6000_va_arg (valist, type)
   lab_over = gen_label_rtx ();
   addr_rtx = gen_reg_rtx (Pmode);
 
-  /*  Vectors never go in registers.  */
-  if (TREE_CODE (type) != VECTOR_TYPE)
+  /*  AltiVec vectors never go in registers.  */
+  if (!TARGET_ALTIVEC || TREE_CODE (type) != VECTOR_TYPE)
     {
       TREE_THIS_VOLATILE (reg) = 1;
       emit_cmp_and_jump_insns
@@ -3280,7 +3570,8 @@ rs6000_va_arg (valist, type)
      All AltiVec vectors go in the overflow area.  So in the AltiVec
      case we need to get the vectors from the overflow area, but
      remember where the GPRs and FPRs are.  */
-  if (n_reg > 1 && TREE_CODE (type) != VECTOR_TYPE)
+  if (n_reg > 1 && (TREE_CODE (type) != VECTOR_TYPE
+                   || !TARGET_ALTIVEC))
     {
       t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
       TREE_SIDE_EFFECTS (t) = 1;
@@ -3294,8 +3585,8 @@ rs6000_va_arg (valist, type)
     {
       int align;
 
-      /* Vectors are 16 byte aligned.  */
-      if (TREE_CODE (type) == VECTOR_TYPE)
+      /* AltiVec vectors are 16 byte aligned.  */
+      if (TARGET_ALTIVEC && TREE_CODE (type) == VECTOR_TYPE)
        align = 15;
       else
        align = 7;
@@ -3328,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[] =
@@ -3383,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 },
@@ -3498,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.  */
@@ -3528,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[] =
@@ -3544,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 },
@@ -3563,10 +4035,46 @@ 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
-altivec_expand_unop_builtin (icode, arglist, target)
+rs6000_expand_unop_builtin (icode, arglist, target)
      enum insn_code icode;
      tree arglist;
      rtx target;
@@ -3577,26 +4085,28 @@ altivec_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 NULL_RTX;
+    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)
        {
          error ("argument 1 must be a 5-bit signed literal");
-         return NULL_RTX;
+         return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3629,7 +4139,7 @@ altivec_expand_abs_builtin (icode, arglist, target)
 
   /* If we have invalid arguments, bail out before generating bad rtl.  */
   if (arg0 == error_mark_node)
-    return NULL_RTX;
+    return const0_rtx;
 
   if (target == 0
       || GET_MODE (target) != tmode
@@ -3651,7 +4161,7 @@ altivec_expand_abs_builtin (icode, arglist, target)
 }
 
 static rtx
-altivec_expand_binop_builtin (icode, arglist, target)
+rs6000_expand_binop_builtin (icode, arglist, target)
      enum insn_code icode;
      tree arglist;
      rtx target;
@@ -3665,29 +4175,45 @@ altivec_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 NULL_RTX;
-
-  switch (icode)
+    return const0_rtx;
+
+  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 NULL_RTX;
+         return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3729,7 +4255,7 @@ altivec_expand_predicate_builtin (icode, opcode, arglist, target)
   if (TREE_CODE (cr6_form) != INTEGER_CST)
     {
       error ("argument 1 of __builtin_altivec_predicate must be a constant");
-      return NULL_RTX;
+      return const0_rtx;
     }
   else
     cr6_form_int = TREE_INT_CST_LOW (cr6_form);
@@ -3739,7 +4265,7 @@ altivec_expand_predicate_builtin (icode, opcode, arglist, target)
 
   /* If we have invalid arguments, bail out before generating bad rtl.  */
   if (arg0 == error_mark_node || arg1 == error_mark_node)
-    return NULL_RTX;
+    return const0_rtx;
 
   if (target == 0
       || GET_MODE (target) != tmode
@@ -3809,7 +4335,7 @@ altivec_expand_stv_builtin (icode, arglist)
   if (arg0 == error_mark_node
       || arg1 == error_mark_node
       || arg2 == error_mark_node)
-    return NULL_RTX;
+    return const0_rtx;
 
   if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
     op0 = copy_to_mode_reg (mode2, op0);
@@ -3825,7 +4351,7 @@ altivec_expand_stv_builtin (icode, arglist)
 }
 
 static rtx
-altivec_expand_ternop_builtin (icode, arglist, target)
+rs6000_expand_ternop_builtin (icode, arglist, target)
      enum insn_code icode;
      tree arglist;
      rtx target;
@@ -3842,28 +4368,28 @@ altivec_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 NULL_RTX;
+    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 NULL_RTX;
+         return const0_rtx;
        }
-      break;
-    default:
-      break;
     }
 
   if (target == 0
@@ -3885,184 +4411,214 @@ altivec_expand_ternop_builtin (icode, arglist, target)
 
   return target;
 }
+
+/* Expand the lvx builtins.  */
 static rtx
-altivec_expand_builtin (exp, target)
+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);
-  
+  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;
+      break;
+    case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
+      icode = CODE_FOR_altivec_lvx_4si;
+      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;
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
 
-    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;
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
 
-      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, op0);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
 
-      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+/* 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;
 
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
+  switch (fcode)
+    {
+    case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
+      icode = CODE_FOR_altivec_stvx_16qi;
+      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;
+    }
 
-    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;
+  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 (target == 0
-         || GET_MODE (target) != tmode
-         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
+  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[icode].operand[1].predicate) (op0, mode0))
-       op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+  pat = GEN_FCN (icode) (op0, op1);
+  if (pat)
+    emit_insn (pat);
 
-      pat = GEN_FCN (icode) (target, op0);
-      if (! pat)
-       return 0;
-      emit_insn (pat);
-      return target;
+  *expandedp = true;
+  return NULL_RTX;
+}
 
-    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;
+/* 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;
 
-      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 = false;
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      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;
 
-    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;
+       /* 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 (! (*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 (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;
+         }
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_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);
 
-    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;
+       pat = GEN_FCN (d->icode) (op0, op1, op2);
+       if (pat != 0)
+         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;
+  return NULL_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;
+/* 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);
 
-      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);
+  target = altivec_expand_ld_builtin (exp, target, expandedp);
+  if (*expandedp)
+    return target;
 
-      pat = GEN_FCN (icode) (op0, op1);
-      if (pat)
-       emit_insn (pat);
-      return NULL_RTX;
+  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:
@@ -4073,7 +4629,7 @@ altivec_expand_builtin (exp, target)
       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;
@@ -4097,7 +4653,7 @@ altivec_expand_builtin (exp, target)
 
       /* If we got invalid arguments bail out before generating bad rtl.  */
       if (arg0 == error_mark_node)
-       return NULL_RTX;
+       return const0_rtx;
 
       if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
        op0 = copy_to_mode_reg (mode0, op0);
@@ -4106,7 +4662,7 @@ altivec_expand_builtin (exp, target)
       if (pat)
        emit_insn (pat);
       return NULL_RTX;
-      
+
     case ALTIVEC_BUILTIN_DSSALL:
       emit_insn (gen_altivec_dssall ());
       return NULL_RTX;
@@ -4119,13 +4675,13 @@ altivec_expand_builtin (exp, target)
 
       /* If we got invalid arguments bail out before generating bad rtl.  */
       if (arg0 == error_mark_node)
-       return NULL_RTX;
+       return const0_rtx;
 
       if (TREE_CODE (arg0) != INTEGER_CST
          || TREE_INT_CST_LOW (arg0) & ~0x3)
        {
          error ("argument to dss must be a 2-bit unsigned literal");
-         return NULL_RTX;
+         return const0_rtx;
        }
 
       if (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
@@ -4135,64 +4691,12 @@ altivec_expand_builtin (exp, target)
       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 NULL_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 NULL_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++)
     if (d->code == fcode)
       return altivec_expand_abs_builtin (d->icode, arglist, target);
 
-  /* 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 altivec_expand_unop_builtin (d->icode, arglist, target);
-
-  /* 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 altivec_expand_binop_builtin (d->icode, arglist, target);
-
   /* Expand the AltiVec predicates.  */
   dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
   for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
@@ -4203,526 +4707,1032 @@ altivec_expand_builtin (exp, target)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LVSL:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvsl,
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsl,
                                           arglist, target);
     case ALTIVEC_BUILTIN_LVSR:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvsr,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsr,
+                                         arglist, target);
     case ALTIVEC_BUILTIN_LVEBX:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvebx,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvebx,
+                                         arglist, target);
     case ALTIVEC_BUILTIN_LVEHX:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvehx,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvehx,
+                                         arglist, target);
     case ALTIVEC_BUILTIN_LVEWX:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvewx,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvewx,
+                                         arglist, target);
     case ALTIVEC_BUILTIN_LVXL:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvxl,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvxl,
+                                         arglist, target);
     case ALTIVEC_BUILTIN_LVX:
-      return altivec_expand_binop_builtin (CODE_FOR_altivec_lvx,
-                                          arglist, target);
+      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvx,
+                                         arglist, target);
     default:
       break;
       /* Fall through.  */
     }
 
-  /* 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 altivec_expand_ternop_builtin (d->icode, arglist, target);
-
-  abort ();
+  *expandedp = false;
   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;
-{
-  if (TARGET_ALTIVEC)
-    return altivec_expand_builtin (exp, target);
-
-  abort ();
-}
-
-static void
-rs6000_init_builtins ()
-{
-  if (TARGET_ALTIVEC)
-    altivec_init_builtins ();
-}
-
-static void
-altivec_init_builtins (void)
+     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;
-  struct builtin_description_predicates *dp;
   size_t i;
 
-  tree endlink = void_list_node;
-
-  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);
+  *expandedp = true;
 
-  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))));
+  /* 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;
+    }
 
-  /* V4SI foo (char).  */
-  tree v4si_ftype_char
-    = build_function_type (V4SI_type_node,
-                          tree_cons (NULL_TREE, char_type_node, endlink));
+  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);
 
-  /* V8HI foo (char).  */
-  tree v8hi_ftype_char
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, char_type_node, endlink));
+  d = (struct builtin_description *) bdesc_spe_predicates;
+  for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
+    if (d->code == fcode)
+      return spe_expand_predicate_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));
+  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);
 
-  /* 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));
+  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;
 
-  /* V8HI foo (V16QI).  */
-  tree v8hi_ftype_v16qi
-    = build_function_type (V8HI_type_node,
-                          tree_cons (NULL_TREE, V16QI_type_node, endlink));
+      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;
 
-  /* 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))));
+      if (arg0 == error_mark_node)
+       return const0_rtx;
 
-  /* 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 (! (*insn_data[icode].operand[0].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
 
-  /* void foo (V4SI).  */
-  tree void_ftype_v4si
+      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;
+  size_t i;
+  rtx ret;
+  bool success;
+  
+  if (TARGET_ALTIVEC)
+    {
+      ret = altivec_expand_builtin (exp, target, &success);
+
+      if (success)
+       return ret;
+    }
+  if (TARGET_SPE)
+    {
+      ret = spe_expand_builtin (exp, target, &success);
+
+      if (success)
+       return ret;
+    }
+
+  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);
+
+      /* 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);
+
+      /* 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);
+    }
+
+  abort ();
+  return NULL_RTX;
+}
+
+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 ();
+}
+
+/* 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;
+
+  for (i = 0; i < size; ++i)
+    if (desc[i].code == start)
+      break;
+
+  if (i == size)
+    return;
+
+  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 ();
+       }
+
+      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);
+    }
+}
 
-  /* vshort foo (void).  */
+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);
 
-  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)));
+  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);
+    }
 
-  /* These are for the unsigned 5 bit literals.  */
+  /* 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 v2si_ftype_char
+    = build_function_type_list (V2SI_type_node, char_type_node, NULL_TREE);
+
+  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;
@@ -4732,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;
@@ -4817,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++)
@@ -4859,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;
@@ -4883,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 ();
            }
@@ -4942,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)
        {
@@ -4970,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++)
@@ -5007,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;
@@ -5025,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 ();
 
@@ -5032,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.  */
 
@@ -5702,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))
@@ -5755,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);
 }
@@ -6206,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;
@@ -6247,29 +7225,93 @@ rs6000_got_register (value)
   return pic_offset_table_rtx;
 }
 \f
-/* Functions to init, mark and free struct machine_function.
-   These will be called, via pointer variables,
-   from push_function_context and pop_function_context.  */
+/* Function to init struct machine_function.
+   This will be called, via a pointer variable,
+   from push_function_context.  */
 
-static void
-rs6000_init_machine_status (p)
-     struct function *p;
+static struct machine_function *
+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;
 {
-  p->machine = (machine_function *) xcalloc (1, sizeof (machine_function));
+  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;
 }
 
-static void
-rs6000_free_machine_status (p)
-     struct function *p;
+int
+extract_ME (op)
+     rtx op;
 {
-  if (p->machine == NULL)
-    return;
+  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;
 
-  free (p->machine);
-  p->machine = NULL;
+  /* 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;
 }
 
-\f
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -6288,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)
     {
@@ -6361,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':
@@ -6471,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;
@@ -6498,42 +7547,15 @@ print_operand (file, x, code)
          if (small_data_operand (x, GET_MODE (x)))
            fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
                     reg_names[SMALL_DATA_REG]);
-       }
-      return;
-                           
-    case 'm':
-      /* MB value for a mask operand.  */
-      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;
+       }
+      return;
+                           
+    case 'm':
+      /* MB value for a mask operand.  */
+      if (! mask_operand (x, SImode))
+       output_operand_lossage ("invalid %%m value");
 
-      /* 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':
@@ -6541,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.  */
@@ -6665,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.  */
@@ -6920,7 +7889,7 @@ print_operand (file, x, code)
        }
       return;
 
-      /* Print AltiVec memory operand.  */
+      /* Print AltiVec or SPE memory operand.  */
     case 'y':
       {
        rtx tmp;
@@ -6930,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)
@@ -7158,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))
@@ -7287,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
@@ -7313,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);
@@ -7373,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;
@@ -7382,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.  */
@@ -7517,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;
@@ -7525,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 ();
@@ -7558,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))
@@ -7775,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
@@ -7830,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);
 
@@ -7878,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;
@@ -7891,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 ();
@@ -7946,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;
@@ -7979,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
@@ -8033,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;
 
@@ -8074,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);
 
@@ -8112,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);
@@ -8146,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);
 
@@ -8159,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);
 
@@ -8650,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),
@@ -8704,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,
@@ -8775,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
@@ -8792,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));
@@ -8902,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)
     {
@@ -8955,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;
@@ -8988,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);
+             }
          }
     }
 
@@ -9009,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);
        }
     }
 
@@ -9079,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;
     }
@@ -9206,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
@@ -9292,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);
 
@@ -9325,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);
@@ -9378,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.  */
@@ -9540,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)
     {
@@ -9593,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++;
@@ -9792,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
@@ -10044,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;
@@ -10255,8 +11590,10 @@ output_toc (file, x, labelno, mode)
          if (TARGET_MINIMAL_TOC)
            fputs (DOUBLE_INT_ASM_OP, file);
          else
-           fprintf (file, "\t.tc FD_%lx_%lx[TC],", k[0], k[1]);
-         fprintf (file, "0x%lx%08lx\n", k[0], k[1]);
+           fprintf (file, "\t.tc FD_%lx_%lx[TC],",
+                    k[0] & 0xffffffff, k[1] & 0xffffffff);
+         fprintf (file, "0x%lx%08lx\n",
+                  k[0] & 0xffffffff, k[1] & 0xffffffff);
          return;
        }
       else
@@ -10264,8 +11601,10 @@ output_toc (file, x, labelno, mode)
          if (TARGET_MINIMAL_TOC)
            fputs ("\t.long ", file);
          else
-           fprintf (file, "\t.tc FD_%lx_%lx[TC],", k[0], k[1]);
-         fprintf (file, "0x%lx,0x%lx\n", k[0], k[1]);
+           fprintf (file, "\t.tc FD_%lx_%lx[TC],",
+                    k[0] & 0xffffffff, k[1] & 0xffffffff);
+         fprintf (file, "0x%lx,0x%lx\n",
+                  k[0] & 0xffffffff, k[1] & 0xffffffff);
          return;
        }
     }
@@ -10282,8 +11621,8 @@ output_toc (file, x, labelno, mode)
          if (TARGET_MINIMAL_TOC)
            fputs (DOUBLE_INT_ASM_OP, file);
          else
-           fprintf (file, "\t.tc FS_%lx[TC],", l);
-         fprintf (file, "0x%lx00000000\n", l);
+           fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
+         fprintf (file, "0x%lx00000000\n", l & 0xffffffff);
          return;
        }
       else
@@ -10291,8 +11630,8 @@ output_toc (file, x, labelno, mode)
          if (TARGET_MINIMAL_TOC)
            fputs ("\t.long ", file);
          else
-           fprintf (file, "\t.tc FS_%lx[TC],", l);
-         fprintf (file, "0x%lx\n", l);
+           fprintf (file, "\t.tc FS_%lx[TC],", l & 0xffffffff);
+         fprintf (file, "0x%lx\n", l & 0xffffffff);
          return;
        }
     }
@@ -10334,16 +11673,27 @@ 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)
        {
          if (TARGET_MINIMAL_TOC)
            fputs (DOUBLE_INT_ASM_OP, file);
          else
-           fprintf (file, "\t.tc ID_%lx_%lx[TC],", (long) high, (long) low);
-         fprintf (file, "0x%lx%08lx\n", (long) high, (long) low);
+           fprintf (file, "\t.tc ID_%lx_%lx[TC],",
+                    (long) high & 0xffffffff, (long) low & 0xffffffff);
+         fprintf (file, "0x%lx%08lx\n",
+                  (long) high & 0xffffffff, (long) low & 0xffffffff);
          return;
        }
       else
@@ -10354,16 +11704,17 @@ output_toc (file, x, labelno, mode)
                fputs ("\t.long ", file);
              else
                fprintf (file, "\t.tc ID_%lx_%lx[TC],",
-                        (long) high, (long) low);
-             fprintf (file, "0x%lx,0x%lx\n", (long) high, (long) low);
+                        (long) high & 0xffffffff, (long) low & 0xffffffff);
+             fprintf (file, "0x%lx,0x%lx\n",
+                      (long) high & 0xffffffff, (long) low & 0xffffffff);
            }
          else
            {
              if (TARGET_MINIMAL_TOC)
                fputs ("\t.long ", file);
              else
-               fprintf (file, "\t.tc IS_%lx[TC],", (long) low);
-             fprintf (file, "0x%lx\n", (long) low);
+               fprintf (file, "\t.tc IS_%lx[TC],", (long) low & 0xffffffff);
+             fprintf (file, "0x%lx\n", (long) low & 0xffffffff);
            }
          return;
        }
@@ -10523,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++ = '_';
@@ -10550,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;
@@ -10564,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)
     {
@@ -10597,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)
@@ -10605,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);
@@ -10619,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);
@@ -10636,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;
-
     }
 }
 
@@ -10683,18 +12052,24 @@ rs6000_adjust_cost (insn, link, dep_insn, cost)
       switch (get_attr_type (insn))
        {
        case TYPE_JMPREG:
-          /* Tell the first scheduling pass about the latency between
+         /* Tell the first scheduling pass about the latency between
             a mtctr and bctr (and mtlr and br/blr).  The first
             scheduling pass will not know about this latency since
             the mtctr instruction, which has the latency associated
             to it, will be generated by reload.  */
-          return TARGET_POWER ? 5 : 4;
+         return TARGET_POWER ? 5 : 4;
        case TYPE_BRANCH:
          /* Leave some extra cycles between a compare and its
             dependent branch, to inhibit expensive mispredicts.  */
-         if ((rs6000_cpu_attr == CPU_PPC750
-               || rs6000_cpu_attr == CPU_PPC7400
-               || rs6000_cpu_attr == CPU_PPC7450)
+         if ((rs6000_cpu_attr == CPU_PPC603
+              || rs6000_cpu_attr == CPU_PPC604
+              || rs6000_cpu_attr == CPU_PPC604E
+              || rs6000_cpu_attr == CPU_PPC620
+              || rs6000_cpu_attr == CPU_PPC630
+              || rs6000_cpu_attr == CPU_PPC750
+              || rs6000_cpu_attr == CPU_PPC7400
+              || rs6000_cpu_attr == CPU_PPC7450
+              || rs6000_cpu_attr == CPU_POWER4)
              && recog_memoized (dep_insn)
              && (INSN_CODE (dep_insn) >= 0)
              && (get_attr_type (dep_insn) == TYPE_COMPARE
@@ -10775,6 +12150,7 @@ rs6000_issue_rate ()
   case CPU_PPC604E:
   case CPU_PPC620:
   case CPU_PPC630:
+  case CPU_POWER4:
     return 4;
   default:
     return 1;
@@ -11226,16 +12602,9 @@ rs6000_fatal_bad_address (op)
 static void
 rs6000_add_gc_roots ()
 {
-  ggc_add_rtx_root (&rs6000_compare_op0, 1);
-  ggc_add_rtx_root (&rs6000_compare_op1, 1);
-
   toc_hash_table = htab_create (1021, toc_hash_function, toc_hash_eq, NULL);
   ggc_add_root (&toc_hash_table, 1, sizeof (toc_hash_table), 
                toc_hash_mark_table);
-
-#if TARGET_MACHO
-  machopic_add_gc_roots ();
-#endif
 }
 
 #if TARGET_MACHO
@@ -11297,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))
@@ -11384,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",
@@ -11642,7 +13010,7 @@ rs6000_elf_asm_out_destructor (symbol, priority)
 }
 #endif
 
-#ifdef OBJECT_FORMAT_COFF
+#if TARGET_XCOFF
 static void
 xcoff_asm_named_section (name, flags)
      const char *name;
@@ -11733,7 +13101,7 @@ rs6000_xcoff_strip_name_encoding (name)
     return name;
 }
 
-#endif /* OBJECT_FORMAT_COFF */
+#endif /* TARGET_XCOFF */
 
 /* Note that this is also used for ELF64.  */