OSDN Git Service

* config/rs6000/rs6000.c (output_toc): Make "offset" HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 602e83a..8d51003 100644 (file)
@@ -17,8 +17,8 @@
 
    You should have received a copy of the GNU General Public License
    along with GCC; see the file COPYING.  If not, write to the
-   Free Software Foundation, 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.  */
+   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -93,7 +93,6 @@ typedef struct rs6000_stack {
   int varargs_save_offset;     /* offset to save the varargs registers */
   int ehrd_offset;             /* offset to EH return data */
   int reg_size;                        /* register size (4 or 8) */
-  int varargs_size;            /* size to hold V.4 args passed in regs */
   HOST_WIDE_INT vars_size;     /* variable save area size */
   int parm_size;               /* outgoing parameter size */
   int save_size;               /* save area size */
@@ -113,6 +112,23 @@ typedef struct rs6000_stack {
   int spe_64bit_regs_used;
 } rs6000_stack_t;
 
+/* A C structure for machine-specific, per-function data.
+   This is added to the cfun structure.  */
+typedef struct machine_function GTY(())
+{
+  /* Flags if __builtin_return_address (n) with n >= 1 was used.  */
+  int ra_needs_full_frame;
+  /* Some local-dynamic symbol.  */
+  const char *some_ld_name;
+  /* Whether the instruction chain has been scanned already.  */
+  int insn_chain_scanned_p;
+  /* Flags if __builtin_return_address (0) was used.  */
+  int ra_need_lr;
+  /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
+     varargs save area.  */
+  HOST_WIDE_INT varargs_save_offset;
+} machine_function;
+
 /* Target cpu type */
 
 enum processor_type rs6000_cpu;
@@ -130,11 +146,6 @@ static GTY(()) bool rs6000_always_hint;
 /* Schedule instructions for group formation.  */
 static GTY(()) bool rs6000_sched_groups;
 
-/* Support adjust_priority scheduler hook
-   and -mprioritize-restricted-insns= option.  */
-const char *rs6000_sched_restricted_insns_priority_str;
-int rs6000_sched_restricted_insns_priority;
-
 /* Support for -msched-costly-dep option.  */
 const char *rs6000_sched_costly_dep_str;
 enum rs6000_dependence_cost rs6000_sched_costly_dep;
@@ -147,42 +158,20 @@ enum rs6000_nop_insertion rs6000_sched_insert_nops;
 static GTY(()) tree altivec_builtin_mask_for_load;
 
 /* Size of long double */
-const char *rs6000_long_double_size_string;
 int rs6000_long_double_type_size;
 
 /* Whether -mabi=altivec has appeared */
 int rs6000_altivec_abi;
 
-/* Whether VRSAVE instructions should be generated.  */
-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;
-
-/* Whether SPE simd instructions should be generated.  */
-int rs6000_spe;
-
 /* Nonzero if floating point operations are done in the GPRs.  */
 int rs6000_float_gprs = 0;
 
 /* Nonzero if we want Darwin's struct-by-value-in-regs ABI.  */
 int rs6000_darwin64_abi;
 
-/* String from -mfloat-gprs=.  */
-const char *rs6000_float_gprs_string;
-
-/* String from -misel=.  */
-const char *rs6000_isel_string;
-
-/* String from -mspe=.  */
-const char *rs6000_spe_string;
-
 /* Set to nonzero once AIX common-mode calls have been defined.  */
 static GTY(()) int common_mode_defined;
 
@@ -216,9 +205,6 @@ const char *rs6000_tls_size_string;
 /* ABI enumeration available for subtarget to use.  */
 enum rs6000_abi rs6000_current_abi;
 
-/* ABI string from -mabi= option.  */
-const char *rs6000_abi_string;
-
 /* Whether to use variant of AIX ABI for PowerPC64 Linux.  */
 int dot_symbols;
 
@@ -227,34 +213,13 @@ const char *rs6000_debug_name;
 int rs6000_debug_stack;                /* debug stack applications */
 int rs6000_debug_arg;          /* debug argument handling */
 
-/* Value is TRUE if register/mode pair is accepatable.  */
+/* Value is TRUE if register/mode pair is acceptable.  */
 bool rs6000_hard_regno_mode_ok_p[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
 
-/* Opaque types.  */
-static GTY(()) tree opaque_V2SI_type_node;
-static GTY(()) tree opaque_V2SF_type_node;
-static GTY(()) tree opaque_p_V2SI_type_node;
-static GTY(()) tree V16QI_type_node;
-static GTY(()) tree V2SI_type_node;
-static GTY(()) tree V2SF_type_node;
-static GTY(()) tree V4HI_type_node;
-static GTY(()) tree V4SI_type_node;
-static GTY(()) tree V4SF_type_node;
-static GTY(()) tree V8HI_type_node;
-static GTY(()) tree unsigned_V16QI_type_node;
-static GTY(()) tree unsigned_V8HI_type_node;
-static GTY(()) tree unsigned_V4SI_type_node;
-static GTY(()) tree bool_char_type_node;       /* __bool char */
-static GTY(()) tree bool_short_type_node;      /* __bool short */
-static GTY(()) tree bool_int_type_node;                /* __bool int */
-static GTY(()) tree pixel_type_node;           /* __pixel */
-static GTY(()) tree bool_V16QI_type_node;      /* __vector __bool char */
-static GTY(()) tree bool_V8HI_type_node;       /* __vector __bool short */
-static GTY(()) tree bool_V4SI_type_node;       /* __vector __bool int */
-static GTY(()) tree pixel_V8HI_type_node;      /* __vector __pixel */
-
-int rs6000_warn_altivec_long = 1;              /* On by default. */
-const char *rs6000_warn_altivec_long_switch;
+/* Built in types.  */
+
+tree rs6000_builtin_types[RS6000_BTI_MAX];
+tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
 
 const char *rs6000_traceback_name;
 static enum {
@@ -271,19 +236,21 @@ char toc_label_name[10];
 /* Alias set for saves and restores from the rs6000 stack.  */
 static GTY(()) int rs6000_sr_alias_set;
 
-/* Call distance, overridden by -mlongcall and #pragma longcall(1).
-   The only place that looks at this is rs6000_set_default_type_attributes;
-   everywhere else should rely on the presence or absence of a longcall
-   attribute on the function declaration.  Exception: init_cumulative_args
-   looks at it too, for libcalls.  */
-int rs6000_default_long_calls;
-const char *rs6000_longcall_switch;
-
 /* Control alignment for fields within structures.  */
 /* String from -malign-XXXXX.  */
-const char *rs6000_alignment_string;
 int rs6000_alignment_flags;
 
+/* True for any options that were explicitly set.  */
+struct {
+  bool aix_struct_ret;         /* True if -maix-struct-ret was used.  */
+  bool alignment;              /* True if -malign- was used.  */
+  bool abi;                    /* True if -mabi= was used.  */
+  bool spe;                    /* True if -mspe= was used.  */
+  bool float_gprs;             /* True if -mfloat-gprs= was used.  */
+  bool isel;                   /* True if -misel was used. */
+  bool long_double;            /* True if -mlong-double- was used.  */
+} rs6000_explicit_options;
+
 struct builtin_description
 {
   /* mask is not const because we're going to alter it below.  This
@@ -601,6 +568,7 @@ struct processor_costs power4_cost = {
 
 \f
 static bool rs6000_function_ok_for_sibcall (tree, tree);
+static const char *rs6000_invalid_within_doloop (rtx);
 static rtx rs6000_generate_compare (enum rtx_code);
 static void rs6000_maybe_dead (rtx);
 static void rs6000_emit_stack_tie (void);
@@ -616,11 +584,11 @@ static unsigned toc_hash_function (const void *);
 static int toc_hash_eq (const void *, const void *);
 static int constant_pool_expr_1 (rtx, int *, int *);
 static bool constant_pool_expr_p (rtx);
-static bool legitimate_small_data_p (enum machine_mode, rtx);
 static bool legitimate_indexed_address_p (rtx, int);
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
 static bool rs6000_assemble_integer (rtx, unsigned int, int);
+static bool no_global_regs_above (int);
 #ifdef HAVE_GAS_HIDDEN
 static void rs6000_assemble_visibility (tree, int);
 #endif
@@ -642,6 +610,7 @@ static void rs6000_file_start (void);
 static unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
 static void rs6000_elf_asm_out_constructor (rtx, int);
 static void rs6000_elf_asm_out_destructor (rtx, int);
+static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
 static void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
 static void rs6000_elf_unique_section (tree, int);
 static void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
@@ -662,9 +631,6 @@ static unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
 static void rs6000_xcoff_file_start (void);
 static void rs6000_xcoff_file_end (void);
 #endif
-#if TARGET_MACHO
-static bool rs6000_binds_local_p (tree);
-#endif
 static int rs6000_variable_issue (FILE *, int, rtx, int);
 static bool rs6000_rtx_costs (rtx, int, int, int *);
 static int rs6000_adjust_cost (rtx, rtx, rtx, int);
@@ -685,6 +651,7 @@ static void rs6000_sched_finish (FILE *, int);
 static int rs6000_use_sched_lookahead (void);
 static tree rs6000_builtin_mask_for_load (void);
 
+static void def_builtin (int, const char *, tree, int);
 static void rs6000_init_builtins (void);
 static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
@@ -716,20 +683,23 @@ static rtx altivec_expand_predicate_builtin (enum insn_code,
                                             const char *, tree, rtx);
 static rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
 static rtx altivec_expand_stv_builtin (enum insn_code, tree);
-static void rs6000_parse_abi_options (void);
-static void rs6000_parse_alignment_option (void);
+static rtx altivec_expand_vec_init_builtin (tree, tree, rtx);
+static rtx altivec_expand_vec_set_builtin (tree);
+static rtx altivec_expand_vec_ext_builtin (tree, rtx);
+static int get_element_number (tree, tree);
+static bool rs6000_handle_option (size_t, const char *, int);
 static void rs6000_parse_tls_size_option (void);
 static void rs6000_parse_yes_no_option (const char *, const char *, int *);
-static void rs6000_parse_float_gprs_option (void);
 static int first_altivec_reg_to_save (void);
 static unsigned int compute_vrsave_mask (void);
 static void compute_save_world_info (rs6000_stack_t *info_ptr);
 static void is_altivec_return_reg (rtx, void *);
 static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
 int easy_vector_constant (rtx, enum machine_mode);
-static bool is_ev64_opaque_type (tree);
+static bool rs6000_is_opaque_type (tree);
 static rtx rs6000_dwarf_register_span (rtx);
 static rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
+static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static rtx rs6000_tls_get_addr (void);
 static rtx rs6000_got_sym (void);
 static int rs6000_tls_symbol_ref_1 (rtx *, void *);
@@ -777,7 +747,7 @@ static rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx,
                                       enum machine_mode);
 static int get_vsel_insn (enum machine_mode);
 static void rs6000_emit_vector_select (rtx, rtx, rtx, rtx);
-
+static tree rs6000_stack_protect_fail (void);
 
 const int INSN_NOT_AVAILABLE = -1;
 static enum machine_mode rs6000_eh_return_filter_mode (void);
@@ -816,7 +786,9 @@ char rs6000_reg_names[][8] =
       "24", "25", "26", "27", "28", "29", "30", "31",
       "vrsave", "vscr",
       /* SPE registers.  */
-      "spe_acc", "spefscr"
+      "spe_acc", "spefscr",
+      /* Soft frame pointer.  */
+      "sfp"
 };
 
 #ifdef TARGET_REGNAMES
@@ -840,7 +812,9 @@ static const char alt_reg_names[][8] =
   "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
   "vrsave", "vscr",
   /* SPE registers.  */
-  "spe_acc", "spefscr"
+  "spe_acc", "spefscr",
+  /* Soft frame pointer.  */
+  "sfp"
 };
 #endif
 \f
@@ -943,7 +917,7 @@ static const char alt_reg_names[][8] =
 
 #if TARGET_MACHO
 #undef TARGET_BINDS_LOCAL_P
-#define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
+#define TARGET_BINDS_LOCAL_P darwin_binds_local_p
 #endif
 
 #undef TARGET_ASM_OUTPUT_MI_THUNK
@@ -955,13 +929,16 @@ static const char alt_reg_names[][8] =
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
 
+#undef TARGET_INVALID_WITHIN_DOLOOP
+#define TARGET_INVALID_WITHIN_DOLOOP rs6000_invalid_within_doloop
+
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS rs6000_rtx_costs
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST hook_int_rtx_0
 
 #undef TARGET_VECTOR_OPAQUE_P
-#define TARGET_VECTOR_OPAQUE_P is_ev64_opaque_type
+#define TARGET_VECTOR_OPAQUE_P rs6000_is_opaque_type
 
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
@@ -1008,6 +985,16 @@ static const char alt_reg_names[][8] =
 #undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
 #define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
 
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION rs6000_handle_option
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS \
+  (TARGET_DEFAULT | MASK_SCHED_PROLOG)
+
+#undef TARGET_STACK_PROTECT_FAIL
+#define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
+
 /* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
    The PowerPC architecture requires only weak consistency among
    processors--that is, memory accesses between processors need not be
@@ -1019,6 +1006,11 @@ static const char alt_reg_names[][8] =
 #undef TARGET_RELAXED_ORDERING
 #define TARGET_RELAXED_ORDERING true
 
+#ifdef HAVE_AS_TLS
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -1157,17 +1149,19 @@ rs6000_override_options (const char *default_cpu)
         {"power4", PROCESSOR_POWER4,
          POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
         {"power5", PROCESSOR_POWER5,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POWERPC64},
+         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GFXOPT
+         | MASK_MFCRF | MASK_POPCNTB},
         {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
         {"powerpc64", PROCESSOR_POWERPC64,
-         POWERPC_BASE_MASK | MASK_POWERPC64},
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
         {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
         {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
         {"rios2", PROCESSOR_RIOS2,
          MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
         {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
         {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK | MASK_POWERPC64},
+        {"rs64", PROCESSOR_RS64A,
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}
       };
 
   const size_t ptt_size = ARRAY_SIZE (processor_target_table);
@@ -1249,14 +1243,14 @@ rs6000_override_options (const char *default_cpu)
        {
          target_flags &= ~MASK_MULTIPLE;
          if ((target_flags_explicit & MASK_MULTIPLE) != 0)
-           warning ("-mmultiple is not supported on little endian systems");
+           warning (0, "-mmultiple is not supported on little endian systems");
        }
 
       if (TARGET_STRING)
        {
          target_flags &= ~MASK_STRING;
          if ((target_flags_explicit & MASK_STRING) != 0)
-           warning ("-mstring is not supported on little endian systems");
+           warning (0, "-mstring is not supported on little endian systems");
        }
     }
 
@@ -1286,53 +1280,27 @@ rs6000_override_options (const char *default_cpu)
               rs6000_traceback_name);
     }
 
-  /* Set size of long double */
-  rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
-  if (rs6000_long_double_size_string)
-    {
-      char *tail;
-      int size = strtol (rs6000_long_double_size_string, &tail, 10);
-      if (*tail != '\0' || (size != 64 && size != 128))
-       error ("Unknown switch -mlong-double-%s",
-              rs6000_long_double_size_string);
-      else
-       rs6000_long_double_type_size = size;
-    }
+  if (!rs6000_explicit_options.long_double)
+    rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
 
   /* Set Altivec ABI as default for powerpc64 linux.  */
   if (TARGET_ELF && TARGET_64BIT)
     {
       rs6000_altivec_abi = 1;
-      rs6000_altivec_vrsave = 1;
+      TARGET_ALTIVEC_VRSAVE = 1;
     }
 
   /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
   if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
     {
       rs6000_darwin64_abi = 1;
-      /* Setting to empty string is same as "-mone-byte-bool".  */
 #if TARGET_MACHO
-      darwin_one_byte_bool = "";
+      darwin_one_byte_bool = 1;
 #endif
       /* Default to natural alignment, for better performance.  */
       rs6000_alignment_flags = MASK_ALIGN_NATURAL;
     }
 
-  /* Handle -mabi= options.  */
-  rs6000_parse_abi_options ();
-
-  /* Handle -malign-XXXXX option.  */
-  rs6000_parse_alignment_option ();
-
-  rs6000_parse_float_gprs_option ();
-
-  /* Handle generic -mFOO=YES/NO options.  */
-  rs6000_parse_yes_no_option ("vrsave", rs6000_altivec_vrsave_string,
-                             &rs6000_altivec_vrsave);
-  rs6000_parse_yes_no_option ("isel", rs6000_isel_string,
-                             &rs6000_isel);
-  rs6000_parse_yes_no_option ("spe", rs6000_spe_string, &rs6000_spe);
-
   /* Handle -mtls-size option.  */
   rs6000_parse_tls_size_option ();
 
@@ -1355,26 +1323,21 @@ rs6000_override_options (const char *default_cpu)
         MASK_STRING above when optimizing for size.  */
       if ((target_flags & MASK_STRING) != 0)
        target_flags = target_flags & ~MASK_STRING;
-
-      /* No SPE means 64-bit long doubles, even if an E500.  */
-      if (rs6000_spe_string != 0
-         && !strcmp (rs6000_spe_string, "no"))
-       rs6000_long_double_type_size = 64;
     }
   else if (rs6000_select[1].string != NULL)
     {
       /* For the powerpc-eabispe configuration, we set all these by
         default, so let's unset them if we manually set another
         CPU that is not the E500.  */
-      if (rs6000_abi_string == 0)
+      if (!rs6000_explicit_options.abi)
        rs6000_spe_abi = 0;
-      if (rs6000_spe_string == 0)
+      if (!rs6000_explicit_options.spe)
        rs6000_spe = 0;
-      if (rs6000_float_gprs_string == 0)
+      if (!rs6000_explicit_options.float_gprs)
        rs6000_float_gprs = 0;
-      if (rs6000_isel_string == 0)
+      if (!rs6000_explicit_options.isel)
        rs6000_isel = 0;
-      if (rs6000_long_double_size_string == 0)
+      if (!rs6000_explicit_options.long_double)
        rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
@@ -1383,43 +1346,13 @@ rs6000_override_options (const char *default_cpu)
   rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
                         || rs6000_cpu == PROCESSOR_POWER5);
 
-  /* 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.
-     Assumption here is that rs6000_longcall_switch points into the
-     text of the complete option, rather than being a copy, so we can
-     scan back for the presence or absence of the no- modifier.  */
-  if (rs6000_longcall_switch)
-    {
-      const char *base = rs6000_longcall_switch;
-      while (base[-1] != 'm') base--;
-
-      if (*rs6000_longcall_switch != '\0')
-       error ("invalid option %qs", base);
-      rs6000_default_long_calls = (base[0] != 'n');
-    }
-
-  /* Handle -m(no-)warn-altivec-long similarly.  */
-  if (rs6000_warn_altivec_long_switch)
-    {
-      const char *base = rs6000_warn_altivec_long_switch;
-      while (base[-1] != 'm') base--;
-
-      if (*rs6000_warn_altivec_long_switch != '\0')
-       error ("invalid option %qs", base);
-      rs6000_warn_altivec_long = (base[0] != 'n');
-    }
-
-  /* Handle -mprioritize-restricted-insns option.  */
   rs6000_sched_restricted_insns_priority
     = (rs6000_sched_groups ? 1 : 0);
-  if (rs6000_sched_restricted_insns_priority_str)
-    rs6000_sched_restricted_insns_priority =
-      atoi (rs6000_sched_restricted_insns_priority_str);
 
   /* Handle -msched-costly-dep option.  */
   rs6000_sched_costly_dep
     = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
+
   if (rs6000_sched_costly_dep_str)
     {
       if (! strcmp (rs6000_sched_costly_dep_str, "no"))
@@ -1437,6 +1370,7 @@ rs6000_override_options (const char *default_cpu)
   /* Handle -minsert-sched-nops option.  */
   rs6000_sched_insert_nops
     = (rs6000_sched_groups ? sched_finish_regroup_exact : sched_finish_none);
+
   if (rs6000_sched_insert_nops_str)
     {
       if (! strcmp (rs6000_sched_insert_nops_str, "no"))
@@ -1456,16 +1390,11 @@ rs6000_override_options (const char *default_cpu)
     memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
 #endif
 
-  /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
+  /* Set aix_struct_return last, after the ABI is determined.
      If -maix-struct-return or -msvr4-struct-return was explicitly
      used, don't override with the ABI default.  */
-  if ((target_flags_explicit & MASK_AIX_STRUCT_RET) == 0)
-    {
-      if (DEFAULT_ABI == ABI_V4 && !DRAFT_V4_STRUCT_RET)
-       target_flags = (target_flags & ~MASK_AIX_STRUCT_RET);
-      else
-       target_flags |= MASK_AIX_STRUCT_RET;
-    }
+  if (!rs6000_explicit_options.aix_struct_ret)
+    aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
 
   if (TARGET_LONG_DOUBLE_128
       && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
@@ -1588,7 +1517,7 @@ rs6000_override_options (const char *default_cpu)
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
       }
 }
 
@@ -1620,87 +1549,6 @@ rs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
     error ("unknown -m%s= option specified: '%s'", name, value);
 }
 
-/* Handle -mabi= options.  */
-static void
-rs6000_parse_abi_options (void)
-{
-  if (rs6000_abi_string == 0)
-    return;
-  else if (! strcmp (rs6000_abi_string, "altivec"))
-    {
-      rs6000_altivec_abi = 1;
-      rs6000_spe_abi = 0;
-    }
-  else if (! strcmp (rs6000_abi_string, "no-altivec"))
-    rs6000_altivec_abi = 0;
-  else if (! strcmp (rs6000_abi_string, "spe"))
-    {
-      rs6000_spe_abi = 1;
-      rs6000_altivec_abi = 0;
-      if (!TARGET_SPE_ABI)
-       error ("not configured for ABI: '%s'", rs6000_abi_string);
-    }
-
-  /* These are here for testing during development only, do not
-     document in the manual please.  */
-  else if (! strcmp (rs6000_abi_string, "d64"))
-    {
-      rs6000_darwin64_abi = 1;
-      warning ("Using darwin64 ABI");
-    }
-  else if (! strcmp (rs6000_abi_string, "d32"))
-    {
-      rs6000_darwin64_abi = 0;
-      warning ("Using old darwin ABI");
-    }
-
-  else if (! strcmp (rs6000_abi_string, "no-spe"))
-    rs6000_spe_abi = 0;
-  else
-    error ("unknown ABI specified: '%s'", rs6000_abi_string);
-}
-
-/* Handle -mfloat-gprs= options.  */
-static void
-rs6000_parse_float_gprs_option (void)
-{
-  if (rs6000_float_gprs_string == 0)
-    return;
-  else if (! strcmp (rs6000_float_gprs_string, "yes")
-          || ! strcmp (rs6000_float_gprs_string, "single"))
-    rs6000_float_gprs = 1;
-  else if (! strcmp (rs6000_float_gprs_string, "double"))
-    rs6000_float_gprs = 2;
-  else if (! strcmp (rs6000_float_gprs_string, "no"))
-    rs6000_float_gprs = 0;
-  else
-    error ("invalid option for -mfloat-gprs");
-}
-
-/* Handle -malign-XXXXXX options.  */
-static void
-rs6000_parse_alignment_option (void)
-{
-  if (rs6000_alignment_string == 0)
-    return;
-  else if (! strcmp (rs6000_alignment_string, "power"))
-    {
-      /* On 64-bit Darwin, power alignment is ABI-incompatible with
-        some C library functions, so warn about it. The flag may be
-        useful for performance studies from time to time though, so
-        don't disable it entirely.  */
-      if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
-       warning ("-malign-power is not supported for 64-bit Darwin;"
-                " it is incompatible with the installed C and C++ libraries");
-      rs6000_alignment_flags = MASK_ALIGN_POWER;
-    }
-  else if (! strcmp (rs6000_alignment_string, "natural"))
-    rs6000_alignment_flags = MASK_ALIGN_NATURAL;
-  else
-    error ("unknown -malign-XXXXX option specified: '%s'",
-          rs6000_alignment_string);
-}
-
 /* Validate and record the size specified with the -mtls-size option.  */
 
 static void
@@ -1721,6 +1569,277 @@ rs6000_parse_tls_size_option (void)
 void
 optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
 {
+  if (DEFAULT_ABI == ABI_DARWIN)
+    /* The Darwin libraries never set errno, so we might as well
+       avoid calling them when that's the only reason we would.  */
+    flag_errno_math = 0;
+}
+
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+rs6000_handle_option (size_t code, const char *arg, int value)
+{
+  switch (code)
+    {
+    case OPT_mno_power:
+      target_flags &= ~(MASK_POWER | MASK_POWER2
+                       | MASK_MULTIPLE | MASK_STRING);
+      target_flags_explicit |= (MASK_POWER | MASK_POWER2
+                               | MASK_MULTIPLE | MASK_STRING);
+      break;
+    case OPT_mno_powerpc:
+      target_flags &= ~(MASK_POWERPC | MASK_PPC_GPOPT
+                       | MASK_PPC_GFXOPT | MASK_POWERPC64);
+      target_flags_explicit |= (MASK_POWERPC | MASK_PPC_GPOPT
+                               | MASK_PPC_GFXOPT | MASK_POWERPC64);
+      break;
+    case OPT_mfull_toc:
+      target_flags &= ~(MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC
+                       | MASK_NO_SUM_IN_TOC);
+      target_flags_explicit |= (MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC
+                               | MASK_NO_SUM_IN_TOC);
+#ifdef TARGET_USES_SYSV4_OPT
+      /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
+        just the same as -mminimal-toc.  */
+      target_flags |= MASK_MINIMAL_TOC;
+      target_flags_explicit |= MASK_MINIMAL_TOC;
+#endif
+      break;
+
+#ifdef TARGET_USES_SYSV4_OPT
+    case OPT_mtoc:
+      /* Make -mtoc behave like -mminimal-toc.  */
+      target_flags |= MASK_MINIMAL_TOC;
+      target_flags_explicit |= MASK_MINIMAL_TOC;
+      break;
+#endif
+
+#ifdef TARGET_USES_AIX64_OPT
+    case OPT_maix64:
+#else
+    case OPT_m64:
+#endif
+      target_flags |= MASK_POWERPC64 | MASK_POWERPC | MASK_PPC_GFXOPT;
+      target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC
+       | MASK_PPC_GFXOPT;
+      break;
+
+#ifdef TARGET_USES_AIX64_OPT
+    case OPT_maix32:
+#else
+    case OPT_m32:
+#endif
+      target_flags &= ~MASK_POWERPC64;
+      target_flags_explicit |= MASK_POWERPC64;
+      break;
+
+    case OPT_minsert_sched_nops_:
+      rs6000_sched_insert_nops_str = arg;
+      break;
+
+    case OPT_mminimal_toc:
+      if (value == 1)
+       {
+         target_flags &= ~(MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC);
+         target_flags_explicit |= (MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC);
+       }
+      break;
+
+    case OPT_mpower:
+      if (value == 1)
+       {
+         target_flags |= (MASK_MULTIPLE | MASK_STRING);
+         target_flags_explicit |= (MASK_MULTIPLE | MASK_STRING);
+       }
+      break;
+
+    case OPT_mpower2:
+      if (value == 1)
+       {
+         target_flags |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
+         target_flags_explicit |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
+       }
+      break;
+
+    case OPT_mpowerpc_gpopt:
+    case OPT_mpowerpc_gfxopt:
+      if (value == 1)
+       {
+         target_flags |= MASK_POWERPC;
+         target_flags_explicit |= MASK_POWERPC;
+       }
+      break;
+
+    case OPT_maix_struct_return:
+    case OPT_msvr4_struct_return:
+      rs6000_explicit_options.aix_struct_ret = true;
+      break;
+
+    case OPT_mvrsave_:
+      rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
+      break;
+
+    case OPT_misel_:
+      rs6000_explicit_options.isel = true;
+      rs6000_parse_yes_no_option ("isel", arg, &(rs6000_isel));
+      break;
+
+    case OPT_mspe_:
+      rs6000_explicit_options.spe = true;
+      rs6000_parse_yes_no_option ("spe", arg, &(rs6000_spe));
+      /* No SPE means 64-bit long doubles, even if an E500.  */
+      if (!rs6000_spe)
+       rs6000_long_double_type_size = 64;
+      break;
+
+    case OPT_mdebug_:
+      rs6000_debug_name = arg;
+      break;
+
+#ifdef TARGET_USES_SYSV4_OPT
+    case OPT_mcall_:
+      rs6000_abi_name = arg;
+      break;
+
+    case OPT_msdata_:
+      rs6000_sdata_name = arg;
+      break;
+
+    case OPT_mtls_size_:
+      rs6000_tls_size_string = arg;
+      break;
+
+    case OPT_mrelocatable:
+      if (value == 1)
+       {
+         target_flags |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC;
+         target_flags_explicit |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC;
+       }
+      break;
+
+    case OPT_mrelocatable_lib:
+      if (value == 1)
+       {
+         target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC
+           | MASK_NO_FP_IN_TOC;
+         target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC
+           | MASK_NO_FP_IN_TOC;
+       }
+      else
+       {
+         target_flags &= ~MASK_RELOCATABLE;
+         target_flags_explicit |= MASK_RELOCATABLE;
+       }
+      break;
+#endif
+
+    case OPT_mabi_:
+      rs6000_explicit_options.abi = true;
+      if (!strcmp (arg, "altivec"))
+       {
+         rs6000_altivec_abi = 1;
+         rs6000_spe_abi = 0;
+       }
+      else if (! strcmp (arg, "no-altivec"))
+       rs6000_altivec_abi = 0;
+      else if (! strcmp (arg, "spe"))
+       {
+         rs6000_spe_abi = 1;
+         rs6000_altivec_abi = 0;
+         if (!TARGET_SPE_ABI)
+           error ("not configured for ABI: '%s'", arg);
+       }
+      else if (! strcmp (arg, "no-spe"))
+       rs6000_spe_abi = 0;
+
+      /* These are here for testing during development only, do not
+        document in the manual please.  */
+      else if (! strcmp (arg, "d64"))
+       {
+         rs6000_darwin64_abi = 1;
+         warning (0, "Using darwin64 ABI");
+       }
+      else if (! strcmp (arg, "d32"))
+       {
+         rs6000_darwin64_abi = 0;
+         warning (0, "Using old darwin ABI");
+       }
+
+      else
+       {
+         error ("unknown ABI specified: '%s'", arg);
+         return false;
+       }
+      break;
+
+    case OPT_mcpu_:
+      rs6000_select[1].string = arg;
+      break;
+
+    case OPT_mtune_:
+      rs6000_select[2].string = arg;
+      break;
+
+    case OPT_mtraceback_:
+      rs6000_traceback_name = arg;
+      break;
+
+    case OPT_mfloat_gprs_:
+      rs6000_explicit_options.float_gprs = true;
+      if (! strcmp (arg, "yes") || ! strcmp (arg, "single"))
+       rs6000_float_gprs = 1;
+      else if (! strcmp (arg, "double"))
+       rs6000_float_gprs = 2;
+      else if (! strcmp (arg, "no"))
+       rs6000_float_gprs = 0;
+      else
+       {
+         error ("invalid option for -mfloat-gprs: '%s'", arg);
+         return false;
+       }
+      break;
+
+    case OPT_mlong_double_:
+      rs6000_explicit_options.long_double = true;
+      rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
+      if (value != 64 && value != 128)
+       {
+         error ("Unknown switch -mlong-double-%s", arg);
+         rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
+         return false;
+       }
+      else
+       rs6000_long_double_type_size = value;
+      break;
+
+    case OPT_msched_costly_dep_:
+      rs6000_sched_costly_dep_str = arg;
+      break;
+
+    case OPT_malign_:
+      rs6000_explicit_options.alignment = true;
+      if (! strcmp (arg, "power"))
+       {
+         /* On 64-bit Darwin, power alignment is ABI-incompatible with
+            some C library functions, so warn about it. The flag may be
+            useful for performance studies from time to time though, so
+            don't disable it entirely.  */
+         if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
+           warning (0, "-malign-power is not supported for 64-bit Darwin;"
+                    " it is incompatible with the installed C and C++ libraries");
+         rs6000_alignment_flags = MASK_ALIGN_POWER;
+       }
+      else if (! strcmp (arg, "natural"))
+       rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+      else
+       {
+         error ("unknown -malign-XXXXX option specified: '%s'", arg);
+         return false;
+       }
+      break;
+    }
+  return true;
 }
 \f
 /* Do anything needed at the start of the asm file.  */
@@ -1757,6 +1876,12 @@ rs6000_file_start (void)
            }
        }
 
+      if (PPC405_ERRATUM77)
+       {
+         fprintf (file, "%s PPC405CR_ERRATUM77", start);
+         start = "";
+       }
+
 #ifdef USING_ELFOS_H
       switch (rs6000_sdata)
        {
@@ -1848,8 +1973,11 @@ num_insns_constant_wide (HOST_WIDE_INT value)
 int
 num_insns_constant (rtx op, enum machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_INT)
+  HOST_WIDE_INT low, high;
+
+  switch (GET_CODE (op))
     {
+    case CONST_INT:
 #if HOST_BITS_PER_WIDE_INT == 64
       if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
          && mask64_operand (op, mode))
@@ -1857,65 +1985,57 @@ num_insns_constant (rtx op, enum machine_mode mode)
       else
 #endif
        return num_insns_constant_wide (INTVAL (op));
-    }
-
-  else if (GET_CODE (op) == CONST_DOUBLE && mode == SFmode)
-    {
-      long l;
-      REAL_VALUE_TYPE rv;
 
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
-      return num_insns_constant_wide ((HOST_WIDE_INT) l);
-    }
+      case CONST_DOUBLE:
+       if (mode == SFmode)
+         {
+           long l;
+           REAL_VALUE_TYPE rv;
 
-  else if (GET_CODE (op) == CONST_DOUBLE)
-    {
-      HOST_WIDE_INT low;
-      HOST_WIDE_INT high;
-      long l[2];
-      REAL_VALUE_TYPE rv;
-      int endian = (WORDS_BIG_ENDIAN == 0);
+           REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+           REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+           return num_insns_constant_wide ((HOST_WIDE_INT) l);
+         }
 
-      if (mode == VOIDmode || mode == DImode)
-       {
-         high = CONST_DOUBLE_HIGH (op);
-         low  = CONST_DOUBLE_LOW (op);
-       }
-      else
-       {
-         REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-         REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
-         high = l[endian];
-         low  = l[1 - endian];
-       }
+       if (mode == VOIDmode || mode == DImode)
+         {
+           high = CONST_DOUBLE_HIGH (op);
+           low  = CONST_DOUBLE_LOW (op);
+         }
+       else
+         {
+           long l[2];
+           REAL_VALUE_TYPE rv;
 
-      if (TARGET_32BIT)
-       return (num_insns_constant_wide (low)
-               + num_insns_constant_wide (high));
+           REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+           REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+           high = l[WORDS_BIG_ENDIAN == 0];
+           low  = l[WORDS_BIG_ENDIAN != 0];
+         }
 
-      else
-       {
-         if (high == 0 && low >= 0)
-           return num_insns_constant_wide (low);
+       if (TARGET_32BIT)
+         return (num_insns_constant_wide (low)
+                 + num_insns_constant_wide (high));
+       else
+         {
+           if ((high == 0 && low >= 0)
+               || (high == -1 && low < 0))
+             return num_insns_constant_wide (low);
 
-         else if (high == -1 && low < 0)
-           return num_insns_constant_wide (low);
+           else if (mask64_operand (op, mode))
+             return 2;
 
-         else if (mask64_operand (op, mode))
-           return 2;
+           else if (low == 0)
+             return num_insns_constant_wide (high) + 1;
 
-         else if (low == 0)
-           return num_insns_constant_wide (high) + 1;
+           else
+             return (num_insns_constant_wide (high)
+                     + num_insns_constant_wide (low) + 1);
+         }
 
-         else
-           return (num_insns_constant_wide (high)
-                   + num_insns_constant_wide (low) + 1);
-       }
+    default:
+      gcc_unreachable ();
     }
-
-  else
-    abort ();
 }
 
 /* Returns the constant for the splat instruction, if exists.  */
@@ -2005,121 +2125,225 @@ output_vec_const_move (rtx *operands)
     {
       if (zero_constant (vec, mode))
        return "vxor %0,%0,%0";
-      else if (easy_vector_constant (vec, mode))
+
+      gcc_assert (easy_vector_constant (vec, mode));
+
+      operands[1] = GEN_INT (cst);
+      switch (mode)
        {
-         operands[1] = GEN_INT (cst);
-         switch (mode)
+       case V4SImode:
+         if (EASY_VECTOR_15 (cst))
            {
-           case V4SImode:
-             if (EASY_VECTOR_15 (cst))
-               {
-                 operands[1] = GEN_INT (cst);
-                 return "vspltisw %0,%1";
-               }
-             else if (EASY_VECTOR_15_ADD_SELF (cst))
-               return "#";
-             cst = cst >> 16;
-             /* Fall thru */
-
-           case V8HImode:
-             if (EASY_VECTOR_15 (cst))
-               {
-                 operands[1] = GEN_INT (cst);
-                 return "vspltish %0,%1";
-               }
-             else if (EASY_VECTOR_15_ADD_SELF (cst))
-               return "#";
-             cst = cst >> 8;
-             /* Fall thru */
+             operands[1] = GEN_INT (cst);
+             return "vspltisw %0,%1";
+           }
+         else if (EASY_VECTOR_15_ADD_SELF (cst))
+           return "#";
+         cst = cst >> 16;
+         /* Fall thru */
 
-           case V16QImode:
-             if (EASY_VECTOR_15 (cst))
-               {
-                 operands[1] = GEN_INT (cst);
-                 return "vspltisb %0,%1";
-               }
-             else if (EASY_VECTOR_15_ADD_SELF (cst))
-               return "#";
+       case V8HImode:
+         if (EASY_VECTOR_15 (cst))
+           {
+             operands[1] = GEN_INT (cst);
+             return "vspltish %0,%1";
+           }
+         else if (EASY_VECTOR_15_ADD_SELF (cst))
+           return "#";
+         cst = cst >> 8;
+         /* Fall thru */
 
-           default:
-             abort ();
+       case V16QImode:
+         if (EASY_VECTOR_15 (cst))
+           {
+             operands[1] = GEN_INT (cst);
+             return "vspltisb %0,%1";
            }
+         else if (EASY_VECTOR_15_ADD_SELF (cst))
+           return "#";
+
+       default:
+         gcc_unreachable ();
        }
-      else
-       abort ();
     }
 
-  if (TARGET_SPE)
-    {
-      /* Vector constant 0 is handled as a splitter of V2SI, and in the
-        pattern of V1DI, V4HI, and V2SF.
+  gcc_assert (TARGET_SPE);
 
-        FIXME: We should probably return # and add post reload
-        splitters for these, but this way is so easy ;-).  */
-      operands[1] = GEN_INT (cst);
-      operands[2] = GEN_INT (cst2);
-      if (cst == cst2)
-       return "li %0,%1\n\tevmergelo %0,%0,%0";
-      else
-       return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
-    }
+  /* Vector constant 0 is handled as a splitter of V2SI, and in the
+     pattern of V1DI, V4HI, and V2SF.
 
-  abort ();
+     FIXME: We should probably return # and add post reload
+     splitters for these, but this way is so easy ;-).  */
+  operands[1] = GEN_INT (cst);
+  operands[2] = GEN_INT (cst2);
+  if (cst == cst2)
+    return "li %0,%1\n\tevmergelo %0,%0,%0";
+  else
+    return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
 }
 
-int
-mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED,
-                      bool allow_one)
-{
-  if (GET_CODE (op) == CONST_INT)
+/* Initialize vector TARGET to VALS.  */
+
+void
+rs6000_expand_vector_init (rtx target, rtx vals)
+{
+  enum machine_mode mode = GET_MODE (target);
+  enum machine_mode inner_mode = GET_MODE_INNER (mode);
+  int n_elts = GET_MODE_NUNITS (mode);
+  int n_var = 0, one_var = -1;
+  bool all_same = true, all_const_zero = true;
+  rtx x, mem;
+  int i;
+
+  for (i = 0; i < n_elts; ++i)
     {
-      HOST_WIDE_INT c, lsb;
-      bool one_ok;
-      
-      c = INTVAL (op);
+      x = XVECEXP (vals, 0, i);
+      if (!CONSTANT_P (x))
+       ++n_var, one_var = i;
+      else if (x != CONST0_RTX (inner_mode))
+       all_const_zero = false;
 
-      /* Disallow all zeros.  */
-      if (c == 0)
-       return 0;
+      if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
+       all_same = false;
+    }
 
-      /* We can use a single rlwinm insn if no upper bits of C are set
-         AND there are zero, one or two transitions in the _whole_ of
-         C.  */
-      one_ok = !(c & ~(HOST_WIDE_INT)0xffffffff);
-      
-      /* 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 first transition.  */
-      lsb = c & -c;
+  if (n_var == 0)
+    {
+      if (mode != V4SFmode && all_const_zero)
+       {
+         /* Zero register.  */
+         emit_insn (gen_rtx_SET (VOIDmode, target,
+                                 gen_rtx_XOR (mode, target, target)));
+         return;
+       }
+      else if (mode != V4SFmode && easy_vector_same (vals, mode))
+       {
+         /* Splat immediate.  */
+         x = gen_rtx_VEC_DUPLICATE (mode, CONST_VECTOR_ELT (vals, 0));
+         emit_insn (gen_rtx_SET (VOIDmode, target, x));
+         return;
+       }
+      else if (all_same)
+       ;       /* Splat vector element.  */
+      else
+       {
+         /* Load from constant pool.  */
+         emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+         return;
+       }
+    }
 
-      /* Invert to look for a second transition.  */
-      c = ~c;
+  /* Store value to stack temp.  Load vector element.  Splat.  */
+  if (all_same)
+    {
+      mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+      emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
+                     XVECEXP (vals, 0, 0));
+      x = gen_rtx_UNSPEC (VOIDmode,
+                         gen_rtvec (1, const0_rtx), UNSPEC_LVE);
+      emit_insn (gen_rtx_PARALLEL (VOIDmode,
+                                  gen_rtvec (2,
+                                             gen_rtx_SET (VOIDmode,
+                                                          target, mem),
+                                             x)));
+      x = gen_rtx_VEC_SELECT (inner_mode, target,
+                             gen_rtx_PARALLEL (VOIDmode,
+                                               gen_rtvec (1, const0_rtx)));
+      emit_insn (gen_rtx_SET (VOIDmode, target,
+                             gen_rtx_VEC_DUPLICATE (mode, x)));
+      return;
+    }
 
-      /* Erase first transition.  */
-      c &= -lsb;
+  /* One field is non-constant.  Load constant then overwrite
+     varying field.  */
+  if (n_var == 1)
+    {
+      rtx copy = copy_rtx (vals);
 
-      /* Find the second transition.  */
-      lsb = c & -c;
+      /* Load constant part of vector, substitute neighboring value for
+        varying element.  */
+      XVECEXP (copy, 0, one_var) = XVECEXP (vals, 0, (one_var + 1) % n_elts);
+      rs6000_expand_vector_init (target, copy);
 
-      /* Invert to look for a third transition.  */
-      c = ~c;
+      /* Insert variable.  */
+      rs6000_expand_vector_set (target, XVECEXP (vals, 0, one_var), one_var);
+      return;
+    }
 
-      /* Erase second transition.  */
-      c &= -lsb;
+  /* Construct the vector in memory one field at a time
+     and load the whole vector.  */
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+  for (i = 0; i < n_elts; i++)
+    emit_move_insn (adjust_address_nv (mem, inner_mode,
+                                   i * GET_MODE_SIZE (inner_mode)),
+                   XVECEXP (vals, 0, i));
+  emit_move_insn (target, mem);
+}
 
-      if (one_ok && !(allow_one || c))
-       return 0;
+/* Set field ELT of TARGET to VAL.  */
 
-      /* Find the third transition (if any).  */
-      lsb = c & -c;
+void
+rs6000_expand_vector_set (rtx target, rtx val, int elt)
+{
+  enum machine_mode mode = GET_MODE (target);
+  enum machine_mode inner_mode = GET_MODE_INNER (mode);
+  rtx reg = gen_reg_rtx (mode);
+  rtx mask, mem, x;
+  int width = GET_MODE_SIZE (inner_mode);
+  int i;
 
-      /* Match if all the bits above are 1's (or c is zero).  */
-      return c == -lsb;
-    }
-  return 0;
+  /* Load single variable value.  */
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+  emit_move_insn (adjust_address_nv (mem, inner_mode, 0), val);
+  x = gen_rtx_UNSPEC (VOIDmode,
+                     gen_rtvec (1, const0_rtx), UNSPEC_LVE);
+  emit_insn (gen_rtx_PARALLEL (VOIDmode,
+                              gen_rtvec (2,
+                                         gen_rtx_SET (VOIDmode,
+                                                      reg, mem),
+                                         x)));
+
+  /* Linear sequence.  */
+  mask = gen_rtx_PARALLEL (V16QImode, rtvec_alloc (16));
+  for (i = 0; i < 16; ++i)
+    XVECEXP (mask, 0, i) = GEN_INT (i);
+
+  /* Set permute mask to insert element into target.  */
+  for (i = 0; i < width; ++i)
+    XVECEXP (mask, 0, elt*width + i)
+      = GEN_INT (i + 0x10);
+  x = gen_rtx_CONST_VECTOR (V16QImode, XVEC (mask, 0));
+  x = gen_rtx_UNSPEC (mode,
+                     gen_rtvec (3, target, reg,
+                                force_reg (V16QImode, x)),
+                     UNSPEC_VPERM);
+  emit_insn (gen_rtx_SET (VOIDmode, target, x));
+}
+
+/* Extract field ELT from VEC into TARGET.  */
+
+void
+rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
+{
+  enum machine_mode mode = GET_MODE (vec);
+  enum machine_mode inner_mode = GET_MODE_INNER (mode);
+  rtx mem, x;
+
+  /* Allocate mode-sized buffer.  */
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+
+  /* Add offset to field within buffer matching vector element.  */
+  mem = adjust_address_nv (mem, mode, elt * GET_MODE_SIZE (inner_mode));
+
+  /* Store single field into mode-sized buffer.  */
+  x = gen_rtx_UNSPEC (VOIDmode,
+                     gen_rtvec (1, const0_rtx), UNSPEC_STVE);
+  emit_insn (gen_rtx_PARALLEL (VOIDmode,
+                              gen_rtvec (2,
+                                         gen_rtx_SET (VOIDmode,
+                                                      mem, vec),
+                                         x)));
+  emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
 }
 
 /* Generates shifts and masks for a pair of rldicl or rldicr insns to
@@ -2131,8 +2355,7 @@ build_mask64_2_operands (rtx in, rtx *out)
   unsigned HOST_WIDE_INT c, lsb, m1, m2;
   int shift;
 
-  if (GET_CODE (in) != CONST_INT)
-    abort ();
+  gcc_assert (GET_CODE (in) == CONST_INT);
 
   c = INTVAL (in);
   if (c & 1)
@@ -2188,7 +2411,7 @@ build_mask64_2_operands (rtx in, rtx *out)
 #else
   (void)in;
   (void)out;
-  abort ();
+  gcc_unreachable ();
 #endif
 }
 
@@ -2222,7 +2445,7 @@ rs6000_special_round_type_align (tree type, int computed, int specified)
 {
   tree field = TYPE_FIELDS (type);
 
-  /* Skip all non field decls */ 
+  /* Skip all non field decls */
   while (field != NULL && TREE_CODE (field) != FIELD_DECL)
     field = TREE_CHAIN (field);
 
@@ -2276,27 +2499,6 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
 #endif
 }
 
-/* Return true, if operand is a memory operand and has a
-   displacement divisible by 4.  */
-
-int
-word_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  rtx addr;
-  int off = 0;
-
-  if (!memory_operand (op, mode))
-    return 0;
-
-  addr = XEXP (op, 0);
-  if (GET_CODE (addr) == PLUS
-      && GET_CODE (XEXP (addr, 0)) == REG
-      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
-    off = INTVAL (XEXP (addr, 1));
-
-  return (off % 4) == 0;
-}
-
 /* Return true if either operand is a general purpose register.  */
 
 bool
@@ -2373,8 +2575,8 @@ legitimate_constant_pool_address_p (rtx x)
          && constant_pool_expr_p (XEXP (x, 1)));
 }
 
-static bool
-legitimate_small_data_p (enum machine_mode mode, rtx x)
+bool
+rs6000_legitimate_small_data_p (enum machine_mode mode, rtx x)
 {
   return (DEFAULT_ABI == ABI_V4
          && !flag_pic && !TARGET_TOC
@@ -2409,10 +2611,10 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     case V8HImode:
     case V4SFmode:
     case V4SImode:
-      /* AltiVec vector modes.  Only reg+reg addressing is valid here,
-        which leaves the only valid constant offset of zero, which by
-        canonicalization rules is also invalid.  */
-      return false;
+      /* AltiVec vector modes.  Only reg+reg addressing is valid and
+        constant offset zero should not occur due to canonicalization.
+        Allow any offset when not strict before reload.  */
+      return !strict;
 
     case V4HImode:
     case V2SImode:
@@ -2676,10 +2878,10 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
     return NULL_RTX;
 }
 
-/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
-void
+static void
 rs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
   switch (size)
@@ -2691,7 +2893,7 @@ rs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
       fputs (DOUBLE_INT_ASM_OP, file);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   output_addr_const (file, x);
   fputs ("@dtprel+0x8000", file);
@@ -2776,8 +2978,13 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
     {
       rtx r3, got, tga, tmp1, tmp2, eqv;
 
+      /* We currently use relocations like @got@tlsgd for tls, which
+        means the linker will handle allocation of tls entries, placing
+        them in the .got section.  So use a pointer to the .got section,
+        not one to secondary TOC sections used by 64-bit -mminimal-toc,
+        or to secondary GOT sections used by 32-bit -fPIC.  */
       if (TARGET_64BIT)
-       got = gen_rtx_REG (Pmode, TOC_REGISTER);
+       got = gen_rtx_REG (Pmode, 2);
       else
        {
          if (flag_pic == 1)
@@ -2790,21 +2997,16 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                rs6000_emit_move (got, gsym, Pmode);
              else
                {
-                 char buf[30];
-                 static int tls_got_labelno = 0;
-                 rtx tempLR, lab, tmp3, mem;
+                 rtx tempLR, tmp3, mem;
                  rtx first, last;
 
-                 ASM_GENERATE_INTERNAL_LABEL (buf, "LTLS", tls_got_labelno++);
-                 lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
                  tempLR = gen_reg_rtx (Pmode);
                  tmp1 = gen_reg_rtx (Pmode);
                  tmp2 = gen_reg_rtx (Pmode);
                  tmp3 = gen_reg_rtx (Pmode);
                  mem = gen_const_mem (Pmode, tmp1);
 
-                 first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
-                                                            gsym));
+                 first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
                  emit_move_insn (tmp1, tempLR);
                  emit_move_insn (tmp2, mem);
                  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
@@ -3048,16 +3250,21 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       return x;
     }
 
-#if TARGET_MACHO
   if (GET_CODE (x) == SYMBOL_REF
+      && !ALTIVEC_VECTOR_MODE (mode)
+#if TARGET_MACHO
       && DEFAULT_ABI == ABI_DARWIN
-      && !ALTIVEC_VECTOR_MODE (mode)
       && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
+#else
+      && DEFAULT_ABI == ABI_V4
+      && !flag_pic
+#endif
       /* Don't do this for TFmode, since the result isn't offsettable.
         The same goes for DImode without 64-bit gprs.  */
       && mode != TFmode
       && (mode != DImode || TARGET_POWERPC64))
     {
+#if TARGET_MACHO
       if (flag_pic)
        {
          rtx offset = gen_rtx_CONST (Pmode,
@@ -3068,6 +3275,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
                  gen_rtx_HIGH (Pmode, offset)), offset);
        }
       else
+#endif
        x = gen_rtx_LO_SUM (GET_MODE (x),
              gen_rtx_HIGH (Pmode, x), x);
 
@@ -3077,7 +3285,23 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       *win = 1;
       return x;
     }
-#endif
+
+  /* Reload an offset address wrapped by an AND that represents the
+     masking of the lower bits.  Strip the outer AND and let reload
+     convert the offset address into an indirect address.  */
+  if (TARGET_ALTIVEC
+      && ALTIVEC_VECTOR_MODE (mode)
+      && GET_CODE (x) == AND
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && INTVAL (XEXP (x, 1)) == -16)
+    {
+      x = XEXP (x, 0);
+      *win = 1;
+      return x;
+    }
 
   if (TARGET_TOC
       && constant_pool_expr_p (x)
@@ -3131,7 +3355,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
-  if (legitimate_small_data_p (mode, x))
+  if (rs6000_legitimate_small_data_p (mode, x))
     return 1;
   if (legitimate_constant_pool_address_p (x))
     return 1;
@@ -3239,7 +3463,7 @@ rs6000_conditional_register_usage (void)
   if (! TARGET_POWER)
     fixed_regs[64] = 1;
 
-  /* 64-bit AIX reserves GPR13 for thread-private data.  */
+  /* 64-bit AIX and Linux reserve GPR13 for thread-private data.  */
   if (TARGET_64BIT)
     fixed_regs[13] = call_used_regs[13]
       = call_really_used_regs[13] = 1;
@@ -3250,6 +3474,11 @@ rs6000_conditional_register_usage (void)
       fixed_regs[i] = call_used_regs[i]
        = call_really_used_regs[i] = 1;
 
+  /* The TOC register is not killed across calls in a way that is
+     visible to the compiler.  */
+  if (DEFAULT_ABI == ABI_AIX)
+    call_really_used_regs[2] = 0;
+
   if (DEFAULT_ABI == ABI_V4
       && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
       && flag_pic == 2)
@@ -3264,8 +3493,7 @@ rs6000_conditional_register_usage (void)
 
   if (DEFAULT_ABI == ABI_DARWIN
       && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
-    global_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
-      = fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
+      fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
       = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
       = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
 
@@ -3309,15 +3537,16 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
   rtx result, insn, set;
   HOST_WIDE_INT c0, c1;
 
-  if (mode == QImode || mode == HImode)
+  switch (mode)
     {
+      case  QImode:
+    case HImode:
       if (dest == NULL)
        dest = gen_reg_rtx (mode);
       emit_insn (gen_rtx_SET (VOIDmode, dest, source));
       return dest;
-    }
-  else if (mode == SImode)
-    {
+
+    case SImode:
       result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
 
       emit_insn (gen_rtx_SET (VOIDmode, result,
@@ -3327,16 +3556,17 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
                              gen_rtx_IOR (SImode, result,
                                           GEN_INT (INTVAL (source) & 0xffff))));
       result = dest;
-    }
-  else if (mode == DImode)
-    {
-      if (GET_CODE (source) == CONST_INT)
+      break;
+
+    case DImode:
+      switch (GET_CODE (source))
        {
+       case CONST_INT:
          c0 = INTVAL (source);
          c1 = -(c0 < 0);
-       }
-      else if (GET_CODE (source) == CONST_DOUBLE)
-       {
+         break;
+
+       case CONST_DOUBLE:
 #if HOST_BITS_PER_WIDE_INT >= 64
          c0 = CONST_DOUBLE_LOW (source);
          c1 = -(c0 < 0);
@@ -3344,14 +3574,18 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
          c0 = CONST_DOUBLE_LOW (source);
          c1 = CONST_DOUBLE_HIGH (source);
 #endif
+         break;
+
+       default:
+         gcc_unreachable ();
        }
-      else
-       abort ();
 
       result = rs6000_emit_set_long_const (dest, c0, c1);
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  else
-    abort ();
 
   insn = get_last_insn ();
   set = single_set (insn);
@@ -3489,13 +3723,12 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
         to a CONST_INT.  */
       operands[1] = gen_int_mode (CONST_DOUBLE_LOW (operands[1]), mode);
     }
-  if (GET_CODE (operands[1]) == CONST_DOUBLE
-      && ! FLOAT_MODE_P (mode)
-      && ((CONST_DOUBLE_HIGH (operands[1]) == 0
-          && CONST_DOUBLE_LOW (operands[1]) >= 0)
-         || (CONST_DOUBLE_HIGH (operands[1]) == -1
-             && CONST_DOUBLE_LOW (operands[1]) < 0)))
-    abort ();
+  gcc_assert (GET_CODE (operands[1]) != CONST_DOUBLE
+             || FLOAT_MODE_P (mode)
+             || ((CONST_DOUBLE_HIGH (operands[1]) != 0
+                  || CONST_DOUBLE_LOW (operands[1]) < 0)
+                 && (CONST_DOUBLE_HIGH (operands[1]) != -1
+                     || CONST_DOUBLE_LOW (operands[1]) >= 0)));
 
   /* Check if GCC is setting up a block move that will end up using FP
      registers as temporaries.  We must make sure this is acceptable.  */
@@ -3550,11 +3783,29 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 
   /* Recognize the case where operand[1] is a reference to thread-local
      data and load its address to a register.  */
-  if (GET_CODE (operands[1]) == SYMBOL_REF)
+  if (rs6000_tls_referenced_p (operands[1]))
     {
-      enum tls_model model = SYMBOL_REF_TLS_MODEL (operands[1]);
-      if (model != 0)
-       operands[1] = rs6000_legitimize_tls_address (operands[1], model);
+      enum tls_model model;
+      rtx tmp = operands[1];
+      rtx addend = NULL;
+
+      if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+       {
+          addend = XEXP (XEXP (tmp, 0), 1);
+         tmp = XEXP (XEXP (tmp, 0), 0);
+       }
+
+      gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+      model = SYMBOL_REF_TLS_MODEL (tmp);
+      gcc_assert (model != 0);
+
+      tmp = rs6000_legitimize_tls_address (tmp, model);
+      if (addend)
+       {
+         tmp = gen_rtx_PLUS (mode, tmp, addend);
+         tmp = force_operand (tmp, operands[0]);
+       }
+      operands[1] = tmp;
     }
 
   /* Handle the case where reload calls us with an invalid address.  */
@@ -3794,7 +4045,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* Above, we may have called force_const_mem which may have returned
@@ -3829,7 +4080,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
    returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
    specifies that structures <= 8 bytes are returned in r3/r4, but a
    draft put them in memory, and GCC used to implement the draft
-   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
+   instead of the final standard.  Therefore, aix_struct_return
    controls this instead of DEFAULT_ABI; V.4 targets needing backward
    compatibility can change DRAFT_V4_STRUCT_RET to override the
    default, and -m switches get the final word.  See
@@ -3865,7 +4116,7 @@ rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
     }
 
   if (AGGREGATE_TYPE_P (type)
-      && (TARGET_AIX_STRUCT_RET
+      && (aix_struct_return
          || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
     return true;
 
@@ -3882,7 +4133,7 @@ rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
       static bool warned_for_return_big_vectors = false;
       if (!warned_for_return_big_vectors)
        {
-         warning ("GCC vector returned by reference: "
+         warning (0, "GCC vector returned by reference: "
                   "non-standard ABI extension with no compatibility guarantee");
          warned_for_return_big_vectors = true;
        }
@@ -3955,9 +4206,9 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
       && TARGET_ALTIVEC_ABI
       && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
     {
-      error ("Cannot return value in vector register because"
+      error ("cannot return value in vector register because"
             " altivec instructions are disabled, use -maltivec"
-            " to enable them.");
+            " to enable them");
     }
 }
 \f
@@ -4060,6 +4311,20 @@ function_arg_boundary (enum machine_mode mode, tree type)
     return PARM_BOUNDARY;
 }
 
+/* For a function parm of MODE and TYPE, return the starting word in
+   the parameter area.  NWORDS of the parameter area are already used.  */
+
+static unsigned int
+rs6000_parm_start (enum machine_mode mode, tree type, unsigned int nwords)
+{
+  unsigned int align;
+  unsigned int parm_offset;
+
+  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+  parm_offset = DEFAULT_ABI == ABI_V4 ? 2 : 6;
+  return nwords + (-(parm_offset + nwords) & align);
+}
+
 /* Compute the size (in words) of a function argument.  */
 
 static unsigned long
@@ -4187,9 +4452,9 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        {
          cum->vregno++;
          if (!TARGET_ALTIVEC)
-           error ("Cannot pass argument in vector register because"
+           error ("cannot pass argument in vector register because"
                   " altivec instructions are disabled, use -maltivec"
-                  " to enable them.");
+                  " to enable them");
 
          /* PowerPC64 Linux and AIX allocate GPRs for a vector argument
             even if it is going to be passed in a vector register.
@@ -4255,7 +4520,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
             grovel through the fields for these too.  */
          cum->intoffset = 0;
          rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
-         rs6000_darwin64_record_arg_advance_flush (cum, 
+         rs6000_darwin64_record_arg_advance_flush (cum,
                                                    size * BITS_PER_UNIT);
        }
     }
@@ -4314,15 +4579,10 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else
     {
       int n_words = rs6000_arg_size (mode, type);
-      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+      int start_words = cum->words;
+      int align_words = rs6000_parm_start (mode, type, start_words);
 
-      /* The simple alignment calculation here works because
-        function_arg_boundary / PARM_BOUNDARY will only be 1 or 2.
-        If we ever want to handle alignments larger than 8 bytes for
-        32-bit or 16 bytes for 64-bit, then we'll need to take into
-        account the offset to the start of the parm save area.  */
-      align &= cum->words;
-      cum->words += align + n_words;
+      cum->words = align_words + n_words;
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT
          && TARGET_HARD_FLOAT && TARGET_FPRS)
@@ -4335,7 +4595,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
                   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
          fprintf (stderr, "named = %d, align = %d, depth = %d\n",
-                  named, align, depth);
+                  named, align_words - start_words, depth);
        }
     }
 }
@@ -4345,22 +4605,23 @@ spe_build_register_parallel (enum machine_mode mode, int gregno)
 {
   rtx r1, r3;
 
-  if (mode == DFmode)
+  switch (mode)
     {
+    case DFmode:
       r1 = gen_rtx_REG (DImode, gregno);
       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
       return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
-    }
-  else if (mode == DCmode)
-    {
+
+    case DCmode:
       r1 = gen_rtx_REG (DImode, gregno);
       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
       r3 = gen_rtx_REG (DImode, gregno + 2);
       r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
       return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
+
+    default:
+      gcc_unreachable ();
     }
-  abort ();
-  return NULL_RTX;
 }
 
 /* Determine where to put a SIMD argument on the SPE.  */
@@ -4421,7 +4682,7 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    structure between cum->intoffset and bitpos to integer registers.  */
 
 static void
-rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum, 
+rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
                                  HOST_WIDE_INT bitpos, rtx rvec[], int *k)
 {
   enum machine_mode mode;
@@ -4465,7 +4726,7 @@ rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
 
   if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno)
     cum->use_stack = 1;
-    
+
   intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno);
   if (intregs <= 0)
     return;
@@ -4489,7 +4750,7 @@ rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
 /* Recursive workhorse for the following.  */
 
 static void
-rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type, 
+rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
                                    HOST_WIDE_INT startbitpos, rtx rvec[],
                                    int *k)
 {
@@ -4523,7 +4784,7 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
 #endif
            rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
            rvec[(*k)++]
-             = gen_rtx_EXPR_LIST (VOIDmode, 
+             = gen_rtx_EXPR_LIST (VOIDmode,
                                   gen_rtx_REG (mode, cum->fregno++),
                                   GEN_INT (bitpos / BITS_PER_UNIT));
            if (mode == TFmode)
@@ -4533,8 +4794,8 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
          {
            rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
            rvec[(*k)++]
-             = gen_rtx_EXPR_LIST (VOIDmode, 
-                                  gen_rtx_REG (mode, cum->vregno++), 
+             = gen_rtx_EXPR_LIST (VOIDmode,
+                                  gen_rtx_REG (mode, cum->vregno++),
                                   GEN_INT (bitpos / BITS_PER_UNIT));
          }
        else if (cum->intoffset == -1)
@@ -4547,12 +4808,12 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
    being passed by value, along with the offset of where the
    register's value may be found in the block.  FP fields go in FP
    register, vector fields go in vector registers, and everything
-   else goes in int registers, packed as in memory.  
+   else goes in int registers, packed as in memory.
 
    This code is also used for function return values.  RETVAL indicates
    whether this is the case.
 
-   Much of this is taken from the Sparc V9 port, which has a similar
+   Much of this is taken from the SPARC V9 port, which has a similar
    calling convention.  */
 
 static rtx
@@ -4690,9 +4951,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (mode == VOIDmode)
     {
       if (abi == ABI_V4
-         && cum->nargs_prototype < 0
          && (cum->call_cookie & CALL_LIBCALL) == 0
-         && (cum->prototype || TARGET_NO_PROTOTYPE))
+         && (cum->stdarg
+             || (cum->nargs_prototype < 0
+                 && (cum->prototype || TARGET_NO_PROTOTYPE))))
        {
          /* For the SPE, we need to crxor CR6 always.  */
          if (TARGET_SPE_ABI)
@@ -4826,8 +5088,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
   else
     {
-      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
-      int align_words = cum->words + (cum->words & align);
+      int align_words = rs6000_parm_start (mode, type, cum->words);
 
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
@@ -4842,8 +5103,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            {
              /* Currently, we only ever need one reg here because complex
                 doubles are split.  */
-             if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
-               abort ();
+             gcc_assert (cum->fregno == FP_ARG_MAX_REG && fmode == TFmode);
 
              /* Long double split over regs and memory.  */
              fmode = DFmode;
@@ -4930,18 +5190,16 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 }
 \f
 /* For an arg passed partly in registers and partly in memory, this is
-   the number of registers used.  For args passed entirely in registers
-   or entirely in memory, zero.  When an arg is described by a PARALLEL,
-   perhaps using more than one register type, this function returns the
-   number of bytes of registers used by the PARALLEL.  */
+   the number of bytes passed in registers.  For args passed entirely in
+   registers or entirely in memory, zero.  When an arg is described by a
+   PARALLEL, perhaps using more than one register type, this function
+   returns the number of bytes used by the first element of the PARALLEL.  */
 
 static int
 rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                          tree type, bool named)
 {
   int ret = 0;
-  int align;
-  int parm_offset;
   int align_words;
 
   if (DEFAULT_ABI == ABI_V4)
@@ -4957,14 +5215,13 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && int_size_in_bytes (type) > 0)
     return 0;
 
-  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
-  parm_offset = TARGET_32BIT ? 2 : 0;
-  align_words = cum->words + ((parm_offset - cum->words) & align);
+  align_words = rs6000_parm_start (mode, type, cum->words);
 
   if (USE_FP_FOR_ARG_P (cum, mode, type)
-      /* If we are passing this arg in gprs as well, then this function
-        should return the number of gprs (or memory) partially passed,
-        *not* the number of fprs.  */
+      /* If we are passing this arg in the fixed parameter save area
+        (gprs or memory) as well as fprs, then this function should
+        return the number of bytes passed in the parameter save area
+        rather than bytes passed in fprs.  */
       && !(type
           && (cum->nargs_prototype <= 0
               || (DEFAULT_ABI == ABI_AIX
@@ -4972,16 +5229,14 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                   && align_words >= GP_ARG_NUM_REG))))
     {
       if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
-       ret = FP_ARG_MAX_REG + 1 - cum->fregno;
+       ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
       else if (cum->nargs_prototype >= 0)
        return 0;
     }
 
   if (align_words < GP_ARG_NUM_REG
       && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
-    ret = GP_ARG_NUM_REG - align_words;
-
-  ret *= (TARGET_32BIT ? 4 : 8);
+    ret = (GP_ARG_NUM_REG - align_words) * (TARGET_32BIT ? 4 : 8);
 
   if (ret != 0 && TARGET_DEBUG_ARG)
     fprintf (stderr, "rs6000_arg_partial_bytes: %d\n", ret);
@@ -5050,7 +5305,7 @@ rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
        fprintf (stderr, "function_arg_pass_by_reference: synthetic vector\n");
       if (!warned_for_pass_big_vectors)
        {
-         warning ("GCC vector passed by reference: "
+         warning (0, "GCC vector passed by reference: "
                   "non-standard ABI extension with no compatibility guarantee");
          warned_for_pass_big_vectors = true;
        }
@@ -5083,8 +5338,7 @@ rs6000_move_block_from_reg (int regno, rtx x, int nregs)
       else
        tem = replace_equiv_address (tem, XEXP (tem, 0));
 
-      if (tem == NULL_RTX)
-       abort ();
+      gcc_assert (tem);
 
       emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
     }
@@ -5120,11 +5374,70 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   if (DEFAULT_ABI == ABI_V4)
     {
+      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
+
       if (! no_rtl)
-       save_area = plus_constant (virtual_stack_vars_rtx,
-                                  - RS6000_VARARGS_SIZE);
+       {
+         int gpr_reg_num = 0, gpr_size = 0, fpr_size = 0;
+         HOST_WIDE_INT offset = 0;
+
+         /* Try to optimize the size of the varargs save area.
+            The ABI requires that ap.reg_save_area is doubleword
+            aligned, but we don't need to allocate space for all
+            the bytes, only those to which we actually will save
+            anything.  */
+         if (cfun->va_list_gpr_size && first_reg_offset < GP_ARG_NUM_REG)
+           gpr_reg_num = GP_ARG_NUM_REG - first_reg_offset;
+         if (TARGET_HARD_FLOAT && TARGET_FPRS
+             && next_cum.fregno <= FP_ARG_V4_MAX_REG
+             && cfun->va_list_fpr_size)
+           {
+             if (gpr_reg_num)
+               fpr_size = (next_cum.fregno - FP_ARG_MIN_REG)
+                          * UNITS_PER_FP_WORD;
+             if (cfun->va_list_fpr_size
+                 < FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
+               fpr_size += cfun->va_list_fpr_size * UNITS_PER_FP_WORD;
+             else
+               fpr_size += (FP_ARG_V4_MAX_REG + 1 - next_cum.fregno)
+                           * UNITS_PER_FP_WORD;
+           }
+         if (gpr_reg_num)
+           {
+             offset = -((first_reg_offset * reg_size) & ~7);
+             if (!fpr_size && gpr_reg_num > cfun->va_list_gpr_size)
+               {
+                 gpr_reg_num = cfun->va_list_gpr_size;
+                 if (reg_size == 4 && (first_reg_offset & 1))
+                   gpr_reg_num++;
+               }
+             gpr_size = (gpr_reg_num * reg_size + 7) & ~7;
+           }
+         else if (fpr_size)
+           offset = - (int) (next_cum.fregno - FP_ARG_MIN_REG)
+                      * UNITS_PER_FP_WORD
+                    - (int) (GP_ARG_NUM_REG * reg_size);
 
-      first_reg_offset = next_cum.sysv_gregno - GP_ARG_MIN_REG;
+         if (gpr_size + fpr_size)
+           {
+             rtx reg_save_area
+               = assign_stack_local (BLKmode, gpr_size + fpr_size, 64);
+             gcc_assert (GET_CODE (reg_save_area) == MEM);
+             reg_save_area = XEXP (reg_save_area, 0);
+             if (GET_CODE (reg_save_area) == PLUS)
+               {
+                 gcc_assert (XEXP (reg_save_area, 0)
+                             == virtual_stack_vars_rtx);
+                 gcc_assert (GET_CODE (XEXP (reg_save_area, 1)) == CONST_INT);
+                 offset += INTVAL (XEXP (reg_save_area, 1));
+               }
+             else
+               gcc_assert (reg_save_area == virtual_stack_vars_rtx);
+           }
+
+         cfun->machine->varargs_save_offset = offset;
+         save_area = plus_constant (virtual_stack_vars_rtx, offset);
+       }
     }
   else
     {
@@ -5136,28 +5449,47 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
 
   set = get_varargs_alias_set ();
-  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG)
+  if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG
+      && cfun->va_list_gpr_size)
     {
+      int nregs = GP_ARG_NUM_REG - first_reg_offset;
+
+      if (va_list_gpr_counter_field)
+       {
+         /* V4 va_list_gpr_size counts number of registers needed.  */
+         if (nregs > cfun->va_list_gpr_size)
+           nregs = cfun->va_list_gpr_size;
+       }
+      else
+       {
+         /* char * va_list instead counts number of bytes needed.  */
+         if (nregs > cfun->va_list_gpr_size / reg_size)
+           nregs = cfun->va_list_gpr_size / reg_size;
+       }
+
       mem = gen_rtx_MEM (BLKmode,
                         plus_constant (save_area,
-                                       first_reg_offset * reg_size)),
+                                       first_reg_offset * reg_size));
+      MEM_NOTRAP_P (mem) = 1;
       set_mem_alias_set (mem, set);
       set_mem_align (mem, BITS_PER_WORD);
 
       rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
-                                 GP_ARG_NUM_REG - first_reg_offset);
+                                 nregs);
     }
 
   /* Save FP registers if needed.  */
   if (DEFAULT_ABI == ABI_V4
       && TARGET_HARD_FLOAT && TARGET_FPRS
       && ! no_rtl
-      && next_cum.fregno <= FP_ARG_V4_MAX_REG)
+      && next_cum.fregno <= FP_ARG_V4_MAX_REG
+      && cfun->va_list_fpr_size)
     {
-      int fregno = next_cum.fregno;
+      int fregno = next_cum.fregno, nregs;
       rtx cr1 = gen_rtx_REG (CCmode, CR1_REGNO);
       rtx lab = gen_label_rtx ();
-      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
+      int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG)
+                                              * UNITS_PER_FP_WORD);
 
       emit_jump_insn
        (gen_rtx_SET (VOIDmode,
@@ -5168,14 +5500,15 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                                            gen_rtx_LABEL_REF (VOIDmode, lab),
                                            pc_rtx)));
 
-      while (fregno <= FP_ARG_V4_MAX_REG)
+      for (nregs = 0;
+          fregno <= FP_ARG_V4_MAX_REG && nregs < cfun->va_list_fpr_size;
+          fregno++, off += UNITS_PER_FP_WORD, nregs++)
        {
          mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
+         MEM_NOTRAP_P (mem) = 1;
          set_mem_alias_set (mem, set);
          set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
          emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
-         fregno++;
-         off += 8;
        }
 
       emit_label (lab);
@@ -5210,6 +5543,9 @@ rs6000_build_builtin_va_list (void)
   f_sav = build_decl (FIELD_DECL, get_identifier ("reg_save_area"),
                      ptr_type_node);
 
+  va_list_gpr_counter_field = f_gpr;
+  va_list_fpr_counter_field = f_fpr;
+
   DECL_FIELD_CONTEXT (f_gpr) = record;
   DECL_FIELD_CONTEXT (f_fpr) = record;
   DECL_FIELD_CONTEXT (f_res) = record;
@@ -5270,15 +5606,21 @@ rs6000_va_start (tree valist, rtx nextarg)
             HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
             words, n_gpr, n_fpr);
 
-  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
-            build_int_cst (NULL_TREE, n_gpr));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (cfun->va_list_gpr_size)
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+                build_int_cst (NULL_TREE, n_gpr));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
-  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
-            build_int_cst (NULL_TREE, n_fpr));
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+  if (cfun->va_list_fpr_size)
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+                build_int_cst (NULL_TREE, n_fpr));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 
   /* Find the overflow area.  */
   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
@@ -5289,10 +5631,19 @@ rs6000_va_start (tree valist, rtx nextarg)
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
+  /* If there were no va_arg invocations, don't set up the register
+     save area.  */
+  if (!cfun->va_list_gpr_size
+      && !cfun->va_list_fpr_size
+      && n_gpr < GP_ARG_NUM_REG
+      && n_fpr < FP_ARG_V4_MAX_REG)
+    return;
+
   /* Find the register save area.  */
   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
-  t = build (PLUS_EXPR, TREE_TYPE (sav), t,
-            build_int_cst (NULL_TREE, -RS6000_VARARGS_SIZE));
+  if (cfun->machine->varargs_save_offset)
+    t = build (PLUS_EXPR, TREE_TYPE (sav), t,
+              build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset));
   t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -5473,12 +5824,19 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 
 /* Builtins.  */
 
-#define def_builtin(MASK, NAME, TYPE, CODE)                            \
-do {                                                                   \
-  if ((MASK) & target_flags)                                           \
-    lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,  \
-                                NULL, NULL_TREE);                      \
-} while (0)
+static void
+def_builtin (int mask, const char *name, tree type, int code)
+{
+  if (mask & target_flags)
+    {
+      if (rs6000_builtin_decls[code])
+       abort ();
+
+      rs6000_builtin_decls[code] =
+        lang_hooks.builtin_function (name, type, code, BUILT_IN_MD,
+                                    NULL, NULL_TREE);
+    }
+}
 
 /* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
 
@@ -5507,6 +5865,22 @@ static const struct builtin_description bdesc_3arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
+
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madd", ALTIVEC_BUILTIN_VEC_MADD },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_madds", ALTIVEC_BUILTIN_VEC_MADDS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mladd", ALTIVEC_BUILTIN_VEC_MLADD },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mradds", ALTIVEC_BUILTIN_VEC_MRADDS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msum", ALTIVEC_BUILTIN_VEC_MSUM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshm", ALTIVEC_BUILTIN_VEC_VMSUMSHM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhm", ALTIVEC_BUILTIN_VEC_VMSUMUHM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsummbm", ALTIVEC_BUILTIN_VEC_VMSUMMBM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumubm", ALTIVEC_BUILTIN_VEC_VMSUMUBM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msums", ALTIVEC_BUILTIN_VEC_MSUMS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumshs", ALTIVEC_BUILTIN_VEC_VMSUMSHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmsumuhs", ALTIVEC_BUILTIN_VEC_VMSUMUHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nmsub", ALTIVEC_BUILTIN_VEC_NMSUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_perm", ALTIVEC_BUILTIN_VEC_PERM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sel", ALTIVEC_BUILTIN_VEC_SEL },
 };
 
 /* DST operations: void foo (void *, const int, const char).  */
@@ -5516,7 +5890,12 @@ static const struct builtin_description bdesc_dst[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_dst, "__builtin_altivec_dst", ALTIVEC_BUILTIN_DST },
   { MASK_ALTIVEC, CODE_FOR_altivec_dstt, "__builtin_altivec_dstt", ALTIVEC_BUILTIN_DSTT },
   { MASK_ALTIVEC, CODE_FOR_altivec_dstst, "__builtin_altivec_dstst", ALTIVEC_BUILTIN_DSTST },
-  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT }
+  { MASK_ALTIVEC, CODE_FOR_altivec_dststt, "__builtin_altivec_dststt", ALTIVEC_BUILTIN_DSTSTT },
+
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dst", ALTIVEC_BUILTIN_VEC_DST },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstt", ALTIVEC_BUILTIN_VEC_DSTT },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dstst", ALTIVEC_BUILTIN_VEC_DSTST },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_dststt", ALTIVEC_BUILTIN_VEC_DSTSTT }
 };
 
 /* Simple binary operations: VECc = foo (VECa, VECb).  */
@@ -5611,12 +5990,12 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsplth, "__builtin_altivec_vsplth", ALTIVEC_BUILTIN_VSPLTH },
   { MASK_ALTIVEC, CODE_FOR_altivec_vspltw, "__builtin_altivec_vspltw", ALTIVEC_BUILTIN_VSPLTW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsrb, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsrh, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsrw, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsrab, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsrah, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsraw, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
+  { MASK_ALTIVEC, CODE_FOR_lshrv16qi3, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
+  { MASK_ALTIVEC, CODE_FOR_lshrv8hi3, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
+  { MASK_ALTIVEC, CODE_FOR_lshrv4si3, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
+  { MASK_ALTIVEC, CODE_FOR_ashrv16qi3, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
+  { MASK_ALTIVEC, CODE_FOR_ashrv8hi3, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
+  { MASK_ALTIVEC, CODE_FOR_ashrv4si3, "__builtin_altivec_vsraw", ALTIVEC_BUILTIN_VSRAW },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsr, "__builtin_altivec_vsr", ALTIVEC_BUILTIN_VSR },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsro, "__builtin_altivec_vsro", ALTIVEC_BUILTIN_VSRO },
   { MASK_ALTIVEC, CODE_FOR_subv16qi3, "__builtin_altivec_vsububm", ALTIVEC_BUILTIN_VSUBUBM },
@@ -5637,6 +6016,134 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
   { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
 
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_add", ALTIVEC_BUILTIN_VEC_ADD },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddfp", ALTIVEC_BUILTIN_VEC_VADDFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduwm", ALTIVEC_BUILTIN_VEC_VADDUWM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhm", ALTIVEC_BUILTIN_VEC_VADDUHM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubm", ALTIVEC_BUILTIN_VEC_VADDUBM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_addc", ALTIVEC_BUILTIN_VEC_ADDC },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_adds", ALTIVEC_BUILTIN_VEC_ADDS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsws", ALTIVEC_BUILTIN_VEC_VADDSWS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduws", ALTIVEC_BUILTIN_VEC_VADDUWS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddshs", ALTIVEC_BUILTIN_VEC_VADDSHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vadduhs", ALTIVEC_BUILTIN_VEC_VADDUHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddsbs", ALTIVEC_BUILTIN_VEC_VADDSBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vaddubs", ALTIVEC_BUILTIN_VEC_VADDUBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_and", ALTIVEC_BUILTIN_VEC_AND },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_andc", ALTIVEC_BUILTIN_VEC_ANDC },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_avg", ALTIVEC_BUILTIN_VEC_AVG },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsw", ALTIVEC_BUILTIN_VEC_VAVGSW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguw", ALTIVEC_BUILTIN_VEC_VAVGUW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsh", ALTIVEC_BUILTIN_VEC_VAVGSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavguh", ALTIVEC_BUILTIN_VEC_VAVGUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgsb", ALTIVEC_BUILTIN_VEC_VAVGSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vavgub", ALTIVEC_BUILTIN_VEC_VAVGUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpb", ALTIVEC_BUILTIN_VEC_CMPB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpeq", ALTIVEC_BUILTIN_VEC_CMPEQ },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpeqfp", ALTIVEC_BUILTIN_VEC_VCMPEQFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequw", ALTIVEC_BUILTIN_VEC_VCMPEQUW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequh", ALTIVEC_BUILTIN_VEC_VCMPEQUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpequb", ALTIVEC_BUILTIN_VEC_VCMPEQUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpge", ALTIVEC_BUILTIN_VEC_CMPGE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmpgt", ALTIVEC_BUILTIN_VEC_CMPGT },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtfp", ALTIVEC_BUILTIN_VEC_VCMPGTFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsw", ALTIVEC_BUILTIN_VEC_VCMPGTSW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuw", ALTIVEC_BUILTIN_VEC_VCMPGTUW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsh", ALTIVEC_BUILTIN_VEC_VCMPGTSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtuh", ALTIVEC_BUILTIN_VEC_VCMPGTUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtsb", ALTIVEC_BUILTIN_VEC_VCMPGTSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vcmpgtub", ALTIVEC_BUILTIN_VEC_VCMPGTUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmple", ALTIVEC_BUILTIN_VEC_CMPLE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_cmplt", ALTIVEC_BUILTIN_VEC_CMPLT },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_max", ALTIVEC_BUILTIN_VEC_MAX },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxfp", ALTIVEC_BUILTIN_VEC_VMAXFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsw", ALTIVEC_BUILTIN_VEC_VMAXSW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuw", ALTIVEC_BUILTIN_VEC_VMAXUW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsh", ALTIVEC_BUILTIN_VEC_VMAXSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxuh", ALTIVEC_BUILTIN_VEC_VMAXUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxsb", ALTIVEC_BUILTIN_VEC_VMAXSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmaxub", ALTIVEC_BUILTIN_VEC_VMAXUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergeh", ALTIVEC_BUILTIN_VEC_MERGEH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghw", ALTIVEC_BUILTIN_VEC_VMRGHW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghh", ALTIVEC_BUILTIN_VEC_VMRGHH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrghb", ALTIVEC_BUILTIN_VEC_VMRGHB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mergel", ALTIVEC_BUILTIN_VEC_MERGEL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglw", ALTIVEC_BUILTIN_VEC_VMRGLW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglh", ALTIVEC_BUILTIN_VEC_VMRGLH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmrglb", ALTIVEC_BUILTIN_VEC_VMRGLB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_min", ALTIVEC_BUILTIN_VEC_MIN },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminfp", ALTIVEC_BUILTIN_VEC_VMINFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsw", ALTIVEC_BUILTIN_VEC_VMINSW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuw", ALTIVEC_BUILTIN_VEC_VMINUW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsh", ALTIVEC_BUILTIN_VEC_VMINSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminuh", ALTIVEC_BUILTIN_VEC_VMINUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminsb", ALTIVEC_BUILTIN_VEC_VMINSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vminub", ALTIVEC_BUILTIN_VEC_VMINUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mule", ALTIVEC_BUILTIN_VEC_MULE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleub", ALTIVEC_BUILTIN_VEC_VMULEUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesb", ALTIVEC_BUILTIN_VEC_VMULESB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuleuh", ALTIVEC_BUILTIN_VEC_VMULEUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulesh", ALTIVEC_BUILTIN_VEC_VMULESH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mulo", ALTIVEC_BUILTIN_VEC_MULO },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosh", ALTIVEC_BUILTIN_VEC_VMULOSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulouh", ALTIVEC_BUILTIN_VEC_VMULOUH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmulosb", ALTIVEC_BUILTIN_VEC_VMULOSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vmuloub", ALTIVEC_BUILTIN_VEC_VMULOUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nor", ALTIVEC_BUILTIN_VEC_NOR },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_or", ALTIVEC_BUILTIN_VEC_OR },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_pack", ALTIVEC_BUILTIN_VEC_PACK },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwum", ALTIVEC_BUILTIN_VEC_VPKUWUM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhum", ALTIVEC_BUILTIN_VEC_VPKUHUM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packpx", ALTIVEC_BUILTIN_VEC_PACKPX },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packs", ALTIVEC_BUILTIN_VEC_PACKS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswss", ALTIVEC_BUILTIN_VEC_VPKSWSS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuwus", ALTIVEC_BUILTIN_VEC_VPKUWUS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshss", ALTIVEC_BUILTIN_VEC_VPKSHSS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkuhus", ALTIVEC_BUILTIN_VEC_VPKUHUS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_packsu", ALTIVEC_BUILTIN_VEC_PACKSU },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkswus", ALTIVEC_BUILTIN_VEC_VPKSWUS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vpkshus", ALTIVEC_BUILTIN_VEC_VPKSHUS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rl", ALTIVEC_BUILTIN_VEC_RL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlw", ALTIVEC_BUILTIN_VEC_VRLW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlh", ALTIVEC_BUILTIN_VEC_VRLH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vrlb", ALTIVEC_BUILTIN_VEC_VRLB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sl", ALTIVEC_BUILTIN_VEC_SL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslw", ALTIVEC_BUILTIN_VEC_VSLW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslh", ALTIVEC_BUILTIN_VEC_VSLH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vslb", ALTIVEC_BUILTIN_VEC_VSLB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sll", ALTIVEC_BUILTIN_VEC_SLL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_slo", ALTIVEC_BUILTIN_VEC_SLO },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sr", ALTIVEC_BUILTIN_VEC_SR },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrw", ALTIVEC_BUILTIN_VEC_VSRW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrh", ALTIVEC_BUILTIN_VEC_VSRH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrb", ALTIVEC_BUILTIN_VEC_VSRB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sra", ALTIVEC_BUILTIN_VEC_SRA },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsraw", ALTIVEC_BUILTIN_VEC_VSRAW },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrah", ALTIVEC_BUILTIN_VEC_VSRAH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsrab", ALTIVEC_BUILTIN_VEC_VSRAB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_srl", ALTIVEC_BUILTIN_VEC_SRL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sro", ALTIVEC_BUILTIN_VEC_SRO },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sub", ALTIVEC_BUILTIN_VEC_SUB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubfp", ALTIVEC_BUILTIN_VEC_VSUBFP },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuwm", ALTIVEC_BUILTIN_VEC_VSUBUWM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhm", ALTIVEC_BUILTIN_VEC_VSUBUHM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububm", ALTIVEC_BUILTIN_VEC_VSUBUBM },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subc", ALTIVEC_BUILTIN_VEC_SUBC },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_subs", ALTIVEC_BUILTIN_VEC_SUBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsws", ALTIVEC_BUILTIN_VEC_VSUBSWS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuws", ALTIVEC_BUILTIN_VEC_VSUBUWS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubshs", ALTIVEC_BUILTIN_VEC_VSUBSHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubuhs", ALTIVEC_BUILTIN_VEC_VSUBUHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsubsbs", ALTIVEC_BUILTIN_VEC_VSUBSBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsububs", ALTIVEC_BUILTIN_VEC_VSUBUBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum4s", ALTIVEC_BUILTIN_VEC_SUM4S },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4shs", ALTIVEC_BUILTIN_VEC_VSUM4SHS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4sbs", ALTIVEC_BUILTIN_VEC_VSUM4SBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vsum4ubs", ALTIVEC_BUILTIN_VEC_VSUM4UBS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sum2s", ALTIVEC_BUILTIN_VEC_SUM2S },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sums", ALTIVEC_BUILTIN_VEC_SUMS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_xor", ALTIVEC_BUILTIN_VEC_XOR },
+
   /* 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 },
@@ -5779,7 +6286,7 @@ static struct builtin_description bdesc_2arg[] =
   { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
 
   /* Place-holder.  Leave as last binary SPE builtin.  */
-  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
+  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR }
 };
 
 /* AltiVec predicates.  */
@@ -5807,7 +6314,11 @@ static const struct builtin_description_predicates bdesc_altivec_preds[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v8hi, "*vcmpequh.", "__builtin_altivec_vcmpequh_p", ALTIVEC_BUILTIN_VCMPEQUH_P },
   { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpequb.", "__builtin_altivec_vcmpequb_p", ALTIVEC_BUILTIN_VCMPEQUB_P },
   { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtsb.", "__builtin_altivec_vcmpgtsb_p", ALTIVEC_BUILTIN_VCMPGTSB_P },
-  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P }
+  { MASK_ALTIVEC, CODE_FOR_altivec_predicate_v16qi, "*vcmpgtub.", "__builtin_altivec_vcmpgtub_p", ALTIVEC_BUILTIN_VCMPGTUB_P },
+
+  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpeq_p", ALTIVEC_BUILTIN_VCMPEQ_P },
+  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpgt_p", ALTIVEC_BUILTIN_VCMPGT_P },
+  { MASK_ALTIVEC, 0, NULL, "__builtin_vec_vcmpge_p", ALTIVEC_BUILTIN_VCMPGE_P }
 };
 
 /* SPE predicates.  */
@@ -5882,6 +6393,26 @@ static struct builtin_description bdesc_1arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
   { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
 
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abs", ALTIVEC_BUILTIN_VEC_ABS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_abss", ALTIVEC_BUILTIN_VEC_ABSS },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_ceil", ALTIVEC_BUILTIN_VEC_CEIL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_expte", ALTIVEC_BUILTIN_VEC_EXPTE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_floor", ALTIVEC_BUILTIN_VEC_FLOOR },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_loge", ALTIVEC_BUILTIN_VEC_LOGE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_mtvscr", ALTIVEC_BUILTIN_VEC_MTVSCR },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_re", ALTIVEC_BUILTIN_VEC_RE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_round", ALTIVEC_BUILTIN_VEC_ROUND },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_rsqrte", ALTIVEC_BUILTIN_VEC_RSQRTE },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_trunc", ALTIVEC_BUILTIN_VEC_TRUNC },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackh", ALTIVEC_BUILTIN_VEC_UNPACKH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsh", ALTIVEC_BUILTIN_VEC_VUPKHSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhpx", ALTIVEC_BUILTIN_VEC_VUPKHPX },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupkhsb", ALTIVEC_BUILTIN_VEC_VUPKHSB },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_unpackl", ALTIVEC_BUILTIN_VEC_UNPACKL },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklpx", ALTIVEC_BUILTIN_VEC_VUPKLPX },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsh", ALTIVEC_BUILTIN_VEC_VUPKLSH },
+  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_vupklsb", ALTIVEC_BUILTIN_VEC_VUPKLSB },
+
   /* 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 },
@@ -5914,7 +6445,7 @@ static struct builtin_description bdesc_1arg[] =
   { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
 
   /* Place-holder.  Leave as last unary SPE builtin.  */
-  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
+  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW }
 };
 
 static rtx
@@ -5942,8 +6473,8 @@ rs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
     {
       /* Only allow 5-bit *signed* literals.  */
       if (GET_CODE (op0) != CONST_INT
-         || INTVAL (op0) > 0x1f
-         || INTVAL (op0) < -0x1f)
+         || INTVAL (op0) > 15
+         || INTVAL (op0) < -16)
        {
          error ("argument 1 must be a 5-bit signed literal");
          return const0_rtx;
@@ -6094,8 +6625,7 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
   else
     cr6_form_int = TREE_INT_CST_LOW (cr6_form);
 
-  if (mode0 != mode1)
-    abort ();
+  gcc_assert (mode0 == mode1);
 
   /* If we have invalid arguments, bail out before generating bad rtl.  */
   if (arg0 == error_mark_node || arg1 == error_mark_node)
@@ -6495,6 +7025,111 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
   return NULL_RTX;
 }
 
+/* Expand vec_init builtin.  */
+static rtx
+altivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
+{
+  enum machine_mode tmode = TYPE_MODE (type);
+  enum machine_mode inner_mode = GET_MODE_INNER (tmode);
+  int i, n_elt = GET_MODE_NUNITS (tmode);
+  rtvec v = rtvec_alloc (n_elt);
+
+  gcc_assert (VECTOR_MODE_P (tmode));
+
+  for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
+    {
+      rtx x = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+      RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
+    }
+
+  gcc_assert (arglist == NULL);
+
+  if (!target || !register_operand (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  rs6000_expand_vector_init (target, gen_rtx_PARALLEL (tmode, v));
+  return target;
+}
+
+/* Return the integer constant in ARG.  Constrain it to be in the range
+   of the subparts of VEC_TYPE; issue an error if not.  */
+
+static int
+get_element_number (tree vec_type, tree arg)
+{
+  unsigned HOST_WIDE_INT elt, max = TYPE_VECTOR_SUBPARTS (vec_type) - 1;
+
+  if (!host_integerp (arg, 1)
+      || (elt = tree_low_cst (arg, 1), elt > max))
+    {
+      error ("selector must be an integer constant in the range 0..%wi", max);
+      return 0;
+    }
+
+  return elt;
+}
+
+/* Expand vec_set builtin.  */
+static rtx
+altivec_expand_vec_set_builtin (tree arglist)
+{
+  enum machine_mode tmode, mode1;
+  tree arg0, arg1, arg2;
+  int elt;
+  rtx op0, op1;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+
+  tmode = TYPE_MODE (TREE_TYPE (arg0));
+  mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
+  gcc_assert (VECTOR_MODE_P (tmode));
+
+  op0 = expand_expr (arg0, NULL_RTX, tmode, 0);
+  op1 = expand_expr (arg1, NULL_RTX, mode1, 0);
+  elt = get_element_number (TREE_TYPE (arg0), arg2);
+
+  if (GET_MODE (op1) != mode1 && GET_MODE (op1) != VOIDmode)
+    op1 = convert_modes (mode1, GET_MODE (op1), op1, true);
+
+  op0 = force_reg (tmode, op0);
+  op1 = force_reg (mode1, op1);
+
+  rs6000_expand_vector_set (op0, op1, elt);
+
+  return op0;
+}
+
+/* Expand vec_ext builtin.  */
+static rtx
+altivec_expand_vec_ext_builtin (tree arglist, rtx target)
+{
+  enum machine_mode tmode, mode0;
+  tree arg0, arg1;
+  int elt;
+  rtx op0;
+
+  arg0 = TREE_VALUE (arglist);
+  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+
+  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  elt = get_element_number (TREE_TYPE (arg0), arg1);
+
+  tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
+  mode0 = TYPE_MODE (TREE_TYPE (arg0));
+  gcc_assert (VECTOR_MODE_P (mode0));
+
+  op0 = force_reg (mode0, op0);
+
+  if (optimize || !target || !register_operand (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  rs6000_expand_vector_extract (target, op0, elt);
+
+  return target;
+}
+
 /* Expand the builtin in EXP and store the result in TARGET.  Store
    true in *EXPANDEDP if we found a builtin to expand.  */
 static rtx
@@ -6511,6 +7146,14 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   enum machine_mode tmode, mode0;
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
 
+  if (fcode >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
+      && fcode <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
+    {
+      *expandedp = true;
+      error ("unresolved overload for Altivec builtin %qF", fndecl);
+      return const0_rtx;
+    }
+
   target = altivec_expand_ld_builtin (exp, target, expandedp);
   if (*expandedp)
     return target;
@@ -6599,15 +7242,27 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
       emit_insn (gen_altivec_dss (op0));
       return NULL_RTX;
 
-    case ALTIVEC_BUILTIN_COMPILETIME_ERROR:
-      arg0 = TREE_VALUE (arglist);
-      while (TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == ADDR_EXPR
-            || TREE_CODE (arg0) == ARRAY_REF)
-       arg0 = TREE_OPERAND (arg0, 0);
-      error ("invalid parameter combination for %qs AltiVec intrinsic",
-            TREE_STRING_POINTER (arg0));
+    case ALTIVEC_BUILTIN_VEC_INIT_V4SI:
+    case ALTIVEC_BUILTIN_VEC_INIT_V8HI:
+    case ALTIVEC_BUILTIN_VEC_INIT_V16QI:
+    case ALTIVEC_BUILTIN_VEC_INIT_V4SF:
+      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target);
 
-      return const0_rtx;
+    case ALTIVEC_BUILTIN_VEC_SET_V4SI:
+    case ALTIVEC_BUILTIN_VEC_SET_V8HI:
+    case ALTIVEC_BUILTIN_VEC_SET_V16QI:
+    case ALTIVEC_BUILTIN_VEC_SET_V4SF:
+      return altivec_expand_vec_set_builtin (arglist);
+
+    case ALTIVEC_BUILTIN_VEC_EXT_V4SI:
+    case ALTIVEC_BUILTIN_VEC_EXT_V8HI:
+    case ALTIVEC_BUILTIN_VEC_EXT_V16QI:
+    case ALTIVEC_BUILTIN_VEC_EXT_V4SF:
+      return altivec_expand_vec_ext_builtin (arglist, target);
+
+    default:
+      break;
+      /* Fall through.  */
     }
 
   /* Expand abs* operations.  */
@@ -6844,8 +7499,7 @@ spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
   else
     form_int = TREE_INT_CST_LOW (form);
 
-  if (mode0 != mode1)
-    abort ();
+  gcc_assert (mode0 == mode1);
 
   if (arg0 == error_mark_node || arg1 == error_mark_node)
     return const0_rtx;
@@ -6894,7 +7548,7 @@ spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
     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.
+        that's ugly and will make validate_condition_mode die.
         So let's just use another pattern.  */
       emit_insn (gen_move_from_CR_ov_bit (target, scratch));
       return target;
@@ -6946,8 +7600,7 @@ spe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
 
-  if (mode0 != mode1)
-    abort ();
+  gcc_assert (mode0 == mode1);
 
   if (arg0 == error_mark_node || arg1 == error_mark_node
       || arg2 == error_mark_node || arg3 == error_mark_node)
@@ -7010,12 +7663,10 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       tree arg;
       rtx op, addr, pat;
 
-      if (!TARGET_ALTIVEC)
-       abort ();
+      gcc_assert (TARGET_ALTIVEC);
 
       arg = TREE_VALUE (arglist);
-      if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
-       abort ();
+      gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
       op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
       addr = memory_address (mode, op);
       if (fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
@@ -7058,29 +7709,27 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
        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);
+  gcc_assert (TARGET_ALTIVEC || TARGET_SPE);
 
-      /* 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 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 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);
-    }
+  /* 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);
 
-  abort ();
-  return NULL_RTX;
+  /* 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);
+
+  gcc_unreachable ();
 }
 
 static tree
@@ -7109,6 +7758,7 @@ rs6000_init_builtins (void)
   opaque_V2SF_type_node = build_opaque_vector_type (float_type_node, 2);
   opaque_V2SI_type_node = build_opaque_vector_type (intSI_type_node, 2);
   opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
+  opaque_V4SI_type_node = copy_node (V4SI_type_node);
 
   /* The 'vector bool ...' types must be kept distinct from 'vector unsigned ...'
      types, especially in C++ land.  Similarly, 'vector pixel' is distinct from
@@ -7119,6 +7769,17 @@ rs6000_init_builtins (void)
   bool_int_type_node = build_distinct_type_copy (unsigned_intSI_type_node);
   pixel_type_node = build_distinct_type_copy (unsigned_intHI_type_node);
 
+  long_integer_type_internal_node = long_integer_type_node;
+  long_unsigned_type_internal_node = long_unsigned_type_node;
+  intQI_type_internal_node = intQI_type_node;
+  uintQI_type_internal_node = unsigned_intQI_type_node;
+  intHI_type_internal_node = intHI_type_node;
+  uintHI_type_internal_node = unsigned_intHI_type_node;
+  intSI_type_internal_node = intSI_type_node;
+  uintSI_type_internal_node = unsigned_intSI_type_node;
+  float_type_internal_node = float_type_node;
+  void_type_internal_node = void_type_node;
+
   (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
                                            get_identifier ("__bool char"),
                                            bool_char_type_node));
@@ -7401,7 +8062,7 @@ spe_init_builtins (void)
          type = int_ftype_int_v2sf_v2sf;
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       def_builtin (d->mask, d->name, type, d->code);
@@ -7422,7 +8083,7 @@ spe_init_builtins (void)
          type = v2sf_ftype_4_v2sf;
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       def_builtin (d->mask, d->name, type, d->code);
@@ -7435,6 +8096,8 @@ altivec_init_builtins (void)
   struct builtin_description *d;
   struct builtin_description_predicates *dp;
   size_t i;
+  tree ftype;
+
   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);
@@ -7449,6 +8112,21 @@ altivec_init_builtins (void)
 
   tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
 
+  tree int_ftype_opaque
+    = build_function_type_list (integer_type_node,
+                               opaque_V4SI_type_node, NULL_TREE);
+
+  tree opaque_ftype_opaque_int
+    = build_function_type_list (opaque_V4SI_type_node,
+                               opaque_V4SI_type_node, integer_type_node, NULL_TREE);
+  tree opaque_ftype_opaque_opaque_int
+    = build_function_type_list (opaque_V4SI_type_node,
+                               opaque_V4SI_type_node, opaque_V4SI_type_node,
+                               integer_type_node, NULL_TREE);
+  tree int_ftype_int_opaque_opaque
+    = build_function_type_list (integer_type_node,
+                                integer_type_node, opaque_V4SI_type_node,
+                                opaque_V4SI_type_node, NULL_TREE);
   tree int_ftype_int_v4si_v4si
     = build_function_type_list (integer_type_node,
                                integer_type_node, V4SI_type_node,
@@ -7482,6 +8160,9 @@ altivec_init_builtins (void)
   tree void_ftype_int
     = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
 
+  tree opaque_ftype_long_pcvoid
+    = build_function_type_list (opaque_V4SI_type_node,
+                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
   tree v16qi_ftype_long_pcvoid
     = build_function_type_list (V16QI_type_node,
                                long_integer_type_node, pcvoid_type_node, NULL_TREE);
@@ -7492,6 +8173,10 @@ altivec_init_builtins (void)
     = build_function_type_list (V4SI_type_node,
                                long_integer_type_node, pcvoid_type_node, NULL_TREE);
 
+  tree void_ftype_opaque_long_pvoid
+    = build_function_type_list (void_type_node,
+                               opaque_V4SI_type_node, long_integer_type_node,
+                               pvoid_type_node, NULL_TREE);
   tree void_ftype_v4si_long_pvoid
     = build_function_type_list (void_type_node,
                                V4SI_type_node, long_integer_type_node,
@@ -7528,9 +8213,6 @@ altivec_init_builtins (void)
     = build_function_type_list (void_type_node,
                                pcvoid_type_node, integer_type_node,
                                integer_type_node, NULL_TREE);
-  tree int_ftype_pcchar
-    = build_function_type_list (integer_type_node,
-                               pcchar_type_node, NULL_TREE);
 
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
               ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
@@ -7564,10 +8246,33 @@ altivec_init_builtins (void)
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
-
-  /* See altivec.h for usage of "__builtin_altivec_compiletime_error".  */
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_compiletime_error", int_ftype_pcchar,
-              ALTIVEC_BUILTIN_COMPILETIME_ERROR);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX);
+
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
+
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
 
   /* Add the DST variants.  */
   d = (struct builtin_description *) bdesc_dst;
@@ -7580,11 +8285,19 @@ altivec_init_builtins (void)
     {
       enum machine_mode mode1;
       tree type;
+      bool is_overloaded = dp->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
+                          && dp->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
 
-      mode1 = insn_data[dp->icode].operand[1].mode;
+      if (is_overloaded)
+       mode1 = VOIDmode;
+      else
+       mode1 = insn_data[dp->icode].operand[1].mode;
 
       switch (mode1)
        {
+       case VOIDmode:
+         type = int_ftype_int_opaque_opaque;
+         break;
        case V4SImode:
          type = int_ftype_int_v4si_v4si;
          break;
@@ -7598,7 +8311,7 @@ altivec_init_builtins (void)
          type = int_ftype_int_v4sf_v4sf;
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       def_builtin (dp->mask, dp->name, type, dp->code);
@@ -7628,7 +8341,7 @@ altivec_init_builtins (void)
          type = v4sf_ftype_v4sf;
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       def_builtin (d->mask, d->name, type, d->code);
@@ -7642,12 +8355,96 @@ altivec_init_builtins (void)
          targetm.vectorize.builtin_mask_for_load.  */
 
       decl = lang_hooks.builtin_function ("__builtin_altivec_mask_for_load",
-                                         v16qi_ftype_long_pcvoid,
-                                         ALTIVEC_BUILTIN_MASK_FOR_LOAD,
-                                         BUILT_IN_MD, NULL, NULL_TREE);
+                               v16qi_ftype_long_pcvoid,
+                               ALTIVEC_BUILTIN_MASK_FOR_LOAD,
+                               BUILT_IN_MD, NULL,
+                               tree_cons (get_identifier ("const"),
+                                          NULL_TREE, NULL_TREE));
       /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
       altivec_builtin_mask_for_load = decl;
     }
+
+  /* Access to the vec_init patterns.  */
+  ftype = build_function_type_list (V4SI_type_node, integer_type_node,
+                                   integer_type_node, integer_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4si", ftype,
+              ALTIVEC_BUILTIN_VEC_INIT_V4SI);
+
+  ftype = build_function_type_list (V8HI_type_node, short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node,
+                                   short_integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v8hi", ftype,
+              ALTIVEC_BUILTIN_VEC_INIT_V8HI);
+
+  ftype = build_function_type_list (V16QI_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, char_type_node,
+                                   char_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v16qi", ftype,
+              ALTIVEC_BUILTIN_VEC_INIT_V16QI);
+
+  ftype = build_function_type_list (V4SF_type_node, float_type_node,
+                                   float_type_node, float_type_node,
+                                   float_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_init_v4sf", ftype,
+              ALTIVEC_BUILTIN_VEC_INIT_V4SF);
+
+  /* Access to the vec_set patterns.  */
+  ftype = build_function_type_list (V4SI_type_node, V4SI_type_node,
+                                   intSI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4si", ftype,
+              ALTIVEC_BUILTIN_VEC_SET_V4SI);
+
+  ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
+                                   intHI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v8hi", ftype,
+              ALTIVEC_BUILTIN_VEC_SET_V8HI);
+
+  ftype = build_function_type_list (V8HI_type_node, V16QI_type_node,
+                                   intQI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v16qi", ftype,
+              ALTIVEC_BUILTIN_VEC_SET_V16QI);
+
+  ftype = build_function_type_list (V4SF_type_node, V4SF_type_node,
+                                   float_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_set_v4sf", ftype,
+              ALTIVEC_BUILTIN_VEC_SET_V4SF);
+
+  /* Access to the vec_extract patterns.  */
+  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4si", ftype,
+              ALTIVEC_BUILTIN_VEC_EXT_V4SI);
+
+  ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v8hi", ftype,
+              ALTIVEC_BUILTIN_VEC_EXT_V8HI);
+
+  ftype = build_function_type_list (intQI_type_node, V16QI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v16qi", ftype,
+              ALTIVEC_BUILTIN_VEC_EXT_V16QI);
+
+  ftype = build_function_type_list (float_type_node, V4SF_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_ALTIVEC, "__builtin_vec_ext_v4sf", ftype,
+              ALTIVEC_BUILTIN_VEC_EXT_V4SF);
 }
 
 static void
@@ -7698,6 +8495,10 @@ rs6000_common_init_builtins (void)
                                integer_type_node, integer_type_node,
                                NULL_TREE);
 
+  tree opaque_ftype_opaque
+    = build_function_type_list (opaque_V4SI_type_node,
+                               opaque_V4SI_type_node, NULL_TREE);
+
   tree v2si_ftype_v2si
     = build_function_type_list (opaque_V2SI_type_node,
                                opaque_V2SI_type_node, NULL_TREE);
@@ -7732,6 +8533,9 @@ rs6000_common_init_builtins (void)
                                integer_type_node, integer_type_node,
                                NULL_TREE);
 
+  tree opaque_ftype_opaque_opaque
+    = build_function_type_list (opaque_V4SI_type_node,
+                                opaque_V4SI_type_node, opaque_V4SI_type_node, NULL_TREE);
   tree v4si_ftype_v4si_v4si
     = build_function_type_list (V4SI_type_node,
                                V4SI_type_node, V4SI_type_node, NULL_TREE);
@@ -7769,6 +8573,10 @@ rs6000_common_init_builtins (void)
   tree v4sf_ftype_v4sf_v4sf
     = build_function_type_list (V4SF_type_node,
                                V4SF_type_node, V4SF_type_node, NULL_TREE);
+  tree opaque_ftype_opaque_opaque_opaque
+    = build_function_type_list (opaque_V4SI_type_node,
+                                opaque_V4SI_type_node, opaque_V4SI_type_node,
+                                opaque_V4SI_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf_v4sf_v4si
     = build_function_type_list (V4SF_type_node,
                                V4SF_type_node, V4SF_type_node,
@@ -7842,23 +8650,37 @@ rs6000_common_init_builtins (void)
   d = (struct builtin_description *) bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
     {
-
       enum machine_mode mode0, mode1, mode2, mode3;
       tree type;
+      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
+                          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
 
-      if (d->name == 0 || d->icode == CODE_FOR_nothing)
-       continue;
+      if (is_overloaded)
+       {
+          mode0 = VOIDmode;
+          mode1 = VOIDmode;
+          mode2 = VOIDmode;
+          mode3 = VOIDmode;
+       }
+      else
+       {
+          if (d->name == 0 || d->icode == CODE_FOR_nothing)
+           continue;
 
-      mode0 = insn_data[d->icode].operand[0].mode;
-      mode1 = insn_data[d->icode].operand[1].mode;
-      mode2 = insn_data[d->icode].operand[2].mode;
-      mode3 = insn_data[d->icode].operand[3].mode;
+          mode0 = insn_data[d->icode].operand[0].mode;
+          mode1 = insn_data[d->icode].operand[1].mode;
+          mode2 = insn_data[d->icode].operand[2].mode;
+          mode3 = insn_data[d->icode].operand[3].mode;
+       }
 
       /* When all four are of the same mode.  */
       if (mode0 == mode1 && mode1 == mode2 && mode2 == mode3)
        {
          switch (mode0)
            {
+           case VOIDmode:
+             type = opaque_ftype_opaque_opaque_opaque;
+             break;
            case V4SImode:
              type = v4si_ftype_v4si_v4si_v4si;
              break;
@@ -7872,7 +8694,7 @@ rs6000_common_init_builtins (void)
              type = v16qi_ftype_v16qi_v16qi_v16qi;
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
       else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
@@ -7892,7 +8714,7 @@ rs6000_common_init_builtins (void)
              type = v16qi_ftype_v16qi_v16qi_v16qi;
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
       else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
@@ -7926,7 +8748,7 @@ rs6000_common_init_builtins (void)
        type = v4sf_ftype_v4sf_v4sf_int;
 
       else
-       abort ();
+       gcc_unreachable ();
 
       def_builtin (d->mask, d->name, type, d->code);
     }
@@ -7937,19 +8759,33 @@ rs6000_common_init_builtins (void)
     {
       enum machine_mode mode0, mode1, mode2;
       tree type;
+      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
+                          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
 
-      if (d->name == 0 || d->icode == CODE_FOR_nothing)
-       continue;
+      if (is_overloaded)
+       {
+         mode0 = VOIDmode;
+         mode1 = VOIDmode;
+         mode2 = VOIDmode;
+       }
+      else
+       {
+          if (d->name == 0 || d->icode == CODE_FOR_nothing)
+           continue;
 
-      mode0 = insn_data[d->icode].operand[0].mode;
-      mode1 = insn_data[d->icode].operand[1].mode;
-      mode2 = insn_data[d->icode].operand[2].mode;
+          mode0 = insn_data[d->icode].operand[0].mode;
+          mode1 = insn_data[d->icode].operand[1].mode;
+          mode2 = insn_data[d->icode].operand[2].mode;
+       }
 
       /* When all three operands are of the same mode.  */
       if (mode0 == mode1 && mode1 == mode2)
        {
          switch (mode0)
            {
+           case VOIDmode:
+             type = opaque_ftype_opaque_opaque;
+             break;
            case V4SFmode:
              type = v4sf_ftype_v4sf_v4sf;
              break;
@@ -7972,7 +8808,7 @@ rs6000_common_init_builtins (void)
              type = int_ftype_int_int;
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
 
@@ -8039,9 +8875,10 @@ rs6000_common_init_builtins (void)
       else if (mode0 == V2SImode && mode1 == SImode && mode2 == QImode)
        type = v2si_ftype_int_char;
 
-      /* int, x, x.  */
-      else if (mode0 == SImode)
+      else
        {
+         /* int, x, x.  */
+         gcc_assert (mode0 == SImode);
          switch (mode1)
            {
            case V4SImode:
@@ -8057,13 +8894,10 @@ rs6000_common_init_builtins (void)
              type = int_ftype_v8hi_v8hi;
              break;
            default:
-             abort ();
+             gcc_unreachable ();
            }
        }
 
-      else
-       abort ();
-
       def_builtin (d->mask, d->name, type, d->code);
     }
 
@@ -8073,12 +8907,22 @@ rs6000_common_init_builtins (void)
     {
       enum machine_mode mode0, mode1;
       tree type;
+      bool is_overloaded = d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
+                          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST;
+
+      if (is_overloaded)
+        {
+          mode0 = VOIDmode;
+          mode1 = VOIDmode;
+        }
+      else
+        {
+          if (d->name == 0 || d->icode == CODE_FOR_nothing)
+           continue;
 
-      if (d->name == 0 || d->icode == CODE_FOR_nothing)
-       continue;
-
-      mode0 = insn_data[d->icode].operand[0].mode;
-      mode1 = insn_data[d->icode].operand[1].mode;
+          mode0 = insn_data[d->icode].operand[0].mode;
+          mode1 = insn_data[d->icode].operand[1].mode;
+        }
 
       if (mode0 == V4SImode && mode1 == QImode)
        type = v4si_ftype_int;
@@ -8086,6 +8930,8 @@ rs6000_common_init_builtins (void)
        type = v8hi_ftype_int;
       else if (mode0 == V16QImode && mode1 == QImode)
        type = v16qi_ftype_int;
+      else if (mode0 == VOIDmode && mode1 == VOIDmode)
+       type = opaque_ftype_opaque;
       else if (mode0 == V4SFmode && mode1 == V4SFmode)
        type = v4sf_ftype_v4sf;
       else if (mode0 == V8HImode && mode1 == V16QImode)
@@ -8103,7 +8949,7 @@ rs6000_common_init_builtins (void)
       else if (mode0 == V2SImode && mode1 == QImode)
        type = v2si_ftype_char;
       else
-       abort ();
+       gcc_unreachable ();
 
       def_builtin (d->mask, d->name, type, d->code);
     }
@@ -8125,12 +8971,22 @@ rs6000_init_libfuncs (void)
          set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
          set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
        }
-
-      /* Standard AIX/Darwin/64-bit SVR4 quad floating point routines.  */
-      set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
-      set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
-      set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
-      set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+
+      /* AIX/Darwin/64-bit Linux quad floating point routines.  */
+      if (!TARGET_XL_COMPAT)
+       {
+         set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
+         set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
+         set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
+         set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+       }
+      else
+       {
+         set_optab_libfunc (add_optab, TFmode, "_xlqadd");
+         set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
+         set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
+         set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
+       }
     }
   else
     {
@@ -8167,14 +9023,14 @@ rs6000_init_libfuncs (void)
 
    operands[0] is the destination
    operands[1] is the length
-   operands[2] is the alignment */
+   operands[3] is the alignment */
 
 int
 expand_block_clear (rtx operands[])
 {
   rtx orig_dest = operands[0];
   rtx bytes_rtx        = operands[1];
-  rtx align_rtx = operands[2];
+  rtx align_rtx = operands[3];
   bool constp  = (GET_CODE (bytes_rtx) == CONST_INT);
   HOST_WIDE_INT align;
   HOST_WIDE_INT bytes;
@@ -8186,9 +9042,8 @@ expand_block_clear (rtx operands[])
   if (! constp)
     return 0;
 
-  /* If this is not a fixed size alignment, abort */
-  if (GET_CODE (align_rtx) != CONST_INT)
-    abort ();
+  /* This must be a fixed size alignment  */
+  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
   align = INTVAL (align_rtx) * BITS_PER_UNIT;
 
   /* Anything to clear? */
@@ -8235,7 +9090,7 @@ expand_block_clear (rtx operands[])
          clear_bytes = 4;
          mode = SImode;
        }
-      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
+      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          clear_bytes = 2;
          mode = HImode;
@@ -8284,9 +9139,8 @@ expand_block_move (rtx operands[])
   if (! constp)
     return 0;
 
-  /* If this is not a fixed size alignment, abort */
-  if (GET_CODE (align_rtx) != CONST_INT)
-    abort ();
+  /* This must be a fixed size alignment */
+  gcc_assert (GET_CODE (align_rtx) == CONST_INT);
   align = INTVAL (align_rtx) * BITS_PER_UNIT;
 
   /* Anything to move? */
@@ -8372,7 +9226,7 @@ expand_block_move (rtx operands[])
          mode = SImode;
          gen_func.mov = gen_movsi;
        }
-      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
+      else if (bytes >= 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          move_bytes = 2;
          mode = HImode;
@@ -8502,40 +9356,33 @@ rs6000_output_load_multiple (rtx operands[3])
 void
 validate_condition_mode (enum rtx_code code, enum machine_mode mode)
 {
-  if ((GET_RTX_CLASS (code) != RTX_COMPARE
-       && GET_RTX_CLASS (code) != RTX_COMM_COMPARE)
-      || GET_MODE_CLASS (mode) != MODE_CC)
-    abort ();
+  gcc_assert ((GET_RTX_CLASS (code) == RTX_COMPARE
+              || GET_RTX_CLASS (code) == RTX_COMM_COMPARE)
+             && GET_MODE_CLASS (mode) == MODE_CC);
 
   /* These don't make sense.  */
-  if ((code == GT || code == LT || code == GE || code == LE)
-      && mode == CCUNSmode)
-    abort ();
+  gcc_assert ((code != GT && code != LT && code != GE && code != LE)
+             || mode != CCUNSmode);
 
-  if ((code == GTU || code == LTU || code == GEU || code == LEU)
-      && mode != CCUNSmode)
-    abort ();
+  gcc_assert ((code != GTU && code != LTU && code != GEU && code != LEU)
+             || mode == CCUNSmode);
 
-  if (mode != CCFPmode
-      && (code == ORDERED || code == UNORDERED
-         || code == UNEQ || code == LTGT
-         || code == UNGT || code == UNLT
-         || code == UNGE || code == UNLE))
-    abort ();
+  gcc_assert (mode == CCFPmode
+             || (code != ORDERED && code != UNORDERED
+                 && code != UNEQ && code != LTGT
+                 && code != UNGT && code != UNLT
+                 && code != UNGE && code != UNLE));
 
   /* These should never be generated except for
      flag_finite_math_only.  */
-  if (mode == CCFPmode
-      && ! flag_finite_math_only
-      && (code == LE || code == GE
-         || code == UNEQ || code == LTGT
-         || code == UNGT || code == UNLT))
-    abort ();
+  gcc_assert (mode != CCFPmode
+             || flag_finite_math_only
+             || (code != LE && code != GE
+                 && code != UNEQ && code != LTGT
+                 && code != UNGT && code != UNLT));
 
   /* These are invalid; the information is not there.  */
-  if (mode == CCEQmode
-      && code != EQ && code != NE)
-    abort ();
+  gcc_assert (mode != CCEQmode || code == EQ || code == NE);
 }
 
 \f
@@ -8774,8 +9621,8 @@ int
 mems_ok_for_quad_peep (rtx mem1, rtx mem2)
 {
   rtx addr1, addr2;
-  unsigned int reg1;
-  int offset1;
+  unsigned int reg1, reg2;
+  int offset1, offset2;
 
   /* The mems cannot be volatile.  */
   if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
@@ -8808,23 +9655,36 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem2)
       offset1 = 0;
     }
 
-  /* Make sure the second address is a (mem (plus (reg) (const_int)))
-     or if it is (mem (reg)) then make sure that offset1 is -8 and the same
-     register as addr1.  */
-  if (offset1 == -8 && GET_CODE (addr2) == REG && reg1 == REGNO (addr2))
-    return 1;
-  if (GET_CODE (addr2) != PLUS)
-    return 0;
-
-  if (GET_CODE (XEXP (addr2, 0)) != REG
-      || GET_CODE (XEXP (addr2, 1)) != CONST_INT)
+  /* And now for the second addr.  */
+  if (GET_CODE (addr2) == PLUS)
+    {
+      /* If not a REG, return zero.  */
+      if (GET_CODE (XEXP (addr2, 0)) != REG)
+       return 0;
+      else
+       {
+         reg2 = REGNO (XEXP (addr2, 0));
+         /* The offset must be constant. */
+         if (GET_CODE (XEXP (addr2, 1)) != CONST_INT)
+           return 0;
+         offset2 = INTVAL (XEXP (addr2, 1));
+       }
+    }
+  else if (GET_CODE (addr2) != REG)
     return 0;
+  else
+    {
+      reg2 = REGNO (addr2);
+      /* This was a simple (mem (reg)) expression.  Offset is 0.  */
+      offset2 = 0;
+    }
 
-  if (reg1 != REGNO (XEXP (addr2, 0)))
+  /* Both of these must have the same base register.  */
+  if (reg1 != reg2)
     return 0;
 
   /* The offset for the second addr must be 8 more than the first addr.  */
-  if (INTVAL (XEXP (addr2, 1)) != offset1 + 8)
+  if (offset2 != offset1 + 8)
     return 0;
 
   /* All the tests passed.  addr1 and addr2 are valid for lfq or stfq
@@ -8930,9 +9790,7 @@ ccr_bit (rtx op, int scc_p)
 
   reg = XEXP (op, 0);
 
-  if (GET_CODE (reg) != REG
-      || ! CR_REGNO_P (REGNO (reg)))
-    abort ();
+  gcc_assert (GET_CODE (reg) == REG && CR_REGNO_P (REGNO (reg)));
 
   cc_mode = GET_MODE (reg);
   cc_regnum = REGNO (reg);
@@ -8942,9 +9800,9 @@ ccr_bit (rtx op, int scc_p)
 
   /* When generating a sCOND operation, only positive conditions are
      allowed.  */
-  if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
-      && code != GTU && code != LTU)
-    abort ();
+  gcc_assert (!scc_p
+             || code == EQ || code == GT || code == LT || code == UNORDERED
+             || code == GTU || code == LTU);
 
   switch (code)
     {
@@ -8969,7 +9827,7 @@ ccr_bit (rtx op, int scc_p)
       return scc_p ? base_bit + 3 : base_bit + 1;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 \f
@@ -9017,8 +9875,7 @@ extract_MB (rtx op)
      from the left.  */
   if ((val & 0x80000000) == 0)
     {
-      if ((val & 0xffffffff) == 0)
-       abort ();
+      gcc_assert (val & 0xffffffff);
 
       i = 1;
       while (((val <<= 1) & 0x80000000) == 0)
@@ -9050,8 +9907,7 @@ extract_ME (rtx op)
      the right.  */
   if ((val & 1) == 0)
     {
-      if ((val & 0xffffffff) == 0)
-       abort ();
+      gcc_assert (val & 0xffffffff);
 
       i = 30;
       while (((val >>= 1) & 1) == 0)
@@ -9091,7 +9947,7 @@ rs6000_get_some_local_dynamic_name (void)
                         rs6000_get_some_local_dynamic_name_1, 0))
       return cfun->machine->some_ld_name;
 
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Helper function for rs6000_get_some_local_dynamic_name.  */
@@ -9124,7 +9980,7 @@ rs6000_output_function_entry (FILE *file, const char *fname)
       switch (DEFAULT_ABI)
        {
        default:
-         abort ();
+         gcc_unreachable ();
 
        case ABI_AIX:
          if (DOT_SYMBOLS)
@@ -9210,8 +10066,7 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'D':
       /* Like 'J' but get to the EQ bit.  */
-      if (GET_CODE (x) != REG)
-       abort ();
+      gcc_assert (GET_CODE (x) == REG);
 
       /* Bit 1 is EQ bit.  */
       i = 4 * (REGNO (x) - CR0_REGNO) + 2;
@@ -9503,15 +10358,13 @@ print_operand (FILE *file, rtx x, int code)
        }
       while (uval != 0)
        --i, uval >>= 1;
-      if (i < 0)
-       abort ();
+      gcc_assert (i >= 0);
       fprintf (file, "%d", i);
       return;
 
     case 't':
       /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
-      if (GET_CODE (x) != REG || GET_MODE (x) != CCmode)
-       abort ();
+      gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == CCmode);
 
       /* Bit 3 is OV bit.  */
       i = 4 * (REGNO (x) - CR0_REGNO) + 3;
@@ -9592,7 +10445,7 @@ print_operand (FILE *file, rtx x, int code)
          fputs ("lge", file);  /* 5 */
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -9625,9 +10478,8 @@ print_operand (FILE *file, rtx x, int code)
        {
          val = CONST_DOUBLE_LOW (x);
 
-         if (val == 0)
-           abort ();
-         else if (val < 0)
+         gcc_assert (val);
+         if (val < 0)
            --i;
          else
            for ( ; i < 64; i++)
@@ -9668,8 +10520,7 @@ print_operand (FILE *file, rtx x, int code)
         names.  If we are configured for System V (or the embedded ABI) on
         the PowerPC, do not emit the period, since those systems do not use
         TOCs and the like.  */
-      if (GET_CODE (x) != SYMBOL_REF)
-       abort ();
+      gcc_assert (GET_CODE (x) == SYMBOL_REF);
 
       /* Mark the decl as referenced so that cgraph will output the
         function.  */
@@ -9715,8 +10566,7 @@ print_operand (FILE *file, rtx x, int code)
       {
        rtx tmp;
 
-       if (GET_CODE (x) != MEM)
-         abort ();
+       gcc_assert (GET_CODE (x) == MEM);
 
        tmp = XEXP (x, 0);
 
@@ -9734,8 +10584,7 @@ print_operand (FILE *file, rtx x, int code)
              {
                int x;
 
-               if (GET_CODE (XEXP (tmp, 0)) != REG)
-                 abort ();
+               gcc_assert (GET_CODE (XEXP (tmp, 0)) == REG);
 
                x = INTVAL (XEXP (tmp, 1));
                fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
@@ -9751,8 +10600,11 @@ print_operand (FILE *file, rtx x, int code)
          tmp = XEXP (tmp, 0);
        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)
+       else
          {
+           gcc_assert (GET_CODE (tmp) == PLUS
+                       && GET_CODE (XEXP (tmp, 1)) == REG);
+
            if (REGNO (XEXP (tmp, 0)) == 0)
              fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
                       reg_names[ REGNO (XEXP (tmp, 0)) ]);
@@ -9760,8 +10612,6 @@ print_operand (FILE *file, rtx x, int code)
              fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 0)) ],
                       reg_names[ REGNO (XEXP (tmp, 1)) ]);
          }
-       else
-         abort ();
        break;
       }
 
@@ -9808,8 +10658,8 @@ print_operand_address (FILE *file, rtx x)
       if (small_data_operand (x, GET_MODE (x)))
        fprintf (file, "@%s(%s)", SMALL_DATA_RELOC,
                 reg_names[SMALL_DATA_REG]);
-      else if (TARGET_TOC)
-       abort ();
+      else
+       gcc_assert (!TARGET_TOC);
     }
   else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
     {
@@ -9877,7 +10727,7 @@ print_operand_address (FILE *file, rtx x)
       fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
     }
   else
-    abort ();
+    gcc_unreachable ();
 }
 \f
 /* Target hook for assembling integer objects.  The PowerPC version has
@@ -10033,52 +10883,78 @@ rs6000_generate_compare (enum rtx_code code)
       switch (code)
        {
        case EQ: case UNEQ: case NE: case LTGT:
-         if (op_mode == SFmode)
-           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);
-         else if (op_mode == DFmode)
-           cmp = flag_unsafe_math_optimizations
-             ? gen_tstdfeq_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1)
-             : gen_cmpdfeq_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1);
-         else abort ();
+         switch (op_mode)
+           {
+           case SFmode:
+             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 DFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tstdfeq_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmpdfeq_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
          break;
+
        case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
-         if (op_mode == SFmode)
-           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);
-         else if (op_mode == DFmode)
-           cmp = flag_unsafe_math_optimizations
-             ? gen_tstdfgt_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1)
-             : gen_cmpdfgt_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1);
-         else abort ();
+         switch (op_mode)
+           {
+           case SFmode:
+             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 DFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tstdfgt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmpdfgt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
          break;
+
        case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
-         if (op_mode == SFmode)
-           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);
-         else if (op_mode == DFmode)
-           cmp = flag_unsafe_math_optimizations
-             ? gen_tstdflt_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1)
-             : gen_cmpdflt_gpr (compare_result, rs6000_compare_op0,
-                                rs6000_compare_op1);
-         else abort ();
+         switch (op_mode)
+           {
+           case SFmode:
+             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;
+
+           case DFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tstdflt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmpdflt_gpr (compare_result, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
          break;
         default:
-          abort ();
+          gcc_unreachable ();
        }
 
       /* Synthesize LE and GE from LT/GT || EQ.  */
@@ -10092,25 +10968,33 @@ rs6000_generate_compare (enum rtx_code code)
            case GE: code = GT; break;
            case LEU: code = LT; break;
            case GEU: code = GT; break;
-           default: abort ();
+           default: gcc_unreachable ();
            }
 
          compare_result2 = gen_reg_rtx (CCFPmode);
 
          /* Do the EQ.  */
-         if (op_mode == SFmode)
-           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);
-         else if (op_mode == DFmode)
-           cmp = flag_unsafe_math_optimizations
-             ? gen_tstdfeq_gpr (compare_result2, rs6000_compare_op0,
-                                rs6000_compare_op1)
-             : gen_cmpdfeq_gpr (compare_result2, rs6000_compare_op0,
-                                rs6000_compare_op1);
-         else abort ();
+         switch (op_mode)
+           {
+           case SFmode:
+             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);
+             break;
+
+           case DFmode:
+             cmp = flag_unsafe_math_optimizations
+               ? gen_tstdfeq_gpr (compare_result2, rs6000_compare_op0,
+                                  rs6000_compare_op1)
+               : gen_cmpdfeq_gpr (compare_result2, rs6000_compare_op0,
+                                  rs6000_compare_op1);
+             break;
+
+           default:
+             gcc_unreachable ();
+           }
          emit_insn (cmp);
 
          /* OR them together.  */
@@ -10153,6 +11037,19 @@ rs6000_generate_compare (enum rtx_code code)
                     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
                     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
                     gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
+      else if (GET_CODE (rs6000_compare_op1) == UNSPEC
+              && XINT (rs6000_compare_op1, 1) == UNSPEC_SP_TEST)
+       {
+         rtx op1 = XVECEXP (rs6000_compare_op1, 0, 0);
+         comp_mode = CCEQmode;
+         compare_result = gen_reg_rtx (CCEQmode);
+         if (TARGET_64BIT)
+           emit_insn (gen_stack_protect_testdi (compare_result,
+                                                rs6000_compare_op0, op1));
+         else
+           emit_insn (gen_stack_protect_testsi (compare_result,
+                                                rs6000_compare_op0, op1));
+       }
       else
        emit_insn (gen_rtx_SET (VOIDmode, compare_result,
                                gen_rtx_COMPARE (comp_mode,
@@ -10161,10 +11058,10 @@ rs6000_generate_compare (enum rtx_code code)
     }
 
   /* Some kinds of FP comparisons need an OR operation;
-     under flag_unsafe_math_optimizations we don't bother.  */
+     under flag_finite_math_only we don't bother.  */
   if (rs6000_compare_fp_p
-      && ! flag_unsafe_math_optimizations
-      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
+      && !flag_finite_math_only
+      && !(TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -10181,7 +11078,7 @@ rs6000_generate_compare (enum rtx_code code)
        case LTGT: or1 = LT;  or2 = GT;  break;
        case UNGT: or1 = UNORDERED;  or2 = GT;  break;
        case UNLT: or1 = UNORDERED;  or2 = LT;  break;
-       default:  abort ();
+       default:  gcc_unreachable ();
        }
       validate_condition_mode (or1, comp_mode);
       validate_condition_mode (or2, comp_mode);
@@ -10222,8 +11119,7 @@ rs6000_emit_sCOND (enum rtx_code code, rtx result)
       PUT_MODE (condition_rtx, SImode);
       t = XEXP (condition_rtx, 0);
 
-      if (cond_code != NE && cond_code != EQ)
-       abort ();
+      gcc_assert (cond_code == NE || cond_code == EQ);
 
       if (cond_code == NE)
        emit_insn (gen_e500_flip_gt_bit (t, t));
@@ -10326,13 +11222,20 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
     {
       /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
         to the GT bit.  */
-      if (code == EQ)
-       /* Opposite of GT.  */
-       code = GT;
-      else if (code == NE)
-       code = UNLE;
-      else
-       abort ();
+      switch (code)
+       {
+       case EQ:
+         /* Opposite of GT.  */
+         code = GT;
+         break;
+
+       case NE:
+         code = UNLE;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
     }
 
   switch (code)
@@ -10356,7 +11259,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
     case UNGE: ccode = "nl"; break;
     case UNLE: ccode = "ng"; break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   /* Maybe we have a guess as to how likely the branch is.
@@ -10416,9 +11319,8 @@ output_e500_flip_gt_bit (rtx dst, rtx src)
   static char string[64];
   int a, b;
 
-  if (GET_CODE (dst) != REG || ! CR_REGNO_P (REGNO (dst))
-      || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
-    abort ();
+  gcc_assert (GET_CODE (dst) == REG && CR_REGNO_P (REGNO (dst))
+             && GET_CODE (src) == REG && CR_REGNO_P (REGNO (src)));
 
   /* GT bit.  */
   a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
@@ -10492,13 +11394,8 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
   enum machine_mode dest_mode;
   enum machine_mode op_mode = GET_MODE (op1);
 
-#ifdef ENABLE_CHECKING
-  if (!TARGET_ALTIVEC)
-    abort ();
-
-  if (GET_MODE (op0) != GET_MODE (op1))
-    abort ();
-#endif
+  gcc_assert (TARGET_ALTIVEC);
+  gcc_assert (GET_MODE (op0) == GET_MODE (op1));
 
   /* Floating point vector compare instructions uses destination V4SImode.
      Move destination to appropriate mode later.  */
@@ -10534,8 +11431,7 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
                                                     dest_mode);
 
            nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
-           if (nor_code == CODE_FOR_nothing)
-             abort ();
+           gcc_assert (nor_code != CODE_FOR_nothing);
            emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
 
            if (dmode != dest_mode)
@@ -10557,16 +11453,27 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
            enum insn_code ior_code;
            enum rtx_code new_code;
 
-           if (rcode == GE)
-             new_code = GT;
-           else if (rcode == GEU)
-             new_code = GTU;
-           else if (rcode == LE)
-             new_code = LT;
-           else if (rcode == LEU)
-             new_code = LTU;
-           else
-             abort ();
+           switch (rcode)
+             {
+             case  GE:
+               new_code = GT;
+               break;
+
+             case GEU:
+               new_code = GTU;
+               break;
+
+             case LE:
+               new_code = LT;
+               break;
+
+             case LEU:
+               new_code = LTU;
+               break;
+
+             default:
+               gcc_unreachable ();
+             }
 
            c_rtx = rs6000_emit_vector_compare (new_code,
                                                op0, op1, dest_mode);
@@ -10574,8 +11481,7 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
                                                 dest_mode);
 
            ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
-           if (ior_code == CODE_FOR_nothing)
-             abort ();
+           gcc_assert (ior_code != CODE_FOR_nothing);
            emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
            if (dmode != dest_mode)
              {
@@ -10587,15 +11493,14 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
          }
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       if (try_again)
        {
          vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
-         if (vec_cmp_insn == INSN_NOT_AVAILABLE)
-           /* You only get two chances.  */
-           abort ();
+         /* You only get two chances.  */
+         gcc_assert (vec_cmp_insn != INSN_NOT_AVAILABLE);
        }
 
       if (swap_operands)
@@ -10607,12 +11512,10 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
        }
     }
 
-  emit_insn (gen_rtx_fmt_ee (SET,
-                            VOIDmode,
-                            mask,
-                            gen_rtx_fmt_Ei (UNSPEC, dest_mode,
-                                            gen_rtvec (2, op0, op1),
-                                            vec_cmp_insn)));
+  emit_insn (gen_rtx_SET (VOIDmode, mask,
+                         gen_rtx_UNSPEC (dest_mode,
+                                         gen_rtvec (2, op0, op1),
+                                         vec_cmp_insn)));
   if (dmode != dest_mode)
     {
       rtx temp = gen_reg_rtx (dest_mode);
@@ -10661,10 +11564,12 @@ rs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask)
 
   temp = gen_reg_rtx (dest_mode);
 
-  t = gen_rtx_fmt_ee (SET, VOIDmode, temp,
-                     gen_rtx_fmt_Ei (UNSPEC, dest_mode,
-                                     gen_rtvec (3, op1, op2, mask),
-                                     vsel_insn_index));
+  /* For each vector element, select op1 when mask is 1 otherwise
+     select op2.  */
+  t = gen_rtx_SET (VOIDmode, temp,
+                  gen_rtx_UNSPEC (dest_mode,
+                                  gen_rtvec (3, op2, op1, mask),
+                                  vsel_insn_index));
   emit_insn (t);
   emit_move_insn (dest, temp);
   return;
@@ -10846,106 +11751,452 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
       false_cond = true_cond;
       true_cond = temp;
 
-      temp = gen_reg_rtx (compare_mode);
-      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
-      op0 = temp;
-      break;
+      temp = gen_reg_rtx (compare_mode);
+      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
+      op0 = temp;
+      break;
+
+    case GT:
+      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
+      temp = gen_reg_rtx (result_mode);
+      emit_insn (gen_rtx_SET (VOIDmode, temp,
+                             gen_rtx_IF_THEN_ELSE (result_mode,
+                                                   gen_rtx_GE (VOIDmode,
+                                                               op0, op1),
+                                                   true_cond, false_cond)));
+      true_cond = false_cond;
+      false_cond = temp;
+
+      temp = gen_reg_rtx (compare_mode);
+      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
+      op0 = temp;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  emit_insn (gen_rtx_SET (VOIDmode, dest,
+                         gen_rtx_IF_THEN_ELSE (result_mode,
+                                               gen_rtx_GE (VOIDmode,
+                                                           op0, op1),
+                                               true_cond, false_cond)));
+  return 1;
+}
+
+/* Same as above, but for ints (isel).  */
+
+static int
+rs6000_emit_int_cmove (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 (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 (rtx dest, enum rtx_code code, rtx op0, 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, c, op0, op1, mode,
+                                   op0, op1, mode, 0);
+  else
+    target = emit_conditional_move (dest, c, op0, op1, mode,
+                                   op1, op0, mode, 0);
+  gcc_assert (target);
+  if (target != dest)
+    emit_move_insn (dest, target);
+}
+
+/* Emit instructions to perform a load-reserved/store-conditional operation.
+   The operation performed is an atomic
+   (set M (CODE:MODE M OP))
+   If not NULL, BEFORE is atomically set to M before the operation, and
+   AFTER is set to M after the operation (that is, (CODE:MODE M OP)).
+   If SYNC_P then a memory barrier is emitted before the operation.
+   Either OP or M may be wrapped in a NOT operation.  */
+
+void
+rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
+                 rtx m, rtx op, rtx before_param, rtx after_param,
+                 bool sync_p)
+{
+  enum machine_mode used_mode;
+  rtx the_op, set_before, set_after, set_atomic, cc_scratch, before, after;
+  rtx used_m;
+  rtvec vec;
+  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
+  rtx shift = NULL_RTX;
+
+  if (sync_p)
+    emit_insn (gen_memory_barrier ());
+
+  if (GET_CODE (m) == NOT)
+    used_m = XEXP (m, 0);
+  else
+    used_m = m;
+
+  /* If this is smaller than SImode, we'll have to use SImode with
+     adjustments.  */
+  if (mode == QImode || mode == HImode)
+    {
+      rtx newop, oldop;
+
+      if (MEM_ALIGN (used_m) >= 32)
+       {
+         int ishift = 0;
+         if (BYTES_BIG_ENDIAN)
+           ishift = GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (mode);
+
+         shift = GEN_INT (ishift);
+       }
+      else
+       {
+         rtx addrSI, aligned_addr;
+         int shift_mask = mode == QImode ? 0x18 : 0x10;
+
+         addrSI = force_reg (SImode, gen_lowpart_common (SImode,
+                                                         XEXP (used_m, 0)));
+         shift = gen_reg_rtx (SImode);
+
+         emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
+                                GEN_INT (shift_mask)));
+         emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
+
+         aligned_addr = expand_binop (Pmode, and_optab,
+                                      XEXP (used_m, 0),
+                                      GEN_INT (-4), NULL_RTX,
+                                      1, OPTAB_LIB_WIDEN);
+         used_m = change_address (used_m, SImode, aligned_addr);
+         set_mem_align (used_m, 32);
+         /* It's safe to keep the old alias set of USED_M, because
+            the operation is atomic and only affects the original
+            USED_M.  */
+         if (GET_CODE (m) == NOT)
+           m = gen_rtx_NOT (SImode, used_m);
+         else
+           m = used_m;
+       }
+
+      if (GET_CODE (op) == NOT)
+       {
+         oldop = lowpart_subreg (SImode, XEXP (op, 0), mode);
+         oldop = gen_rtx_NOT (SImode, oldop);
+       }
+      else
+       oldop = lowpart_subreg (SImode, op, mode);
+
+      switch (code)
+       {
+       case IOR:
+       case XOR:
+         newop = expand_binop (SImode, and_optab,
+                               oldop, GEN_INT (imask), NULL_RTX,
+                               1, OPTAB_LIB_WIDEN);
+         emit_insn (gen_ashlsi3 (newop, newop, shift));
+         break;
+
+       case AND:
+         newop = expand_binop (SImode, ior_optab,
+                               oldop, GEN_INT (~imask), NULL_RTX,
+                               1, OPTAB_LIB_WIDEN);
+         emit_insn (gen_rotlsi3 (newop, newop, shift));
+         break;
+
+       case PLUS:
+       case MINUS:
+         {
+           rtx mask;
+
+           newop = expand_binop (SImode, and_optab,
+                                 oldop, GEN_INT (imask), NULL_RTX,
+                                 1, OPTAB_LIB_WIDEN);
+           emit_insn (gen_ashlsi3 (newop, newop, shift));
+
+           mask = gen_reg_rtx (SImode);
+           emit_move_insn (mask, GEN_INT (imask));
+           emit_insn (gen_ashlsi3 (mask, mask, shift));
+
+           if (code == PLUS)
+             newop = gen_rtx_PLUS (SImode, m, newop);
+           else
+             newop = gen_rtx_MINUS (SImode, m, newop);
+           newop = gen_rtx_AND (SImode, newop, mask);
+           newop = gen_rtx_IOR (SImode, newop,
+                                gen_rtx_AND (SImode,
+                                             gen_rtx_NOT (SImode, mask),
+                                             m));
+           break;
+         }
+
+       default:
+         gcc_unreachable ();
+       }
+
+      if (GET_CODE (m) == NOT)
+       {
+         rtx mask, xorm;
+
+         mask = gen_reg_rtx (SImode);
+         emit_move_insn (mask, GEN_INT (imask));
+         emit_insn (gen_ashlsi3 (mask, mask, shift));
+
+         xorm = gen_rtx_XOR (SImode, used_m, mask);
+         /* Depending on the value of 'op', the XOR or the operation might
+            be able to be simplified away.  */
+         newop = simplify_gen_binary (code, SImode, xorm, newop);
+       }
+      op = newop;
+      used_mode = SImode;
+      before = gen_reg_rtx (used_mode);
+      after = gen_reg_rtx (used_mode);
+    }
+  else
+    {
+      used_mode = mode;
+      before = before_param;
+      after = after_param;
+
+      if (before == NULL_RTX)
+       before = gen_reg_rtx (used_mode);
+      if (after == NULL_RTX)
+       after = gen_reg_rtx (used_mode);
+    }
+
+  if ((code == PLUS || code == MINUS || GET_CODE (m) == NOT)
+      && used_mode != mode)
+    the_op = op;  /* Computed above.  */
+  else if (GET_CODE (op) == NOT && GET_CODE (m) != NOT)
+    the_op = gen_rtx_fmt_ee (code, used_mode, op, m);
+  else
+    the_op = gen_rtx_fmt_ee (code, used_mode, m, op);
+
+  set_after = gen_rtx_SET (VOIDmode, after, the_op);
+  set_before = gen_rtx_SET (VOIDmode, before, used_m);
+  set_atomic = gen_rtx_SET (VOIDmode, used_m,
+                           gen_rtx_UNSPEC (used_mode,
+                                           gen_rtvec (1, the_op),
+                                           UNSPEC_SYNC_OP));
+  cc_scratch = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (CCmode));
+
+  if ((code == PLUS || code == MINUS) && used_mode != mode)
+    vec = gen_rtvec (5, set_after, set_before, set_atomic, cc_scratch,
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (SImode)));
+  else
+    vec = gen_rtvec (4, set_after, set_before, set_atomic, cc_scratch);
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+
+  /* Shift and mask the return values properly.  */
+  if (used_mode != mode && before_param)
+    {
+      emit_insn (gen_lshrsi3 (before, before, shift));
+      convert_move (before_param, before, 1);
+    }
+
+  if (used_mode != mode && after_param)
+    {
+      emit_insn (gen_lshrsi3 (after, after, shift));
+      convert_move (after_param, after, 1);
+    }
+
+  /* The previous sequence will end with a branch that's dependent on
+     the conditional store, so placing an isync will ensure that no
+     other instructions (especially, no load or store instructions)
+     can start before the atomic operation completes.  */
+  if (sync_p)
+    emit_insn (gen_isync ());
+}
+
+/* A subroutine of the atomic operation splitters.  Jump to LABEL if
+   COND is true.  Mark the jump as unlikely to be taken.  */
+
+static void
+emit_unlikely_jump (rtx cond, rtx label)
+{
+  rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
+  rtx x;
+
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, label, pc_rtx);
+  x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
+  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
+}
+
+/* A subroutine of the atomic operation splitters.  Emit a load-locked
+   instruction in MODE.  */
 
-    case GT:
-      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
-      temp = gen_reg_rtx (result_mode);
-      emit_insn (gen_rtx_SET (VOIDmode, temp,
-                             gen_rtx_IF_THEN_ELSE (result_mode,
-                                                   gen_rtx_GE (VOIDmode,
-                                                               op0, op1),
-                                                   true_cond, false_cond)));
-      true_cond = false_cond;
-      false_cond = temp;
+static void
+emit_load_locked (enum machine_mode mode, rtx reg, rtx mem)
+{
+  rtx (*fn) (rtx, rtx) = NULL;
+  if (mode == SImode)
+    fn = gen_load_locked_si;
+  else if (mode == DImode)
+    fn = gen_load_locked_di;
+  emit_insn (fn (reg, mem));
+}
 
-      temp = gen_reg_rtx (compare_mode);
-      emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
-      op0 = temp;
-      break;
+/* A subroutine of the atomic operation splitters.  Emit a store-conditional
+   instruction in MODE.  */
 
-    default:
-      abort ();
-    }
+static void
+emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
+{
+  rtx (*fn) (rtx, rtx, rtx) = NULL;
+  if (mode == SImode)
+    fn = gen_store_conditional_si;
+  else if (mode == DImode)
+    fn = gen_store_conditional_di;
 
-  emit_insn (gen_rtx_SET (VOIDmode, dest,
-                         gen_rtx_IF_THEN_ELSE (result_mode,
-                                               gen_rtx_GE (VOIDmode,
-                                                           op0, op1),
-                                               true_cond, false_cond)));
-  return 1;
+  /* Emit sync before stwcx. to address PPC405 Erratum.  */
+  if (PPC405_ERRATUM77)
+    emit_insn (gen_memory_barrier ());
+
+  emit_insn (fn (res, mem, val));
 }
 
-/* Same as above, but for ints (isel).  */
+/* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
+   to perform.  MEM is the memory on which to operate.  VAL is the second
+   operand of the binary operator.  BEFORE and AFTER are optional locations to
+   return the value of MEM either before of after the operation.  SCRATCH is
+   a scratch register.  */
 
-static int
-rs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
+void
+rs6000_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
+                       rtx before, rtx after, rtx scratch)
 {
-  rtx condition_rtx, cr;
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
 
-  /* All isel implementations thus far are 32-bits.  */
-  if (GET_MODE (rs6000_compare_op0) != SImode)
-    return 0;
+  emit_insn (gen_memory_barrier ());
 
-  /* 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);
+  label = gen_label_rtx ();
+  emit_label (label);
+  label = gen_rtx_LABEL_REF (VOIDmode, label);
 
-  if (GET_MODE (cr) == CCmode)
-    emit_insn (gen_isel_signed (dest, condition_rtx,
-                               true_cond, false_cond, cr));
+  if (before == NULL_RTX)
+    before = scratch;
+  emit_load_locked (mode, before, mem);
+
+  if (code == NOT)
+    x = gen_rtx_AND (mode, gen_rtx_NOT (mode, before), val);
+  else if (code == AND)
+    x = gen_rtx_UNSPEC (mode, gen_rtvec (2, before, val), UNSPEC_AND);
   else
-    emit_insn (gen_isel_unsigned (dest, condition_rtx,
-                                 true_cond, false_cond, cr));
+    x = gen_rtx_fmt_ee (code, mode, before, val);
 
-  return 1;
+  if (after != NULL_RTX)
+    emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
+  emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label);
+
+  emit_insn (gen_isync ());
 }
 
-const char *
-output_isel (rtx *operands)
+/* Expand an atomic compare and swap operation.  MEM is the memory on which
+   to operate.  OLDVAL is the old value to be compared.  NEWVAL is the new
+   value to be stored.  SCRATCH is a scratch GPR.  */
+
+void
+rs6000_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
+                              rtx scratch)
 {
-  enum rtx_code code;
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
 
-  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";
+  emit_insn (gen_memory_barrier ());
+
+  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  emit_label (XEXP (label1, 0));
+
+  emit_load_locked (mode, retval, mem);
+
+  x = gen_rtx_COMPARE (CCmode, retval, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label2);
+
+  emit_move_insn (scratch, newval);
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label1);
+
+  emit_insn (gen_isync ());
+  emit_label (XEXP (label2, 0));
 }
 
+/* Expand an atomic test and set operation.  MEM is the memory on which
+   to operate.  VAL is the value set.  SCRATCH is a scratch GPR.  */
+
 void
-rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
+rs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
 {
-  enum machine_mode mode = GET_MODE (op0);
-  enum rtx_code c;
-  rtx target;
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
 
-  if (code == SMAX || code == SMIN)
-    c = GE;
-  else
-    c = GEU;
+  emit_insn (gen_memory_barrier ());
 
-  if (code == SMAX || code == UMAX)
-    target = emit_conditional_move (dest, c, op0, op1, mode,
-                                   op0, op1, mode, 0);
-  else
-    target = emit_conditional_move (dest, c, op0, op1, mode,
-                                   op1, op0, mode, 0);
-  if (target == NULL_RTX)
-    abort ();
-  if (target != dest)
-    emit_move_insn (dest, target);
+  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  emit_label (XEXP (label, 0));
+
+  emit_load_locked (mode, retval, mem);
+  emit_move_insn (scratch, val);
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label);
+
+  emit_insn (gen_isync ());
 }
 
-/* Emit instructions to move SRC to DST.  Called by splitters for
+  /* Emit instructions to move SRC to DST.  Called by splitters for
    multi-register moves.  It will emit at most one instruction for
    each register that is accessed; that is, it won't emit li/lis pairs
    (or equivalent for 64-bit code).  One of SRC or DST must be a hard
@@ -10966,7 +12217,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
 
   reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
   mode = GET_MODE (dst);
-  nregs = HARD_REGNO_NREGS (reg, mode);
+  nregs = hard_regno_nregs[reg][mode];
   if (FP_REGNO_P (reg))
     reg_mode = DFmode;
   else if (ALTIVEC_REGNO_P (reg))
@@ -10975,8 +12226,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
     reg_mode = word_mode;
   reg_mode_size = GET_MODE_SIZE (reg_mode);
 
-  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
-    abort ();
+  gcc_assert (reg_mode_size * nregs == GET_MODE_SIZE (mode));
 
   if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
     {
@@ -11011,16 +12261,14 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              emit_insn (TARGET_32BIT
                         ? gen_addsi3 (breg, breg, delta_rtx)
                         : gen_adddi3 (breg, breg, delta_rtx));
-             src = gen_rtx_MEM (mode, breg);
+             src = replace_equiv_address (src, breg);
            }
          else if (! offsettable_memref_p (src))
            {
-             rtx newsrc, basereg;
+             rtx basereg;
              basereg = gen_rtx_REG (Pmode, reg);
              emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
-             newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
-             MEM_COPY_ATTRIBUTES (newsrc, src);
-             src = newsrc;
+             src = replace_equiv_address (src, basereg);
            }
 
          breg = XEXP (src, 0);
@@ -11065,10 +12313,10 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                emit_insn (TARGET_32BIT
                           ? gen_addsi3 (breg, breg, delta_rtx)
                           : gen_adddi3 (breg, breg, delta_rtx));
-             dst = gen_rtx_MEM (mode, breg);
+             dst = replace_equiv_address (dst, breg);
            }
-         else if (! offsettable_memref_p (dst))
-           abort ();
+         else
+           gcc_assert (offsettable_memref_p (dst));
        }
 
       for (i = 0; i < nregs; i++)
@@ -11238,10 +12486,10 @@ compute_save_world_info (rs6000_stack_t *info_ptr)
 
       /* Because the Darwin register save/restore routines only handle
         F14 .. F31 and V20 .. V31 as per the ABI, perform a consistency
-        check and abort if there's something worng.  */
-      if (info_ptr->first_fp_reg_save < FIRST_SAVED_FP_REGNO
-         || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO)
-       abort ();
+        check.  */
+      gcc_assert (info_ptr->first_fp_reg_save >= FIRST_SAVED_FP_REGNO
+                 && (info_ptr->first_altivec_reg_save
+                     >= FIRST_SAVED_ALTIVEC_REGNO));
     }
   return;
 }
@@ -11428,9 +12676,6 @@ rs6000_stack_info (void)
          && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
       || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
       || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
-      || (DEFAULT_ABI == ABI_DARWIN
-         && flag_pic
-         && current_function_uses_pic_offset_table)
       || info_ptr->calls_p)
     {
       info_ptr->lr_save_p = 1;
@@ -11467,10 +12712,16 @@ rs6000_stack_info (void)
   /* Determine various sizes.  */
   info_ptr->reg_size     = reg_size;
   info_ptr->fixed_size   = RS6000_SAVE_AREA;
-  info_ptr->varargs_size = RS6000_VARARGS_AREA;
   info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
   info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
                                         TARGET_ALTIVEC ? 16 : 8);
+  if (FRAME_GROWS_DOWNWARD)
+    info_ptr->vars_size
+      += RS6000_ALIGN (info_ptr->fixed_size + info_ptr->vars_size
+                      + info_ptr->parm_size,
+                      ABI_STACK_BOUNDARY / BITS_PER_UNIT)
+        - (info_ptr->fixed_size + info_ptr->vars_size
+           + info_ptr->parm_size);
 
   if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
     info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
@@ -11494,7 +12745,7 @@ rs6000_stack_info (void)
     {
     case ABI_NONE:
     default:
-      abort ();
+      gcc_unreachable ();
 
     case ABI_AIX:
     case ABI_DARWIN:
@@ -11595,8 +12846,7 @@ rs6000_stack_info (void)
 
   non_fixed_size        = (info_ptr->vars_size
                            + info_ptr->parm_size
-                           + info_ptr->save_size
-                           + info_ptr->varargs_size);
+                           + info_ptr->save_size);
 
   info_ptr->total_size = RS6000_ALIGN (non_fixed_size + info_ptr->fixed_size,
                                       ABI_STACK_BOUNDARY / BITS_PER_UNIT);
@@ -11796,9 +13046,6 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
             info->total_size);
 
-  if (info->varargs_size)
-    fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
-
   if (info->vars_size)
     fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
             info->vars_size);
@@ -11910,6 +13157,24 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   return false;
 }
 
+/* NULL if INSN insn is valid within a low-overhead loop.
+   Otherwise return why doloop cannot be applied.
+   PowerPC uses the COUNT register for branch on table instructions.  */
+
+static const char *
+rs6000_invalid_within_doloop (rtx insn)
+{
+  if (CALL_P (insn))
+    return "Function call in the loop.";
+
+  if (JUMP_P (insn)
+      && (GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
+         || GET_CODE (PATTERN (insn)) == ADDR_VEC))
+    return "Computed branch in the loop.";
+
+  return NULL;
+}
+
 static int
 rs6000_ra_ever_killed (void)
 {
@@ -11977,15 +13242,49 @@ rs6000_emit_load_toc_table (int fromprolog)
   rtx dest, insn;
   dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
 
-  if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+  if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
+    {
+      char buf[30];
+      rtx lab, tmp1, tmp2, got, tempLR;
+
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+      lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+      if (flag_pic == 2)
+       got = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
+      else
+       got = rs6000_got_sym ();
+      tmp1 = tmp2 = dest;
+      if (!fromprolog)
+       {
+         tmp1 = gen_reg_rtx (Pmode);
+         tmp2 = gen_reg_rtx (Pmode);
+       }
+      tempLR = (fromprolog
+               ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
+               : gen_reg_rtx (Pmode));
+      insn = emit_insn (gen_load_toc_v4_PIC_1 (tempLR, lab));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+      insn = emit_move_insn (tmp1, tempLR);
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+      insn = emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+      insn = emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+    }
+  else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
     {
-      rtx temp = (fromprolog
-                 ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                 : gen_reg_rtx (Pmode));
-      insn = emit_insn (gen_load_toc_v4_pic_si (temp));
+      rtx tempLR = (fromprolog
+                   ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
+                   : gen_reg_rtx (Pmode));
+
+      insn = emit_insn (gen_load_toc_v4_pic_si (tempLR));
       if (fromprolog)
        rs6000_maybe_dead (insn);
-      insn = emit_move_insn (dest, temp);
+      insn = emit_move_insn (dest, tempLR);
       if (fromprolog)
        rs6000_maybe_dead (insn);
     }
@@ -11998,11 +13297,10 @@ rs6000_emit_load_toc_table (int fromprolog)
       rtx temp0 = (fromprolog
                   ? gen_rtx_REG (Pmode, 0)
                   : gen_reg_rtx (Pmode));
-      rtx symF;
 
       if (fromprolog)
        {
-         rtx symL;
+         rtx symF, symL;
 
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
          symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
@@ -12020,14 +13318,9 @@ rs6000_emit_load_toc_table (int fromprolog)
       else
        {
          rtx tocsym;
-         static int reload_toc_labelno = 0;
 
          tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
-
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
-         symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-
-         emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym));
+         emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
          emit_move_insn (dest, tempLR);
          emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
        }
@@ -12050,8 +13343,10 @@ rs6000_emit_load_toc_table (int fromprolog)
       if (fromprolog)
        rs6000_maybe_dead (insn);
     }
-  else if (DEFAULT_ABI == ABI_AIX)
+  else
     {
+      gcc_assert (DEFAULT_ABI == ABI_AIX);
+
       if (TARGET_32BIT)
        insn = emit_insn (gen_load_toc_aix_si (dest));
       else
@@ -12059,8 +13354,6 @@ rs6000_emit_load_toc_table (int fromprolog)
       if (fromprolog)
        rs6000_maybe_dead (insn);
     }
-  else
-    abort ();
 }
 
 /* Emit instructions to restore the link register after determining where
@@ -12085,7 +13378,10 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
          || current_function_calls_alloca
          || info->total_size > 32767)
        {
-         emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
+         tmp = gen_rtx_MEM (Pmode, frame_rtx);
+         MEM_NOTRAP_P (tmp) = 1;
+         set_mem_alias_set (tmp, rs6000_sr_alias_set);
+         emit_move_insn (operands[1], tmp);
          frame_rtx = operands[1];
        }
       else if (info->push_p)
@@ -12093,6 +13389,8 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
 
       tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
       tmp = gen_rtx_MEM (Pmode, tmp);
+      MEM_NOTRAP_P (tmp) = 1;
+      set_mem_alias_set (tmp, rs6000_sr_alias_set);
       emit_move_insn (tmp, operands[0]);
     }
   else
@@ -12165,12 +13463,12 @@ rs6000_aix_emit_builtin_unwind_init (void)
   rtx tocompare = gen_reg_rtx (SImode);
   rtx no_toc_save_needed = gen_label_rtx ();
 
-  mem = gen_rtx_MEM (Pmode, hard_frame_pointer_rtx);
+  mem = gen_frame_mem (Pmode, hard_frame_pointer_rtx);
   emit_move_insn (stack_top, mem);
 
-  mem = gen_rtx_MEM (Pmode,
-                    gen_rtx_PLUS (Pmode, stack_top,
-                                  GEN_INT (2 * GET_MODE_SIZE (Pmode))));
+  mem = gen_frame_mem (Pmode,
+                      gen_rtx_PLUS (Pmode, stack_top,
+                                    GEN_INT (2 * GET_MODE_SIZE (Pmode))));
   emit_move_insn (opcode_addr, mem);
   emit_move_insn (opcode, gen_rtx_MEM (SImode, opcode_addr));
   emit_move_insn (tocompare, gen_int_mode (TARGET_32BIT ? 0x80410014
@@ -12180,9 +13478,9 @@ rs6000_aix_emit_builtin_unwind_init (void)
                           SImode, NULL_RTX, NULL_RTX,
                           no_toc_save_needed);
 
-  mem = gen_rtx_MEM (Pmode,
-                    gen_rtx_PLUS (Pmode, stack_top,
-                                  GEN_INT (5 * GET_MODE_SIZE (Pmode))));
+  mem = gen_frame_mem (Pmode,
+                      gen_rtx_PLUS (Pmode, stack_top,
+                                    GEN_INT (5 * GET_MODE_SIZE (Pmode))));
   emit_move_insn (mem, gen_rtx_REG (Pmode, 2));
   emit_label (no_toc_save_needed);
 }
@@ -12213,7 +13511,7 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
 
   if (INTVAL (todec) != -size)
     {
-      warning ("stack frame too large");
+      warning (0, "stack frame too large");
       emit_insn (gen_trap ());
       return;
     }
@@ -12250,7 +13548,7 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
                                    const0_rtx));
        }
       else
-       warning ("stack limit expression is not supported");
+       warning (0, "stack limit expression is not supported");
     }
 
   if (copy_r12 || ! TARGET_UPDATE)
@@ -12343,9 +13641,11 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
            XEXP (SET_DEST (set), 0) = temp;
        }
     }
-  else if (GET_CODE (real) == PARALLEL)
+  else
     {
       int i;
+
+      gcc_assert (GET_CODE (real) == PARALLEL);
       for (i = 0; i < XVECLEN (real, 0); i++)
        if (GET_CODE (XVECEXP (real, 0, i)) == SET)
          {
@@ -12366,8 +13666,6 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
            RTX_FRAME_RELATED_P (set) = 1;
          }
     }
-  else
-    abort ();
 
   if (TARGET_SPE)
     real = spe_synthesize_frame_save (real);
@@ -12396,10 +13694,9 @@ spe_synthesize_frame_save (rtx real)
      This is so we can differentiate between 64-bit and 32-bit saves.
      Words cannot describe this nastiness.  */
 
-  if (GET_CODE (SET_DEST (real)) != MEM
-      || GET_CODE (XEXP (SET_DEST (real), 0)) != PLUS
-      || GET_CODE (SET_SRC (real)) != REG)
-    abort ();
+  gcc_assert (GET_CODE (SET_DEST (real)) == MEM
+             && GET_CODE (XEXP (SET_DEST (real), 0)) == PLUS
+             && GET_CODE (SET_SRC (real)) == REG);
 
   /* Transform:
        (set (mem (plus (reg x) (const y)))
@@ -12456,7 +13753,7 @@ generate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
                   vrsave,
                   gen_rtx_UNSPEC_VOLATILE (SImode,
                                            gen_rtvec (2, reg, vrsave),
-                                           30));
+                                           UNSPECV_SET_VRSAVE));
 
   nclobs = 1;
 
@@ -12566,6 +13863,19 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
   return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
 }
 
+/* Look for user-defined global regs.  We should not save and restore these,
+   and cannot use stmw/lmw if there are any in its range.  */
+
+static bool
+no_global_regs_above (int first_greg)
+{
+  int i;
+  for (i = 0; i < 32 - first_greg; i++)
+    if (global_regs[first_greg + i])
+      return false;
+  return true;
+}
+
 #ifndef TARGET_FIX_AND_CONTINUE
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
@@ -12590,7 +13900,7 @@ rs6000_emit_prologue (void)
   if (TARGET_FIX_AND_CONTINUE)
     {
       /* gdb on darwin arranges to forward a function from the old
-        address by modifying the first 4 instructions of the function
+        address by modifying the first 5 instructions of the function
         to branch to the overriding function.  This is necessary to
         permit function pointers that point to the old function to
         actually forward to the new function.  */
@@ -12598,6 +13908,7 @@ rs6000_emit_prologue (void)
       emit_insn (gen_nop ());
       emit_insn (gen_nop ());
       emit_insn (gen_nop ());
+      emit_insn (gen_nop ());
     }
 
   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
@@ -12609,7 +13920,8 @@ rs6000_emit_prologue (void)
   using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
                          && (!TARGET_SPE_ABI
                              || info->spe_64bit_regs_used == 0)
-                         && info->first_gp_reg_save < 31);
+                         && info->first_gp_reg_save < 31
+                         && no_global_regs_above (info->first_gp_reg_save));
   saving_FPRs_inline = (info->first_fp_reg_save == 64
                        || FP_SAVE_INLINE (info->first_fp_reg_save)
                        || current_function_calls_eh_return
@@ -12652,17 +13964,17 @@ rs6000_emit_prologue (void)
 
       /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
         assumptions about the offsets of various bits of the stack
-        frame.  Abort if things aren't what they should be.  */
-      if (info->gp_save_offset != -220
-         || info->fp_save_offset != -144
-         || info->lr_save_offset != 8
-         || info->cr_save_offset != 4
-         || !info->push_p
-         || !info->lr_save_p
-         || (current_function_calls_eh_return && info->ehrd_offset != -432)
-         || (info->vrsave_save_offset != -224
-             || info->altivec_save_offset != (-224 -16 -192)))
-       abort ();
+        frame.  */
+      gcc_assert (info->gp_save_offset == -220
+                 && info->fp_save_offset == -144
+                 && info->lr_save_offset == 8
+                 && info->cr_save_offset == 4
+                 && info->push_p
+                 && info->lr_save_p
+                 && (!current_function_calls_eh_return
+                      || info->ehrd_offset == -432)
+                 && info->vrsave_save_offset == -224
+                 && info->altivec_save_offset == (-224 -16 -192));
 
       treg = gen_rtx_REG (SImode, 11);
       emit_move_insn (treg, GEN_INT (-info->total_size));
@@ -12797,7 +14109,7 @@ rs6000_emit_prologue (void)
      epilogue.  */
 
   if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && !WORLD_SAVE_P (info) && info->vrsave_mask != 0)
+      && info->vrsave_mask != 0)
     {
       rtx reg, mem, vrsave;
       int offset;
@@ -12812,13 +14124,16 @@ rs6000_emit_prologue (void)
       else
        emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
 
-      /* Save VRSAVE.  */
-      offset = info->vrsave_save_offset + sp_offset;
-      mem
-       = gen_rtx_MEM (SImode,
-                      gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset)));
-      set_mem_alias_set (mem, rs6000_sr_alias_set);
-      insn = emit_move_insn (mem, reg);
+      if (!WORLD_SAVE_P (info))
+       {
+          /* Save VRSAVE.  */
+          offset = info->vrsave_save_offset + sp_offset;
+          mem
+           = gen_rtx_MEM (SImode,
+                          gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (offset)));
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+          insn = emit_move_insn (mem, reg);
+       }
 
       /* Include the registers in the mask.  */
       emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
@@ -12930,12 +14245,12 @@ rs6000_emit_prologue (void)
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       if ((regs_ever_live[info->first_gp_reg_save+i]
-            && (! call_used_regs[info->first_gp_reg_save+i]
-                || (i+info->first_gp_reg_save
+       if ((regs_ever_live[info->first_gp_reg_save + i]
+            && (!call_used_regs[info->first_gp_reg_save + i]
+                || (i + info->first_gp_reg_save
                     == RS6000_PIC_OFFSET_TABLE_REGNUM
                     && TARGET_TOC && TARGET_MINIMAL_TOC)))
-           || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
+           || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
                && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
          {
@@ -13075,14 +14390,15 @@ rs6000_emit_prologue (void)
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
     {
-      insn = emit_move_insn (gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),
+      insn = emit_move_insn (gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM),
                             sp_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
   /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
   if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
-      || (DEFAULT_ABI == ABI_V4 && flag_pic == 1
+      || (DEFAULT_ABI == ABI_V4
+         && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
          && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
     {
       /* If emit_load_toc_table will use the link register, we need to save
@@ -13119,12 +14435,19 @@ rs6000_emit_prologue (void)
       rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
       rtx src = machopic_function_base_sym ();
 
+      /* Save and restore LR locally around this call (in R0).  */
+      if (!info->lr_save_p)
+       rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), lr));
+
       rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
 
       insn = emit_move_insn (gen_rtx_REG (Pmode,
                                          RS6000_PIC_OFFSET_TABLE_REGNUM),
                             lr);
       rs6000_maybe_dead (insn);
+
+      if (!info->lr_save_p)
+       rs6000_maybe_dead (emit_move_insn (lr, gen_rtx_REG (Pmode, 0)));
     }
 #endif
 }
@@ -13184,7 +14507,7 @@ rs6000_output_function_prologue (FILE *file,
 
       if (TARGET_DEBUG_STACK)
        debug_rtx_list (get_insns (), 100);
-      final (get_insns (), file, FALSE, FALSE);
+      final (get_insns (), file, FALSE);
       end_sequence ();
     }
 
@@ -13224,7 +14547,8 @@ rs6000_emit_epilogue (int sibcall)
   using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
                         && (!TARGET_SPE_ABI
                             || info->spe_64bit_regs_used == 0)
-                        && info->first_gp_reg_save < 31);
+                        && info->first_gp_reg_save < 31
+                        && no_global_regs_above (info->first_gp_reg_save));
   restoring_FPRs_inline = (sibcall
                           || current_function_calls_eh_return
                           || info->first_fp_reg_save == 64
@@ -13488,11 +14812,11 @@ rs6000_emit_epilogue (int sibcall)
     }
   else
     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-      if ((regs_ever_live[info->first_gp_reg_save+i]
-          && (! call_used_regs[info->first_gp_reg_save+i]
-              || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
+      if ((regs_ever_live[info->first_gp_reg_save + i]
+          && (!call_used_regs[info->first_gp_reg_save + i]
+              || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
                   && TARGET_TOC && TARGET_MINIMAL_TOC)))
-         || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
+         || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
              && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
        {
@@ -13556,8 +14880,7 @@ rs6000_emit_epilogue (int sibcall)
          for (i = 0; i < 8; i++)
            if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
              count++;
-         if (count == 0)
-           abort ();
+         gcc_assert (count);
        }
 
       if (using_mfcr_multiple && count > 1)
@@ -13580,8 +14903,7 @@ rs6000_emit_epilogue (int sibcall)
                ndx++;
              }
          emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
-         if (ndx != count)
-           abort ();
+         gcc_assert (ndx == count);
        }
       else
        for (i = 0; i < 8; i++)
@@ -13714,7 +15036,7 @@ rs6000_output_function_epilogue (FILE *file,
 
          if (TARGET_DEBUG_STACK)
            debug_rtx_list (get_insns (), 100);
-         final (get_insns (), file, FALSE, FALSE);
+         final (get_insns (), file, FALSE);
          end_sequence ();
        }
     }
@@ -13816,7 +15138,7 @@ rs6000_output_function_epilogue (FILE *file,
       else if (! strcmp (language_string, "GNU Objective-C"))
        i = 14;
       else
-       abort ();
+       gcc_unreachable ();
       fprintf (file, "%d,", i);
 
       /* 8 single bit fields: global linkage (not set for C extern linkage,
@@ -13869,12 +15191,20 @@ rs6000_output_function_epilogue (FILE *file,
 
                      float_parms++;
 
-                     if (mode == SFmode)
-                       bits = 0x2;
-                     else if (mode == DFmode || mode == TFmode)
-                       bits = 0x3;
-                     else
-                       abort ();
+                     switch (mode)
+                       {
+                       case SFmode:
+                         bits = 0x2;
+                         break;
+
+                       case DFmode:
+                       case TFmode:
+                         bits = 0x3;
+                         break;
+
+                       default:
+                         gcc_unreachable ();
+                       }
 
                      /* If only one bit will fit, don't or in this entry.  */
                      if (next_parm_info_bit > 0)
@@ -14062,7 +15392,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 #endif
 
   /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
-     generate sibcall RTL explicitly to avoid constraint abort.  */
+     generate sibcall RTL explicitly.  */
   insn = emit_call_insn (
           gen_rtx_PARALLEL (VOIDmode,
             gen_rtvec (4,
@@ -14084,7 +15414,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn_locators_initialize ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
+  final (insn, file, 1);
   final_end_function ();
 
   reload_completed = 0;
@@ -14188,7 +15518,7 @@ rs6000_hash_constant (rtx k)
       case '0':
        break;
       default:
-       abort ();
+       gcc_unreachable ();
       }
 
   return result;
@@ -14258,10 +15588,9 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
   const char *name = buf;
   const char *real_name;
   rtx base = x;
-  int offset = 0;
+  HOST_WIDE_INT offset = 0;
 
-  if (TARGET_NO_TOC)
-    abort ();
+  gcc_assert (!TARGET_NO_TOC);
 
   /* When the linker won't eliminate them, don't output duplicate
      TOC entries (this happens on AIX if there is any kind of TOC,
@@ -14440,8 +15769,8 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
         For a 32-bit target, CONST_INT values are loaded and shifted
         entirely within `low' and can be stored in one TOC entry.  */
 
-      if (TARGET_64BIT && POINTER_SIZE < GET_MODE_BITSIZE (mode))
-       abort ();/* It would be easy to make this work, but it doesn't now.  */
+      /* It would be easy to make this work, but it doesn't now.  */
+      gcc_assert (!TARGET_64BIT || POINTER_SIZE >= GET_MODE_BITSIZE (mode));
 
       if (POINTER_SIZE > GET_MODE_BITSIZE (mode))
        {
@@ -14493,21 +15822,30 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
 
   if (GET_CODE (x) == CONST)
     {
-      if (GET_CODE (XEXP (x, 0)) != PLUS)
-       abort ();
+      gcc_assert (GET_CODE (XEXP (x, 0)) == PLUS);
 
       base = XEXP (XEXP (x, 0), 0);
       offset = INTVAL (XEXP (XEXP (x, 0), 1));
     }
 
-  if (GET_CODE (base) == SYMBOL_REF)
-    name = XSTR (base, 0);
-  else if (GET_CODE (base) == LABEL_REF)
-    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (XEXP (base, 0)));
-  else if (GET_CODE (base) == CODE_LABEL)
-    ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
-  else
-    abort ();
+  switch (GET_CODE (base))
+    {
+    case SYMBOL_REF:
+      name = XSTR (base, 0);
+      break;
+
+    case LABEL_REF:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L",
+                                  CODE_LABEL_NUMBER (XEXP (base, 0)));
+      break;
+
+    case CODE_LABEL:
+      ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (base));
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
 
   real_name = (*targetm.strip_name_encoding) (name);
   if (TARGET_MINIMAL_TOC)
@@ -14517,9 +15855,9 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
       fprintf (file, "\t.tc %s", real_name);
 
       if (offset < 0)
-       fprintf (file, ".N%d", - offset);
+       fprintf (file, ".N" HOST_WIDE_INT_PRINT_UNSIGNED, - offset);
       else if (offset)
-       fprintf (file, ".P%d", offset);
+       fprintf (file, ".P" HOST_WIDE_INT_PRINT_UNSIGNED, offset);
 
       fputs ("[TC],", file);
     }
@@ -14534,9 +15872,9 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
     {
       RS6000_OUTPUT_BASENAME (file, name);
       if (offset < 0)
-       fprintf (file, "%d", offset);
+       fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
       else if (offset > 0)
-       fprintf (file, "+%d", offset);
+       fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
     }
   else
     output_addr_const (file, x);
@@ -14669,6 +16007,10 @@ rs6000_gen_section_name (char **buf, const char *filename,
 void
 output_profile_hook (int labelno ATTRIBUTE_UNUSED)
 {
+  /* Non-standard profiling for kernels, which just saves LR then calls
+     _mcount without worrying about arg saves.  The idea is to change
+     the function prologue as little as possible as it isn't easy to
+     account for arg save/restore code added just for _mcount.  */
   if (TARGET_PROFILE_KERNEL)
     return;
 
@@ -14720,27 +16062,42 @@ void
 output_function_profiler (FILE *file, int labelno)
 {
   char buf[100];
-  int save_lr = 8;
 
   switch (DEFAULT_ABI)
     {
     default:
-      abort ();
+      gcc_unreachable ();
 
     case ABI_V4:
-      save_lr = 4;
       if (!TARGET_32BIT)
        {
-         warning ("no profiling of 64-bit code for this ABI");
+         warning (0, "no profiling of 64-bit code for this ABI");
          return;
        }
       ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
       fprintf (file, "\tmflr %s\n", reg_names[0]);
-      if (flag_pic == 1)
+      if (NO_PROFILE_COUNTERS)
+       {
+         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+                      reg_names[0], reg_names[1]);
+       }
+      else if (TARGET_SECURE_PLT && flag_pic)
+       {
+         asm_fprintf (file, "\tbcl 20,31,1f\n1:\n\t{st|stw} %s,4(%s)\n",
+                      reg_names[0], reg_names[1]);
+         asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
+         asm_fprintf (file, "\t{cau|addis} %s,%s,",
+                      reg_names[12], reg_names[12]);
+         assemble_name (file, buf);
+         asm_fprintf (file, "-1b@ha\n\t{cal|la} %s,", reg_names[0]);
+         assemble_name (file, buf);
+         asm_fprintf (file, "-1b@l(%s)\n", reg_names[12]);
+       }
+      else if (flag_pic == 1)
        {
          fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
-                      reg_names[0], save_lr, reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+                      reg_names[0], 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);
@@ -14748,10 +16105,10 @@ output_function_profiler (FILE *file, int labelno)
        }
       else if (flag_pic > 1)
        {
-         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
-                      reg_names[0], save_lr, reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+                      reg_names[0], reg_names[1]);
          /* Now, we need to get the address of the label.  */
-         fputs ("\tb1f\n\t.long ", file);
+         fputs ("\tbcl 20,31,1f\n\t.long ", file);
          assemble_name (file, buf);
          fputs ("-.\n1:", file);
          asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
@@ -14765,8 +16122,8 @@ output_function_profiler (FILE *file, int 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,%d(%s)\n",
-                      reg_names[0], save_lr, reg_names[1]);
+         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+                      reg_names[0], 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]);
@@ -14785,8 +16142,7 @@ output_function_profiler (FILE *file, int labelno)
        }
       else
        {
-         if (TARGET_32BIT)
-           abort ();
+         gcc_assert (!TARGET_32BIT);
 
          asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
          asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
@@ -14963,6 +16319,11 @@ is_dispatch_slot_restricted (rtx insn)
     case TYPE_IDIV:
     case TYPE_LDIV:
       return 2;
+    case TYPE_LOAD_L:
+    case TYPE_STORE_C:
+    case TYPE_ISYNC:
+    case TYPE_SYNC:
+      return 4;
     default:
       if (rs6000_cpu == PROCESSOR_POWER5
          && is_cracked_insn (insn))
@@ -15234,7 +16595,7 @@ static bool
 rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
                             int distance)
 {
-  /* If the flag is not enbled - no dependence is considered costly;
+  /* If the flag is not enabled - no dependence is considered costly;
      allow all dependent insns in the same group.
      This is the most aggressive option.  */
   if (rs6000_sched_costly_dep == no_dep_costly)
@@ -15276,26 +16637,24 @@ rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
 static rtx
 get_next_active_insn (rtx insn, rtx tail)
 {
-  rtx next_insn;
-
-  if (!insn || insn == tail)
+  if (insn == NULL_RTX || insn == tail)
     return NULL_RTX;
 
-  next_insn = NEXT_INSN (insn);
-
-  while (next_insn
-        && next_insn != tail
-        && (GET_CODE (next_insn) == NOTE
-            || GET_CODE (PATTERN (next_insn)) == USE
-            || GET_CODE (PATTERN (next_insn)) == CLOBBER))
+  while (1)
     {
-      next_insn = NEXT_INSN (next_insn);
-    }
-
-  if (!next_insn || next_insn == tail)
-    return NULL_RTX;
+      insn = NEXT_INSN (insn);
+      if (insn == NULL_RTX || insn == tail)
+       return NULL_RTX;
 
-  return next_insn;
+      if (CALL_P (insn)
+         || JUMP_P (insn)
+         || (NONJUMP_INSN_P (insn)
+             && GET_CODE (PATTERN (insn)) != USE
+             && GET_CODE (PATTERN (insn)) != CLOBBER
+             && INSN_CODE (insn) != CODE_FOR_stack_tie))
+       break;
+    }
+  return insn;
 }
 
 /* Return whether the presence of INSN causes a dispatch group termination
@@ -15511,7 +16870,7 @@ force_new_group (int sched_verbose, FILE *dump, rtx *group_insns,
    between the insns.
 
    The function estimates the group boundaries that the processor will form as
-   folllows:  It keeps track of how many vacant issue slots are available after
+   follows:  It keeps track of how many vacant issue slots are available after
    each insn.  A subsequent insn will start a new group if one of the following
    4 cases applies:
    - no more vacant issue slots remain in the current dispatch group.
@@ -15704,7 +17063,7 @@ rs6000_trampoline_size (void)
   switch (DEFAULT_ABI)
     {
     default:
-      abort ();
+      gcc_unreachable ();
 
     case ABI_AIX:
       ret = (TARGET_32BIT) ? 12 : 24;
@@ -15733,7 +17092,7 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
   switch (DEFAULT_ABI)
     {
     default:
-      abort ();
+      gcc_unreachable ();
 
 /* Macros to shorten the code expansions below.  */
 #define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
@@ -15823,7 +17182,7 @@ rs6000_handle_altivec_attribute (tree *node,
     if (TARGET_64BIT)
       error ("use of %<long%> in AltiVec types is invalid for 64-bit code");
     else if (rs6000_warn_altivec_long)
-      warning ("use of %<long%> in AltiVec types is deprecated; use %<int%>");
+      warning (0, "use of %<long%> in AltiVec types is deprecated; use %<int%>");
     }
   else if (type == long_long_unsigned_type_node
            || type == long_long_integer_type_node)
@@ -15918,7 +17277,7 @@ rs6000_handle_longcall_attribute (tree *node, tree name,
       && TREE_CODE (*node) != FIELD_DECL
       && TREE_CODE (*node) != TYPE_DECL)
     {
-      warning ("%qs attribute only applies to functions",
+      warning (OPT_Wattributes, "%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
@@ -16113,11 +17472,10 @@ find_addr_reg (rtx addr)
       else if (CONSTANT_P (XEXP (addr, 1)))
        addr = XEXP (addr, 0);
       else
-       abort ();
+       gcc_unreachable ();
     }
-  if (GET_CODE (addr) == REG && REGNO (addr) != 0)
-    return addr;
-  abort ();
+  gcc_assert (GET_CODE (addr) == REG && REGNO (addr) != 0);
+  return addr;
 }
 
 void
@@ -16335,7 +17693,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
 
       label++;
-      local_label_0 = alloca (sizeof ("\"L0000000000$spb\""));
+      local_label_0 = alloca (sizeof ("\"L00000000000$spb\""));
       sprintf (local_label_0, "\"L%011d$spb\"", label);
 
       fprintf (file, "\tmflr r0\n");
@@ -16390,25 +17748,22 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
 
   if (GET_CODE (orig) == CONST)
     {
+      rtx reg_temp;
+
       if (GET_CODE (XEXP (orig, 0)) == PLUS
          && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
        return orig;
 
-      if (GET_CODE (XEXP (orig, 0)) == PLUS)
-       {
-         /* Use a different reg for the intermediate value, as
-            it will be marked UNCHANGING.  */
-         rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
 
-         base =
-           rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
-                                                   Pmode, reg_temp);
-         offset =
-           rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
-                                                   Pmode, reg);
-       }
-      else
-       abort ();
+      /* Use a different reg for the intermediate value, as
+        it will be marked UNCHANGING.  */
+      reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+      base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
+                                                    Pmode, reg_temp);
+      offset =
+       rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+                                               Pmode, reg);
 
       if (GET_CODE (offset) == CONST_INT)
        {
@@ -16599,6 +17954,7 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
     }
 
   if (TARGET_RELOCATABLE
+      && !TARGET_SECURE_PLT
       && (get_pool_size () != 0 || current_function_profile)
       && uses_TOC ())
     {
@@ -16640,6 +17996,13 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
     }
   ASM_OUTPUT_LABEL (file, name);
 }
+
+static void
+rs6000_elf_end_indicate_exec_stack (void)
+{
+  if (TARGET_32BIT)
+    file_end_indicate_exec_stack ();
+}
 #endif
 
 #if TARGET_XCOFF
@@ -16808,17 +18171,6 @@ rs6000_xcoff_file_end (void)
 }
 #endif /* TARGET_XCOFF */
 
-#if TARGET_MACHO
-/* Cross-module name binding.  Darwin does not support overriding
-   functions at dynamic-link time.  */
-
-static bool
-rs6000_binds_local_p (tree decl)
-{
-  return default_binds_local_p_1 (decl, 0);
-}
-#endif
-
 /* Compute a (partial) cost for rtx X.  Return true if the complete
    cost has been computed, and false if subexpressions should be
    scanned.  In either case, *TOTAL contains the cost result.  */
@@ -16841,7 +18193,9 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                  || (CONST_OK_FOR_LETTER_P (INTVAL (x),
                                             mode == SImode ? 'L' : 'J'))
-                 || mask_operand (x, VOIDmode)))
+                 || mask_operand (x, mode)
+                 || (mode == DImode
+                     && mask64_operand (x, DImode))))
          || ((outer_code == IOR || outer_code == XOR)
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                  || (CONST_OK_FOR_LETTER_P (INTVAL (x),
@@ -16874,9 +18228,9 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          return true;
        }
       else if ((outer_code == PLUS
-               && reg_or_add_cint64_operand (x, VOIDmode))
+               && reg_or_add_cint_operand (x, VOIDmode))
               || (outer_code == MINUS
-                  && reg_or_sub_cint64_operand (x, VOIDmode))
+                  && reg_or_sub_cint_operand (x, VOIDmode))
               || ((outer_code == SET
                    || outer_code == IOR
                    || outer_code == XOR)
@@ -16893,6 +18247,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          && ((outer_code == AND
               && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
                   || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+                  || mask_operand (x, DImode)
                   || mask64_operand (x, DImode)))
              || ((outer_code == IOR || outer_code == XOR)
                  && CONST_DOUBLE_HIGH (x) == 0
@@ -16949,12 +18304,6 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          else
            *total = rs6000_cost->fp;
        }
-      else if (GET_CODE (XEXP (x, 0)) == MULT)
-       {
-         /* The rs6000 doesn't have shift-and-add instructions.  */
-         rs6000_rtx_costs (XEXP (x, 0), MULT, PLUS, total);
-         *total += COSTS_N_INSNS (1);
-       }
       else
        *total = COSTS_N_INSNS (1);
       return false;
@@ -16981,12 +18330,6 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          else
            *total = rs6000_cost->fp;
        }
-      else if (GET_CODE (XEXP (x, 0)) == MULT)
-       {
-         /* The rs6000 doesn't have shift-and-sub instructions.  */
-         rs6000_rtx_costs (XEXP (x, 0), MULT, MINUS, total);
-         *total += COSTS_N_INSNS (1);
-       }
       else
        *total = COSTS_N_INSNS (1);
       return false;
@@ -17111,11 +18454,17 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
     case UNSIGNED_FLOAT:
     case FIX:
     case UNSIGNED_FIX:
-    case FLOAT_EXTEND:
     case FLOAT_TRUNCATE:
       *total = rs6000_cost->fp;
       return false;
 
+    case FLOAT_EXTEND:
+      if (mode == DFmode)
+       *total = 0;
+      else
+       *total = rs6000_cost->fp;
+      return false;
+
     case UNSPEC:
       switch (XINT (x, 1))
        {
@@ -17217,7 +18566,7 @@ rs6000_register_move_cost (enum machine_mode mode,
 
       else
        /* A move will cost one instruction per GPR moved.  */
-       return 2 * HARD_REGNO_NREGS (0, mode);
+       return 2 * hard_regno_nregs[0][mode];
     }
 
   /* Moving between two similar registers is just one instruction.  */
@@ -17238,15 +18587,118 @@ rs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
                         int in ATTRIBUTE_UNUSED)
 {
   if (reg_classes_intersect_p (class, GENERAL_REGS))
-    return 4 * HARD_REGNO_NREGS (0, mode);
+    return 4 * hard_regno_nregs[0][mode];
   else if (reg_classes_intersect_p (class, FLOAT_REGS))
-    return 4 * HARD_REGNO_NREGS (32, mode);
+    return 4 * hard_regno_nregs[32][mode];
   else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
-    return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
+    return 4 * hard_regno_nregs[FIRST_ALTIVEC_REGNO][mode];
   else
     return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
 }
 
+/* Newton-Raphson approximation of single-precision floating point divide n/d.
+   Assumes no trapping math and finite arguments.  */
+
+void
+rs6000_emit_swdivsf (rtx res, rtx n, rtx d)
+{
+  rtx x0, e0, e1, y1, u0, v0, one;
+
+  x0 = gen_reg_rtx (SFmode);
+  e0 = gen_reg_rtx (SFmode);
+  e1 = gen_reg_rtx (SFmode);
+  y1 = gen_reg_rtx (SFmode);
+  u0 = gen_reg_rtx (SFmode);
+  v0 = gen_reg_rtx (SFmode);
+  one = force_reg (SFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, SFmode));
+
+  /* x0 = 1./d estimate */
+  emit_insn (gen_rtx_SET (VOIDmode, x0,
+                         gen_rtx_UNSPEC (SFmode, gen_rtvec (1, d),
+                                         UNSPEC_FRES)));
+  /* e0 = 1. - d * x0 */
+  emit_insn (gen_rtx_SET (VOIDmode, e0,
+                         gen_rtx_MINUS (SFmode, one,
+                                        gen_rtx_MULT (SFmode, d, x0))));
+  /* e1 = e0 + e0 * e0 */
+  emit_insn (gen_rtx_SET (VOIDmode, e1,
+                         gen_rtx_PLUS (SFmode,
+                                       gen_rtx_MULT (SFmode, e0, e0), e0)));
+  /* y1 = x0 + e1 * x0 */
+  emit_insn (gen_rtx_SET (VOIDmode, y1,
+                         gen_rtx_PLUS (SFmode,
+                                       gen_rtx_MULT (SFmode, e1, x0), x0)));
+  /* u0 = n * y1 */
+  emit_insn (gen_rtx_SET (VOIDmode, u0,
+                         gen_rtx_MULT (SFmode, n, y1)));
+  /* v0 = n - d * u0 */
+  emit_insn (gen_rtx_SET (VOIDmode, v0,
+                         gen_rtx_MINUS (SFmode, n,
+                                        gen_rtx_MULT (SFmode, d, u0))));
+  /* res = u0 + v0 * y1 */
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_PLUS (SFmode,
+                                       gen_rtx_MULT (SFmode, v0, y1), u0)));
+}
+
+/* Newton-Raphson approximation of double-precision floating point divide n/d.
+   Assumes no trapping math and finite arguments.  */
+
+void
+rs6000_emit_swdivdf (rtx res, rtx n, rtx d)
+{
+  rtx x0, e0, e1, e2, y1, y2, y3, u0, v0, one;
+
+  x0 = gen_reg_rtx (DFmode);
+  e0 = gen_reg_rtx (DFmode);
+  e1 = gen_reg_rtx (DFmode);
+  e2 = gen_reg_rtx (DFmode);
+  y1 = gen_reg_rtx (DFmode);
+  y2 = gen_reg_rtx (DFmode);
+  y3 = gen_reg_rtx (DFmode);
+  u0 = gen_reg_rtx (DFmode);
+  v0 = gen_reg_rtx (DFmode);
+  one = force_reg (DFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, DFmode));
+
+  /* x0 = 1./d estimate */
+  emit_insn (gen_rtx_SET (VOIDmode, x0,
+                         gen_rtx_UNSPEC (DFmode, gen_rtvec (1, d),
+                                         UNSPEC_FRES)));
+  /* e0 = 1. - d * x0 */
+  emit_insn (gen_rtx_SET (VOIDmode, e0,
+                         gen_rtx_MINUS (DFmode, one,
+                                        gen_rtx_MULT (SFmode, d, x0))));
+  /* y1 = x0 + e0 * x0 */
+  emit_insn (gen_rtx_SET (VOIDmode, y1,
+                         gen_rtx_PLUS (DFmode,
+                                       gen_rtx_MULT (DFmode, e0, x0), x0)));
+  /* e1 = e0 * e0 */
+  emit_insn (gen_rtx_SET (VOIDmode, e1,
+                         gen_rtx_MULT (DFmode, e0, e0)));
+  /* y2 = y1 + e1 * y1 */
+  emit_insn (gen_rtx_SET (VOIDmode, y2,
+                         gen_rtx_PLUS (DFmode,
+                                       gen_rtx_MULT (DFmode, e1, y1), y1)));
+  /* e2 = e1 * e1 */
+  emit_insn (gen_rtx_SET (VOIDmode, e2,
+                         gen_rtx_MULT (DFmode, e1, e1)));
+  /* y3 = y2 + e2 * y2 */
+  emit_insn (gen_rtx_SET (VOIDmode, y3,
+                         gen_rtx_PLUS (DFmode,
+                                       gen_rtx_MULT (DFmode, e2, y2), y2)));
+  /* u0 = n * y3 */
+  emit_insn (gen_rtx_SET (VOIDmode, u0,
+                         gen_rtx_MULT (DFmode, n, y3)));
+  /* v0 = n - d * u0 */
+  emit_insn (gen_rtx_SET (VOIDmode, v0,
+                         gen_rtx_MINUS (DFmode, n,
+                                        gen_rtx_MULT (DFmode, d, u0))));
+  /* res = u0 + v0 * y3 */
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_PLUS (DFmode,
+                                       gen_rtx_MULT (DFmode, v0, y3), u0)));
+}
+
 /* Return an RTX representing where to find the function value of a
    function returning MODE.  */
 static rtx
@@ -17327,7 +18779,26 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
                                                   GP_ARG_RETURN + 1),
                                      GEN_INT (4))));
     }
-
+  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DCmode)
+    {
+      return gen_rtx_PARALLEL (DCmode,
+       gen_rtvec (4,
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
+                                     const0_rtx),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 1),
+                                     GEN_INT (4)),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 2),
+                                     GEN_INT (8)),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 3),
+                                     GEN_INT (12))));
+    }
   if ((INTEGRAL_TYPE_P (valtype)
        && TYPE_PRECISION (valtype) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
@@ -17399,29 +18870,39 @@ rs6000_initial_elimination_offset (int from, int to)
   rs6000_stack_t *info = rs6000_stack_info ();
   HOST_WIDE_INT offset;
 
-  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+  if (from == HARD_FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     offset = info->push_p ? 0 : -info->total_size;
-  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+  else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    {
+      offset = info->push_p ? 0 : -info->total_size;
+      if (FRAME_GROWS_DOWNWARD)
+       offset += info->fixed_size + info->vars_size + info->parm_size;
+    }
+  else if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    offset = FRAME_GROWS_DOWNWARD
+            ? info->fixed_size + info->vars_size + info->parm_size
+            : 0;
+  else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
     offset = info->total_size;
   else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     offset = info->push_p ? info->total_size : 0;
   else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
     offset = 0;
   else
-    abort ();
+    gcc_unreachable ();
 
   return offset;
 }
 
-/* Return true if TYPE is of type __ev64_opaque__.  */
+/* Return true if TYPE is a SPE or AltiVec opaque type.  */
 
 static bool
-is_ev64_opaque_type (tree type)
+rs6000_is_opaque_type (tree type)
 {
-  return (TARGET_SPE
-         && (type == opaque_V2SI_type_node
+  return (type == opaque_V2SI_type_node
              || type == opaque_V2SF_type_node
-             || type == opaque_p_V2SI_type_node));
+             || type == opaque_p_V2SI_type_node
+             || type == opaque_V4SI_type_node);
 }
 
 static rtx
@@ -17481,10 +18962,8 @@ rs6000_dbx_register_number (unsigned int regno)
     return 612;
   /* SPE high reg number.  We get these values of regno from
      rs6000_dwarf_register_span.  */
-  if (regno >= 1200 && regno < 1232)
-    return regno;
-
-  abort ();
+  gcc_assert (regno >= 1200 && regno < 1232);
+  return regno;
 }
 
 /* target hook eh_return_filter_mode */
@@ -17509,8 +18988,8 @@ rs6000_vector_mode_supported_p (enum machine_mode mode)
     return false;
 }
 
-/* Target hook for invalid_arg_for_unprototyped_fn. */ 
-static const char * 
+/* Target hook for invalid_arg_for_unprototyped_fn. */
+static const char *
 invalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
 {
   return (!rs6000_darwin64_abi
@@ -17523,4 +19002,17 @@ invalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
          : NULL;
 }
 
+/* For TARGET_SECURE_PLT 32-bit PIC code we can save PIC register
+   setup by using __stack_chk_fail_local hidden function instead of
+   calling __stack_chk_fail directly.  Otherwise it is better to call
+   __stack_chk_fail directly.  */
+
+static tree
+rs6000_stack_protect_fail (void)
+{
+  return (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
+        ? default_hidden_stack_protect_fail ()
+        : default_external_stack_protect_fail ();
+}
+
 #include "gt-rs6000.h"