hooks.c (hook_int_rtx_mode_as_bool_0): New function.
[platform/upstream/gcc.git] / gcc / config / rs6000 / rs6000.c
index 2996513..430125f 100644 (file)
@@ -1,7 +1,5 @@
 /* Subroutines used for code generation on IBM RS/6000.
-   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
-   Free Software Foundation, Inc.
+   Copyright (C) 1991-2012 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
    This file is part of GCC.
@@ -39,8 +37,8 @@
 #include "except.h"
 #include "function.h"
 #include "output.h"
+#include "dbxout.h"
 #include "basic-block.h"
-#include "integrate.h"
 #include "diagnostic-core.h"
 #include "toplev.h"
 #include "ggc.h"
@@ -51,7 +49,6 @@
 #include "common/common-target.h"
 #include "langhooks.h"
 #include "reload.h"
-#include "cfglayout.h"
 #include "cfgloop.h"
 #include "sched-int.h"
 #include "gimple.h"
@@ -60,6 +57,7 @@
 #include "params.h"
 #include "tm-constrs.h"
 #include "opts.h"
+#include "tree-vectorizer.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
@@ -215,10 +213,7 @@ static GTY(()) section *toc_section;
 
 struct builtin_description
 {
-  /* mask is not const because we're going to alter it below.  This
-     nonsense will go away when we rewrite the -march infrastructure
-     to give us more target flag bits.  */
-  unsigned int mask;
+  const unsigned int mask;
   const enum insn_code icode;
   const char *const name;
   const enum rs6000_builtins code;
@@ -289,6 +284,11 @@ static struct
 /* 2 argument gen function typedef.  */
 typedef rtx (*gen_2arg_fn_t) (rtx, rtx, rtx);
 
+/* Pointer to function (in rs6000-c.c) that can define or undefine target
+   macros that have changed.  Languages that don't support the preprocessor
+   don't link in rs6000-c.c, so we can't call it directly.  */
+void (*rs6000_target_modify_macros_ptr) (bool, int, unsigned);
+
 \f
 /* Target cpu costs.  */
 
@@ -352,44 +352,6 @@ struct processor_costs size64_cost = {
   0,
 };
 
-/* Instruction costs on RIOS1 processors.  */
-static const
-struct processor_costs rios1_cost = {
-  COSTS_N_INSNS (5),    /* mulsi */
-  COSTS_N_INSNS (4),    /* mulsi_const */
-  COSTS_N_INSNS (3),    /* mulsi_const9 */
-  COSTS_N_INSNS (5),    /* muldi */
-  COSTS_N_INSNS (19),   /* divsi */
-  COSTS_N_INSNS (19),   /* divdi */
-  COSTS_N_INSNS (2),    /* fp */
-  COSTS_N_INSNS (2),    /* dmul */
-  COSTS_N_INSNS (19),   /* sdiv */
-  COSTS_N_INSNS (19),   /* ddiv */
-  128,                 /* cache line size */
-  64,                  /* l1 cache */
-  512,                 /* l2 cache */
-  0,                   /* streams */
-};
-
-/* Instruction costs on RIOS2 processors.  */
-static const
-struct processor_costs rios2_cost = {
-  COSTS_N_INSNS (2),    /* mulsi */
-  COSTS_N_INSNS (2),    /* mulsi_const */
-  COSTS_N_INSNS (2),    /* mulsi_const9 */
-  COSTS_N_INSNS (2),    /* muldi */
-  COSTS_N_INSNS (13),   /* divsi */
-  COSTS_N_INSNS (13),   /* divdi */
-  COSTS_N_INSNS (2),    /* fp */
-  COSTS_N_INSNS (2),    /* dmul */
-  COSTS_N_INSNS (17),   /* sdiv */
-  COSTS_N_INSNS (17),   /* ddiv */
-  256,                 /* cache line size */
-  256,                 /* l1 cache */
-  1024,                        /* l2 cache */
-  0,                   /* streams */
-};
-
 /* Instruction costs on RS64A processors.  */
 static const
 struct processor_costs rs64a_cost = {
@@ -752,6 +714,44 @@ struct processor_costs ppce500mc64_cost = {
   1,                   /* prefetch streams /*/
 };
 
+/* Instruction costs on PPCE5500 processors.  */
+static const
+struct processor_costs ppce5500_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (5),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (14),   /* divsi */
+  COSTS_N_INSNS (14),   /* divdi */
+  COSTS_N_INSNS (7),    /* fp */
+  COSTS_N_INSNS (10),   /* dmul */
+  COSTS_N_INSNS (36),   /* sdiv */
+  COSTS_N_INSNS (66),   /* ddiv */
+  64,                  /* cache line size */
+  32,                  /* l1 cache */
+  128,                 /* l2 cache */
+  1,                   /* prefetch streams /*/
+};
+
+/* Instruction costs on PPCE6500 processors.  */
+static const
+struct processor_costs ppce6500_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (5),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (14),   /* divsi */
+  COSTS_N_INSNS (14),   /* divdi */
+  COSTS_N_INSNS (7),    /* fp */
+  COSTS_N_INSNS (10),   /* dmul */
+  COSTS_N_INSNS (36),   /* sdiv */
+  COSTS_N_INSNS (66),   /* ddiv */
+  64,                  /* cache line size */
+  32,                  /* l1 cache */
+  128,                 /* l2 cache */
+  1,                   /* prefetch streams /*/
+};
+
 /* Instruction costs on AppliedMicro Titan processors.  */
 static const
 struct processor_costs titan_cost = {
@@ -849,336 +849,171 @@ struct processor_costs ppca2_cost = {
 
 \f
 /* Table that classifies rs6000 builtin functions (pure, const, etc.).  */
-#undef RS6000_BUILTIN
-#undef RS6000_BUILTIN_EQUATE
-#define RS6000_BUILTIN(NAME, TYPE) TYPE,
-#define RS6000_BUILTIN_EQUATE(NAME, VALUE)
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE) \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
 
-static const enum rs6000_btc builtin_classify[(int)RS6000_BUILTIN_COUNT] =
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)  \
+  { NAME, ICODE, MASK, ATTR },
+
+struct rs6000_builtin_info_type {
+  const char *name;
+  const enum insn_code icode;
+  const unsigned mask;
+  const unsigned attr;
+};
+
+static const struct rs6000_builtin_info_type rs6000_builtin_info[] =
 {
 #include "rs6000-builtin.def"
 };
 
-#undef RS6000_BUILTIN
-#undef RS6000_BUILTIN_EQUATE
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
 
 /* Support for -mveclibabi=<xxx> to control which vector library to use.  */
 static tree (*rs6000_veclib_handler) (tree, tree, tree);
 
 \f
-static bool rs6000_function_ok_for_sibcall (tree, tree);
-static const char *rs6000_invalid_within_doloop (const_rtx);
-static bool rs6000_legitimate_address_p (enum machine_mode, rtx, bool);
 static bool rs6000_debug_legitimate_address_p (enum machine_mode, rtx, bool);
-static rtx rs6000_generate_compare (rtx, enum machine_mode);
-static void rs6000_emit_stack_tie (void);
 static bool spe_func_has_64bit_regs_p (void);
-static rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
-static unsigned rs6000_hash_constant (rtx);
-static unsigned toc_hash_function (const void *);
-static int toc_hash_eq (const void *, const void *);
-static bool reg_offset_addressing_ok_p (enum machine_mode);
-static bool virtual_stack_registers_memory_p (rtx);
-static bool constant_pool_expr_p (rtx);
-static bool legitimate_small_data_p (enum machine_mode, rtx);
-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, bool);
-#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
-static void rs6000_assemble_visibility (tree, int);
-#endif
 static int rs6000_ra_ever_killed (void);
-static bool rs6000_attribute_takes_identifier_p (const_tree);
 static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
 static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
-static bool rs6000_ms_bitfield_layout_p (const_tree);
 static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
-static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
-static const char *rs6000_mangle_type (const_tree);
-static void rs6000_set_default_type_attributes (tree);
-static rtx rs6000_savres_routine_sym (rs6000_stack_t *, bool, bool, bool);
-static rtx rs6000_emit_stack_reset (rs6000_stack_t *, rtx, rtx, int, bool);
-static rtx rs6000_make_savres_rtx (rs6000_stack_t *, rtx, int,
-                                  enum machine_mode, bool, bool, bool);
-static bool rs6000_reg_live_or_pic_offset_p (int);
 static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
-static tree rs6000_builtin_vectorized_function (tree, tree, tree);
-static void rs6000_restore_saved_cr (rtx, int);
-static bool rs6000_output_addr_const_extra (FILE *, rtx);
-static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
-static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
-                                   tree);
 static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
-static bool rs6000_return_in_memory (const_tree, const_tree);
-static rtx rs6000_function_value (const_tree, const_tree, bool);
-static void rs6000_file_start (void);
-#if TARGET_ELF
-static int rs6000_elf_reloc_rw_mask (void);
-static void rs6000_elf_asm_out_constructor (rtx, int) ATTRIBUTE_UNUSED;
-static void rs6000_elf_asm_out_destructor (rtx, int) ATTRIBUTE_UNUSED;
-static void rs6000_elf_file_end (void) ATTRIBUTE_UNUSED;
-static void rs6000_elf_asm_init_sections (void);
-static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
-                                              unsigned HOST_WIDE_INT);
-static void rs6000_elf_encode_section_info (tree, rtx, int)
-     ATTRIBUTE_UNUSED;
-#endif
-static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx);
-static void rs6000_alloc_sdmode_stack_slot (void);
-static void rs6000_instantiate_decls (void);
-#if TARGET_XCOFF
-static void rs6000_xcoff_asm_output_anchor (rtx);
-static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
-static void rs6000_xcoff_asm_init_sections (void);
-static int rs6000_xcoff_reloc_rw_mask (void);
-static void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree);
-static section *rs6000_xcoff_select_section (tree, int,
-                                            unsigned HOST_WIDE_INT);
-static void rs6000_xcoff_unique_section (tree, int);
-static section *rs6000_xcoff_select_rtx_section
-  (enum machine_mode, rtx, unsigned HOST_WIDE_INT);
-static const char * rs6000_xcoff_strip_name_encoding (const char *);
-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
-static int rs6000_variable_issue (FILE *, int, rtx, int);
-static int rs6000_register_move_cost (enum machine_mode,
-                                     reg_class_t, reg_class_t);
 static int rs6000_memory_move_cost (enum machine_mode, reg_class_t, bool);
-static bool rs6000_rtx_costs (rtx, int, int, int *, bool);
-static bool rs6000_debug_rtx_costs (rtx, int, int, int *, bool);
-static int rs6000_debug_address_cost (rtx, bool);
-static int rs6000_adjust_cost (rtx, rtx, rtx, int);
+static bool rs6000_debug_rtx_costs (rtx, int, int, int, int *, bool);
+static int rs6000_debug_address_cost (rtx, enum machine_mode, addr_space_t,
+                                     bool);
 static int rs6000_debug_adjust_cost (rtx, rtx, rtx, int);
-static void rs6000_sched_init (FILE *, int, int);
 static bool is_microcoded_insn (rtx);
 static bool is_nonpipeline_insn (rtx);
 static bool is_cracked_insn (rtx);
-static bool is_branch_slot_insn (rtx);
-static bool is_load_insn (rtx);
-static rtx get_store_dest (rtx pat);
-static bool is_store_insn (rtx);
+static bool is_load_insn (rtx, rtx *);
+static bool is_store_insn (rtx, rtx *);
 static bool set_to_load_agen (rtx,rtx);
-static bool adjacent_mem_locations (rtx,rtx);
-static int rs6000_adjust_priority (rtx, int);
-static int rs6000_issue_rate (void);
-static bool rs6000_is_costly_dependence (dep_t, int, int);
-static rtx get_next_active_insn (rtx, rtx);
 static bool insn_terminates_group_p (rtx , enum group_termination);
 static bool insn_must_be_first_in_group (rtx);
 static bool insn_must_be_last_in_group (rtx);
-static bool is_costly_group (rtx *, rtx);
-static int force_new_group (int, FILE *, rtx *, rtx, bool *, int, int *);
-static int redefine_groups (FILE *, int, rtx, rtx);
-static int pad_groups (FILE *, int, rtx, rtx);
-static void rs6000_sched_finish (FILE *, int);
-static int rs6000_sched_reorder (FILE *, int, rtx *, int *, int);
-static int rs6000_sched_reorder2 (FILE *, int, rtx *, int *, int);
-static int rs6000_use_sched_lookahead (void);
-static int rs6000_use_sched_lookahead_guard (rtx);
-static void * rs6000_alloc_sched_context (void);
-static void rs6000_init_sched_context (void *, bool);
-static void rs6000_set_sched_context (void *);
-static void rs6000_free_sched_context (void *);
-static tree rs6000_builtin_reciprocal (unsigned int, bool, bool);
-static tree rs6000_builtin_mask_for_load (void);
-static tree rs6000_builtin_mul_widen_even (tree);
-static tree rs6000_builtin_mul_widen_odd (tree);
-static tree rs6000_builtin_conversion (unsigned int, tree, tree);
-static tree rs6000_builtin_vec_perm (tree, tree *);
-static bool rs6000_builtin_support_vector_misalignment (enum
-                                                       machine_mode,
-                                                       const_tree,
-                                                       int, bool);
-static int rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt,
-                                              tree, int);
-static enum machine_mode rs6000_preferred_simd_mode (enum machine_mode);
-
-static void def_builtin (int, const char *, tree, int);
-static bool rs6000_vector_alignment_reachable (const_tree, bool);
-static void rs6000_init_builtins (void);
-static tree rs6000_builtin_decl (unsigned, bool);
-
-static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
-static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
-static rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
-static rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void altivec_init_builtins (void);
-static unsigned builtin_hash_function (const void *);
-static int builtin_hash_eq (const void *, const void *);
 static tree builtin_function_type (enum machine_mode, enum machine_mode,
                                   enum machine_mode, enum machine_mode,
                                   enum rs6000_builtins, const char *name);
 static void rs6000_common_init_builtins (void);
-static void rs6000_init_libfuncs (void);
-
 static void paired_init_builtins (void);
-static rtx paired_expand_builtin (tree, rtx, bool *);
-static rtx paired_expand_lv_builtin (enum insn_code, tree, rtx);
-static rtx paired_expand_stv_builtin (enum insn_code, tree);
 static rtx paired_expand_predicate_builtin (enum insn_code, tree, rtx);
-
-static void enable_mask_for_builtins (struct builtin_description *, int,
-                                     enum rs6000_builtins,
-                                     enum rs6000_builtins);
 static void spe_init_builtins (void);
-static rtx spe_expand_builtin (tree, rtx, bool *);
-static rtx spe_expand_stv_builtin (enum insn_code, tree);
 static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
 static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
 static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
 static rs6000_stack_t *rs6000_stack_info (void);
-static void debug_stack_info (rs6000_stack_t *);
-
-static rtx altivec_expand_builtin (tree, rtx, bool *);
-static rtx altivec_expand_ld_builtin (tree, rtx, bool *);
-static rtx altivec_expand_st_builtin (tree, rtx, bool *);
-static rtx altivec_expand_dst_builtin (tree, rtx, bool *);
-static rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
-static rtx altivec_expand_predicate_builtin (enum insn_code, tree, rtx);
-static rtx altivec_expand_stv_builtin (enum insn_code, tree);
-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 void rs6000_option_override (void);
-static int rs6000_loop_align_max_skip (rtx);
-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 rtx rs6000_dwarf_register_span (rtx);
-static void rs6000_init_dwarf_reg_sizes_extra (tree);
-static rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode);
 static rtx rs6000_debug_legitimize_address (rtx, rtx, enum machine_mode);
 static rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
-static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
-static rtx rs6000_delegitimize_address (rtx);
-static rtx rs6000_tls_get_addr (void);
-static rtx rs6000_got_sym (void);
 static int rs6000_tls_symbol_ref_1 (rtx *, void *);
-static const char *rs6000_get_some_local_dynamic_name (void);
 static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
-static rtx rs6000_complex_function_value (enum machine_mode);
-static rtx rs6000_spe_function_arg (const CUMULATIVE_ARGS *,
-                                   enum machine_mode, const_tree);
-static void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
-                                                     HOST_WIDE_INT, int);
-static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
-                                                       const_tree,
-                                                       HOST_WIDE_INT);
-static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
-                                             HOST_WIDE_INT,
-                                             rtx[], int *);
-static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
-                                               const_tree, HOST_WIDE_INT,
-                                               rtx[], int *);
-static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, bool, bool);
-static rtx rs6000_mixed_function_arg (enum machine_mode, const_tree, int);
-static void rs6000_function_arg_advance (cumulative_args_t, enum machine_mode,
-                                        const_tree, bool);
-static rtx rs6000_function_arg (cumulative_args_t, enum machine_mode,
-                               const_tree, bool);
-static unsigned int rs6000_function_arg_boundary (enum machine_mode,
-                                                 const_tree);
-static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
-static void setup_incoming_varargs (cumulative_args_t,
-                                   enum machine_mode, tree,
-                                   int *, int);
-static bool rs6000_pass_by_reference (cumulative_args_t, enum machine_mode,
-                                     const_tree, bool);
-static int rs6000_arg_partial_bytes (cumulative_args_t, enum machine_mode,
-                                    tree, bool);
-static const char *invalid_arg_for_unprototyped_fn (const_tree, const_tree, const_tree);
+static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree,
+                                      bool, bool);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
-static int no_previous_def (tree function_name);
-static tree get_prev_label (tree function_name);
-static void rs6000_darwin_file_start (void);
 #endif
-
-static tree rs6000_build_builtin_va_list (void);
-static void rs6000_va_start (tree, rtx);
-static tree rs6000_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
-static bool rs6000_must_pass_in_stack (enum machine_mode, const_tree);
-static bool rs6000_scalar_mode_supported_p (enum machine_mode);
-static bool rs6000_vector_mode_supported_p (enum machine_mode);
-static rtx rs6000_emit_vector_compare_inner (enum rtx_code, rtx, rtx);
-static rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx,
-                                      enum machine_mode);
-static tree rs6000_stack_protect_fail (void);
-
 static rtx rs6000_legitimize_reload_address (rtx, enum machine_mode, int, int,
                                             int, int *);
-
 static rtx rs6000_debug_legitimize_reload_address (rtx, enum machine_mode, int,
                                                   int, int, int *);
-
-rtx (*rs6000_legitimize_reload_address_ptr) (rtx, enum machine_mode, int, int,
-                                            int, int *)
-  = rs6000_legitimize_reload_address;
-
-static bool rs6000_mode_dependent_address_p (const_rtx);
 static bool rs6000_mode_dependent_address (const_rtx);
 static bool rs6000_debug_mode_dependent_address (const_rtx);
-static bool (*rs6000_mode_dependent_address_ptr) (const_rtx)
-  = rs6000_mode_dependent_address;
-
 static enum reg_class rs6000_secondary_reload_class (enum reg_class,
                                                     enum machine_mode, rtx);
 static enum reg_class rs6000_debug_secondary_reload_class (enum reg_class,
                                                           enum machine_mode,
                                                           rtx);
-enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class,
-                                                    enum machine_mode, rtx)
-  = rs6000_secondary_reload_class;
-
 static enum reg_class rs6000_preferred_reload_class (rtx, enum reg_class);
 static enum reg_class rs6000_debug_preferred_reload_class (rtx,
                                                           enum reg_class);
-enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class)
-  = rs6000_preferred_reload_class;
-
 static bool rs6000_secondary_memory_needed (enum reg_class, enum reg_class,
                                            enum machine_mode);
-
 static bool rs6000_debug_secondary_memory_needed (enum reg_class,
                                                  enum reg_class,
                                                  enum machine_mode);
-
-bool (*rs6000_secondary_memory_needed_ptr) (enum reg_class, enum reg_class,
-                                           enum machine_mode)
-  = rs6000_secondary_memory_needed;
-
 static bool rs6000_cannot_change_mode_class (enum machine_mode,
                                             enum machine_mode,
                                             enum reg_class);
 static bool rs6000_debug_cannot_change_mode_class (enum machine_mode,
                                                   enum machine_mode,
                                                   enum reg_class);
+static bool rs6000_save_toc_in_prologue_p (void);
+
+rtx (*rs6000_legitimize_reload_address_ptr) (rtx, enum machine_mode, int, int,
+                                            int, int *)
+  = rs6000_legitimize_reload_address;
+
+static bool (*rs6000_mode_dependent_address_ptr) (const_rtx)
+  = rs6000_mode_dependent_address;
+
+enum reg_class (*rs6000_secondary_reload_class_ptr) (enum reg_class,
+                                                    enum machine_mode, rtx)
+  = rs6000_secondary_reload_class;
+
+enum reg_class (*rs6000_preferred_reload_class_ptr) (rtx, enum reg_class)
+  = rs6000_preferred_reload_class;
+
+bool (*rs6000_secondary_memory_needed_ptr) (enum reg_class, enum reg_class,
+                                           enum machine_mode)
+  = rs6000_secondary_memory_needed;
 
 bool (*rs6000_cannot_change_mode_class_ptr) (enum machine_mode,
                                             enum machine_mode,
                                             enum reg_class)
   = rs6000_cannot_change_mode_class;
 
-static reg_class_t rs6000_secondary_reload (bool, rtx, reg_class_t,
-                                           enum machine_mode,
-                                           struct secondary_reload_info *);
-
 const int INSN_NOT_AVAILABLE = -1;
-static enum machine_mode rs6000_eh_return_filter_mode (void);
-static bool rs6000_can_eliminate (const int, const int);
-static void rs6000_conditional_register_usage (void);
-static void rs6000_trampoline_init (rtx, tree, rtx);
-static bool rs6000_cannot_force_const_mem (enum machine_mode, rtx);
-static bool rs6000_legitimate_constant_p (enum machine_mode, rtx);
-static bool rs6000_save_toc_in_prologue_p (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -1204,14 +1039,6 @@ struct GTY(()) builtin_hash_struct
 
 static GTY ((param_is (struct builtin_hash_struct))) htab_t builtin_hash_table;
 
-static bool rs6000_valid_attribute_p (tree, tree, tree, int);
-static void rs6000_function_specific_save (struct cl_target_option *);
-static void rs6000_function_specific_restore (struct cl_target_option *);
-static void rs6000_function_specific_print (FILE *, int,
-                                           struct cl_target_option *);
-static bool rs6000_can_inline_p (tree, tree);
-static void rs6000_set_current_function (tree);
-
 \f
 /* Default register names.  */
 char rs6000_reg_names[][8] =
@@ -1339,11 +1166,14 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER rs6000_assemble_integer
 
-#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
+#if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 #undef TARGET_ASM_ASSEMBLE_VISIBILITY
 #define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
 #endif
 
+#undef TARGET_SET_UP_BY_PROLOGUE
+#define TARGET_SET_UP_BY_PROLOGUE rs6000_set_up_by_prologue
+
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS HAVE_AS_TLS
 
@@ -1353,6 +1183,9 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_DELEGITIMIZE_ADDRESS
 #define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address
 
+#undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
+#define TARGET_CONST_NOT_OK_FOR_DEBUG_P rs6000_const_not_ok_for_debug_p
+
 #undef TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue
 #undef TARGET_ASM_FUNCTION_EPILOGUE
@@ -1401,14 +1234,6 @@ static const struct attribute_spec rs6000_attribute_table[] =
 
 #undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
 #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load
-#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN
-#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN rs6000_builtin_mul_widen_even
-#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD
-#define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD rs6000_builtin_mul_widen_odd
-#undef TARGET_VECTORIZE_BUILTIN_CONVERSION
-#define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
-#undef TARGET_VECTORIZE_BUILTIN_VEC_PERM
-#define TARGET_VECTORIZE_BUILTIN_VEC_PERM rs6000_builtin_vec_perm
 #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT           \
   rs6000_builtin_support_vector_misalignment
@@ -1420,6 +1245,14 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE \
   rs6000_preferred_simd_mode
+#undef TARGET_VECTORIZE_INIT_COST
+#define TARGET_VECTORIZE_INIT_COST rs6000_init_cost
+#undef TARGET_VECTORIZE_ADD_STMT_COST
+#define TARGET_VECTORIZE_ADD_STMT_COST rs6000_add_stmt_cost
+#undef TARGET_VECTORIZE_FINISH_COST
+#define TARGET_VECTORIZE_FINISH_COST rs6000_finish_cost
+#undef TARGET_VECTORIZE_DESTROY_COST_DATA
+#define TARGET_VECTORIZE_DESTROY_COST_DATA rs6000_destroy_cost_data
 
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
@@ -1462,7 +1295,7 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS rs6000_rtx_costs
 #undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
+#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
 
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
@@ -1470,6 +1303,9 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
 #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
 
+#undef TARGET_MEMBER_TYPE_FORCES_BLK
+#define TARGET_MEMBER_TYPE_FORCES_BLK rs6000_member_type_forces_blk
+
 /* On rs6000, function arguments are promoted, as are function return
    values.  */
 #undef TARGET_PROMOTE_FUNCTION_MODE
@@ -1532,7 +1368,7 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \
   rs6000_builtin_vectorized_function
 
-#ifndef TARGET_MACHO
+#if !TARGET_MACHO
 #undef TARGET_STACK_PROTECT_FAIL
 #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
 #endif
@@ -1618,14 +1454,14 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_LEGITIMATE_CONSTANT_P
 #define TARGET_LEGITIMATE_CONSTANT_P rs6000_legitimate_constant_p
 
-struct gcc_target targetm = TARGET_INITIALIZER;
+#undef TARGET_VECTORIZE_VEC_PERM_CONST_OK
+#define TARGET_VECTORIZE_VEC_PERM_CONST_OK rs6000_vectorize_vec_perm_const_ok
 \f
 
 /* Simplifications for entries below.  */
 
 enum {
-  POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
-  POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
+  POWERPC_7400_MASK = MASK_PPC_GFXOPT | MASK_ALTIVEC
 };
 
 /* Some OSs don't support saving the high part of 64-bit registers on context
@@ -1635,8 +1471,7 @@ enum {
    the user's specification.  */
 
 enum {
-  POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
-  POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN
+  POWERPC_MASKS = (MASK_PPC_GPOPT | MASK_STRICT_ALIGN
                   | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
                   | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
                   | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP
@@ -1881,6 +1716,7 @@ rs6000_debug_reg_print (int first_regno, int last_regno, const char *reg_name)
 }
 
 #define DEBUG_FMT_D "%-32s= %d\n"
+#define DEBUG_FMT_X "%-32s= 0x%x\n"
 #define DEBUG_FMT_S "%-32s= %s\n"
 
 /* Print various interesting information with -mdebug=reg.  */
@@ -1918,7 +1754,6 @@ rs6000_debug_reg_global (void)
   rs6000_debug_reg_print (LR_REGNO, LR_REGNO, "lr");
   rs6000_debug_reg_print (CTR_REGNO, CTR_REGNO, "ctr");
   rs6000_debug_reg_print (CR0_REGNO, CR7_REGNO, "cr");
-  rs6000_debug_reg_print (MQ_REGNO, MQ_REGNO, "mq");
   rs6000_debug_reg_print (CA_REGNO, CA_REGNO, "ca");
   rs6000_debug_reg_print (VRSAVE_REGNO, VRSAVE_REGNO, "vrsave");
   rs6000_debug_reg_print (VSCR_REGNO, VSCR_REGNO, "vscr");
@@ -2108,6 +1943,11 @@ rs6000_debug_reg_global (void)
           rs6000_long_double_type_size);
   fprintf (stderr, DEBUG_FMT_D, "sched_restricted_insns_priority",
           (int)rs6000_sched_restricted_insns_priority);
+  fprintf (stderr, DEBUG_FMT_D, "Number of standard builtins",
+          (int)END_BUILTINS);
+  fprintf (stderr, DEBUG_FMT_D, "Number of rs6000 builtins",
+          (int)RS6000_BUILTIN_COUNT);
+  fprintf (stderr, DEBUG_FMT_X, "Builtin mask", rs6000_builtin_mask);
 }
 
 /* Initialize the various global tables that are based on register size.  */
@@ -2136,7 +1976,6 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
   for (r = CR1_REGNO; r <= CR7_REGNO; ++r)
     rs6000_regno_regclass[r] = CR_REGS;
 
-  rs6000_regno_regclass[MQ_REGNO] = MQ_REGS;
   rs6000_regno_regclass[LR_REGNO] = LINK_REGS;
   rs6000_regno_regclass[CTR_REGNO] = CTR_REGS;
   rs6000_regno_regclass[CA_REGNO] = CA_REGS;
@@ -2239,7 +2078,7 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
 
   /* TODO add SPE and paired floating point vector support.  */
 
-  /* Register class constaints for the constraints that depend on compile
+  /* Register class constraints for the constraints that depend on compile
      switches.  */
   if (TARGET_HARD_FLOAT && TARGET_FPRS)
     rs6000_constraints[RS6000_CONSTRAINT_f] = FLOAT_REGS;
@@ -2282,6 +2121,11 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
          rs6000_vector_reload[V4SFmode][1]  = CODE_FOR_reload_v4sf_di_load;
          rs6000_vector_reload[V2DFmode][0]  = CODE_FOR_reload_v2df_di_store;
          rs6000_vector_reload[V2DFmode][1]  = CODE_FOR_reload_v2df_di_load;
+         if (TARGET_VSX && TARGET_VSX_SCALAR_MEMORY)
+           {
+             rs6000_vector_reload[DFmode][0]  = CODE_FOR_reload_df_di_store;
+             rs6000_vector_reload[DFmode][1]  = CODE_FOR_reload_df_di_load;
+           }
        }
       else
        {
@@ -2297,6 +2141,11 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
          rs6000_vector_reload[V4SFmode][1]  = CODE_FOR_reload_v4sf_si_load;
          rs6000_vector_reload[V2DFmode][0]  = CODE_FOR_reload_v2df_si_store;
          rs6000_vector_reload[V2DFmode][1]  = CODE_FOR_reload_v2df_si_load;
+         if (TARGET_VSX && TARGET_VSX_SCALAR_MEMORY)
+           {
+             rs6000_vector_reload[DFmode][0]  = CODE_FOR_reload_df_si_store;
+             rs6000_vector_reload[DFmode][1]  = CODE_FOR_reload_df_si_load;
+           }
        }
     }
 
@@ -2454,6 +2303,7 @@ darwin_rs6000_override_options (void)
      off.  */
   rs6000_altivec_abi = 1;
   TARGET_ALTIVEC_VRSAVE = 1;
+  rs6000_current_abi = ABI_DARWIN;
 
   if (DEFAULT_ABI == ABI_DARWIN
       && TARGET_64BIT)
@@ -2479,7 +2329,7 @@ darwin_rs6000_override_options (void)
 
   /* Unless the user (not the configurer) has explicitly overridden
      it with -mcpu=G3 or -mno-altivec, then 10.5+ targets default to
-     G4 unless targetting the kernel.  */
+     G4 unless targeting the kernel.  */
   if (!flag_mkernel
       && !flag_apple_kext
       && strverscmp (darwin_macosx_version_min, "10.5") >= 0
@@ -2498,6 +2348,26 @@ darwin_rs6000_override_options (void)
 #define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
 #endif
 
+/* Return the builtin mask of the various options used that could affect which
+   builtins were used.  In the past we used target_flags, but we've run out of
+   bits, and some options like SPE and PAIRED are no longer in
+   target_flags.  */
+
+unsigned
+rs6000_builtin_mask_calculate (void)
+{
+  return (((TARGET_ALTIVEC)                ? RS6000_BTM_ALTIVEC  : 0)
+         | ((TARGET_VSX)                   ? RS6000_BTM_VSX      : 0)
+         | ((TARGET_SPE)                   ? RS6000_BTM_SPE      : 0)
+         | ((TARGET_PAIRED_FLOAT)          ? RS6000_BTM_PAIRED   : 0)
+         | ((TARGET_FRE)                   ? RS6000_BTM_FRE      : 0)
+         | ((TARGET_FRES)                  ? RS6000_BTM_FRES     : 0)
+         | ((TARGET_FRSQRTE)               ? RS6000_BTM_FRSQRTE  : 0)
+         | ((TARGET_FRSQRTES)              ? RS6000_BTM_FRSQRTES : 0)
+         | ((TARGET_POPCNTD)               ? RS6000_BTM_POPCNTD  : 0)
+         | ((rs6000_cpu == PROCESSOR_CELL) ? RS6000_BTM_CELL     : 0));
+}
+
 /* Override command line options.  Mostly we process the processor type and
    sometimes adjust other TARGET_ options.  */
 
@@ -2505,7 +2375,11 @@ static bool
 rs6000_option_override_internal (bool global_init_p)
 {
   bool ret = true;
-  const char *default_cpu = OPTION_TARGET_CPU_DEFAULT;
+  bool have_cpu = false;
+
+  /* The default cpu requested at configure time, if any.  */
+  const char *implicit_cpu = OPTION_TARGET_CPU_DEFAULT;
+
   int set_masks;
   int cpu_index;
   int tune_index;
@@ -2524,11 +2398,6 @@ rs6000_option_override_internal (bool global_init_p)
     warning (0, "-malign-power is not supported for 64-bit Darwin;"
             " it is incompatible with the installed C and C++ libraries");
 
-  if (global_options_set.x_rs6000_spe_abi
-      && rs6000_spe_abi
-      && !TARGET_SPE_ABI)
-    error ("not configured for SPE ABI");
-
   /* Numerous experiment shows that IRA based loop pressure
      calculation works better for RTL loop invariant motion on targets
      with enough (>= 32) registers.  It is an expensive optimization.
@@ -2548,7 +2417,7 @@ rs6000_option_override_internal (bool global_init_p)
       rs6000_pointer_size = 32;
     }
 
-  set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
+  set_masks = POWERPC_MASKS | MASK_SOFT_FLOAT;
 #ifdef OS_MISSING_POWERPC64
   if (OS_MISSING_POWERPC64)
     set_masks &= ~MASK_POWERPC64;
@@ -2561,52 +2430,109 @@ rs6000_option_override_internal (bool global_init_p)
   /* Don't override by the processor default if given explicitly.  */
   set_masks &= ~target_flags_explicit;
 
-  /* Identify the processor type.  */
-  if (!default_cpu)
-    {
-      if (TARGET_POWERPC64)
-       default_cpu = "powerpc64";
-      else if (TARGET_POWERPC)
-       default_cpu = "powerpc";
-    }
-
   /* Process the -mcpu=<xxx> and -mtune=<xxx> argument.  If the user changed
      the cpu in a target attribute or pragma, but did not specify a tuning
      option, use the cpu for the tuning option rather than the option specified
-     with -mtune on the command line.  */
-  if (rs6000_cpu_index > 0)
-    cpu_index = rs6000_cpu_index;
-  else if (main_target_opt != NULL && main_target_opt->x_rs6000_cpu_index > 0)
-    rs6000_cpu_index = cpu_index = main_target_opt->x_rs6000_cpu_index;
+     with -mtune on the command line.  Process a '--with-cpu' configuration
+     request as an implicit --cpu.  */
+  if (rs6000_cpu_index >= 0)
+    {
+      cpu_index = rs6000_cpu_index;
+      have_cpu = true;
+    }
+  else if (main_target_opt != NULL && main_target_opt->x_rs6000_cpu_index >= 0)
+    {
+      rs6000_cpu_index = cpu_index = main_target_opt->x_rs6000_cpu_index;
+      have_cpu = true;
+    }
   else
-    rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
+    {
+      const char *default_cpu =
+        (implicit_cpu ? implicit_cpu
+         : (TARGET_POWERPC64 ? "powerpc64" : "powerpc"));
+
+      rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
+      have_cpu = implicit_cpu != 0;
+    }
+
+  gcc_assert (cpu_index >= 0);
+
+  target_flags &= ~set_masks;
+  target_flags |= (processor_target_table[cpu_index].target_enable
+                  & set_masks);
 
-  if (rs6000_tune_index > 0)
+  if (rs6000_tune_index >= 0)
     tune_index = rs6000_tune_index;
-  else
+  else if (have_cpu)
     rs6000_tune_index = tune_index = cpu_index;
-
-  if (cpu_index >= 0)
+  else
     {
-      target_flags &= ~set_masks;
-      target_flags |= (processor_target_table[cpu_index].target_enable
-                      & set_masks);
+      size_t i;
+      enum processor_type tune_proc
+       = (TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT);
+
+      tune_index = -1;
+      for (i = 0; i < ARRAY_SIZE (processor_target_table); i++)
+       if (processor_target_table[i].processor == tune_proc)
+         {
+           rs6000_tune_index = tune_index = i;
+           break;
+         }
     }
 
-  rs6000_cpu = ((tune_index >= 0)
-               ? processor_target_table[tune_index].processor
-               : (TARGET_POWERPC64
-                  ? PROCESSOR_DEFAULT64
-                  : PROCESSOR_DEFAULT));
+  gcc_assert (tune_index >= 0);
+  rs6000_cpu = processor_target_table[tune_index].processor;
+
+  /* Pick defaults for SPE related control flags.  Do this early to make sure
+     that the TARGET_ macros are representative ASAP.  */
+  {
+    int spe_capable_cpu =
+      (rs6000_cpu == PROCESSOR_PPC8540
+       || rs6000_cpu == PROCESSOR_PPC8548);
+
+    if (!global_options_set.x_rs6000_spe_abi)
+      rs6000_spe_abi = spe_capable_cpu;
+
+    if (!global_options_set.x_rs6000_spe)
+      rs6000_spe = spe_capable_cpu;
+
+    if (!global_options_set.x_rs6000_float_gprs)
+      rs6000_float_gprs =
+        (rs6000_cpu == PROCESSOR_PPC8540 ? 1
+         : rs6000_cpu == PROCESSOR_PPC8548 ? 2
+         : 0);
+  }
+
+  if (global_options_set.x_rs6000_spe_abi
+      && rs6000_spe_abi
+      && !TARGET_SPE_ABI)
+    error ("not configured for SPE ABI");
+
+  if (global_options_set.x_rs6000_spe
+      && rs6000_spe
+      && !TARGET_SPE)
+    error ("not configured for SPE instruction set");
+
+  if (main_target_opt != NULL
+      && ((main_target_opt->x_rs6000_spe_abi != rs6000_spe_abi)
+          || (main_target_opt->x_rs6000_spe != rs6000_spe)
+          || (main_target_opt->x_rs6000_float_gprs != rs6000_float_gprs)))
+    error ("target attribute or pragma changes SPE ABI");
 
   if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3
-      || rs6000_cpu == PROCESSOR_PPCE500MC || rs6000_cpu == PROCESSOR_PPCE500MC64)
+      || rs6000_cpu == PROCESSOR_PPCE500MC || rs6000_cpu == PROCESSOR_PPCE500MC64
+      || rs6000_cpu == PROCESSOR_PPCE5500)
     {
       if (TARGET_ALTIVEC)
        error ("AltiVec not supported in this target");
       if (TARGET_SPE)
        error ("SPE not supported in this target");
     }
+  if (rs6000_cpu == PROCESSOR_PPCE6500)
+    {
+      if (TARGET_SPE)
+       error ("SPE not supported in this target");
+    }
 
   /* Disable Cell microcode if we are optimizing for the Cell
      and not optimizing for size.  */
@@ -2701,7 +2627,9 @@ rs6000_option_override_internal (bool global_init_p)
      user's opinion, though.  */
   if (rs6000_block_move_inline_limit == 0
       && (rs6000_cpu == PROCESSOR_PPCE500MC
-         || rs6000_cpu == PROCESSOR_PPCE500MC64))
+         || rs6000_cpu == PROCESSOR_PPCE500MC64
+         || rs6000_cpu == PROCESSOR_PPCE5500
+         || rs6000_cpu == PROCESSOR_PPCE6500))
     rs6000_block_move_inline_limit = 128;
 
   /* store_one_arg depends on expand_block_move to handle at least the
@@ -2762,7 +2690,7 @@ rs6000_option_override_internal (bool global_init_p)
        rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
-#ifndef POWERPC_LINUX
+#if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD)
   if (!global_options_set.x_rs6000_ieeequad)
     rs6000_ieeequad = 1;
 #endif
@@ -2834,35 +2762,46 @@ rs6000_option_override_internal (bool global_init_p)
   SUB3TARGET_OVERRIDE_OPTIONS;
 #endif
 
-  if (TARGET_E500 || rs6000_cpu == PROCESSOR_PPCE500MC
-      || rs6000_cpu == PROCESSOR_PPCE500MC64)
+  /* For the E500 family of cores, reset the single/double FP flags to let us
+     check that they remain constant across attributes or pragmas.  Also,
+     clear a possible request for string instructions, not supported and which
+     we might have silently queried above for -Os. 
+
+     For other families, clear ISEL in case it was set implicitly.
+  */
+
+  switch (rs6000_cpu)
     {
-      /* The e500 and e500mc do not have string instructions, and we set
-        MASK_STRING above when optimizing for size.  */
-      if ((target_flags & MASK_STRING) != 0)
-       target_flags = target_flags & ~MASK_STRING;
+    case PROCESSOR_PPC8540:
+    case PROCESSOR_PPC8548:
+    case PROCESSOR_PPCE500MC:
+    case PROCESSOR_PPCE500MC64:
+    case PROCESSOR_PPCE5500:
+    case PROCESSOR_PPCE6500:
+
+      rs6000_single_float = TARGET_E500_SINGLE || TARGET_E500_DOUBLE;
+      rs6000_double_float = TARGET_E500_DOUBLE;
+
+      target_flags &= ~MASK_STRING;
+
+      break;
+
+    default:
+
+      if (have_cpu && !(target_flags_explicit & MASK_ISEL))
+       target_flags &= ~MASK_ISEL;
+
+      break;
     }
-  else if (global_options_set.x_rs6000_cpu_index)
+
+  if (main_target_opt)
     {
-      /* 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 (main_target_opt != NULL
-         && ((main_target_opt->x_rs6000_spe_abi != rs6000_spe_abi)
-             || (main_target_opt->x_rs6000_spe != rs6000_spe)
-             || (main_target_opt->x_rs6000_float_gprs != rs6000_float_gprs)))
-       error ("target attribute or pragma changes SPE ABI");
-      else
-       {
-         if (!global_options_set.x_rs6000_spe_abi)
-           rs6000_spe_abi = 0;
-         if (!global_options_set.x_rs6000_spe)
-           rs6000_spe = 0;
-         if (!global_options_set.x_rs6000_float_gprs)
-           rs6000_float_gprs = 0;
-       }
-      if (!(target_flags_explicit & MASK_ISEL))
-       target_flags &= ~MASK_ISEL;
+      if (main_target_opt->x_rs6000_single_float != rs6000_single_float)
+       error ("target attribute or pragma changes single precision floating "
+              "point");
+      if (main_target_opt->x_rs6000_double_float != rs6000_double_float)
+       error ("target attribute or pragma changes double precision floating "
+              "point");
     }
 
   /* Detect invalid option combinations with E500.  */
@@ -2873,7 +2812,8 @@ rs6000_option_override_internal (bool global_init_p)
                        && rs6000_cpu != PROCESSOR_POWER6
                        && rs6000_cpu != PROCESSOR_POWER7
                        && rs6000_cpu != PROCESSOR_PPCA2
-                       && rs6000_cpu != PROCESSOR_CELL);
+                       && rs6000_cpu != PROCESSOR_CELL
+                       && rs6000_cpu != PROCESSOR_PPC476);
   rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4
                         || rs6000_cpu == PROCESSOR_POWER5
                         || rs6000_cpu == PROCESSOR_POWER7);
@@ -2882,7 +2822,9 @@ rs6000_option_override_internal (bool global_init_p)
                                 || rs6000_cpu == PROCESSOR_POWER6
                                 || rs6000_cpu == PROCESSOR_POWER7
                                 || rs6000_cpu == PROCESSOR_PPCE500MC
-                                || rs6000_cpu == PROCESSOR_PPCE500MC64);
+                                || rs6000_cpu == PROCESSOR_PPCE500MC64
+                                || rs6000_cpu == PROCESSOR_PPCE5500
+                                || rs6000_cpu == PROCESSOR_PPCE6500);
 
   /* Allow debug switches to override the above settings.  These are set to -1
      in rs6000.opt to indicate the user hasn't directly set the switch.  */
@@ -2900,7 +2842,7 @@ rs6000_option_override_internal (bool global_init_p)
 
   /* Handle -msched-costly-dep option.  */
   rs6000_sched_costly_dep
-    = (rs6000_sched_groups ? store_to_load_dep_costly : no_dep_costly);
+    = (rs6000_sched_groups ? true_store_to_load_dep_costly : no_dep_costly);
 
   if (rs6000_sched_costly_dep_str)
     {
@@ -3018,14 +2960,6 @@ rs6000_option_override_internal (bool global_init_p)
   else
     switch (rs6000_cpu)
       {
-      case PROCESSOR_RIOS1:
-       rs6000_cost = &rios1_cost;
-       break;
-
-      case PROCESSOR_RIOS2:
-       rs6000_cost = &rios2_cost;
-       break;
-
       case PROCESSOR_RS64A:
        rs6000_cost = &rs64a_cost;
        break;
@@ -3088,6 +3022,7 @@ rs6000_option_override_internal (bool global_init_p)
        break;
 
       case PROCESSOR_PPC8540:
+      case PROCESSOR_PPC8548:
        rs6000_cost = &ppc8540_cost;
        break;
 
@@ -3104,6 +3039,14 @@ rs6000_option_override_internal (bool global_init_p)
        rs6000_cost = &ppce500mc64_cost;
        break;
 
+      case PROCESSOR_PPCE5500:
+       rs6000_cost = &ppce5500_cost;
+       break;
+
+      case PROCESSOR_PPCE6500:
+       rs6000_cost = &ppce6500_cost;
+       break;
+
       case PROCESSOR_TITAN:
        rs6000_cost = &titan_cost;
        break;
@@ -3160,26 +3103,6 @@ rs6000_option_override_internal (bool global_init_p)
       && rs6000_single_float == 0 && rs6000_double_float == 0)
     rs6000_single_float = rs6000_double_float = 1;
 
-  /* Reset single and double FP flags if target is E500. */
-  if (TARGET_E500) 
-  {
-    rs6000_single_float = rs6000_double_float = 0;
-    if (TARGET_E500_SINGLE)
-      rs6000_single_float = 1; 
-    if (TARGET_E500_DOUBLE)
-      rs6000_single_float = rs6000_double_float = 1;
-  }
-
-  if (main_target_opt)
-    {
-      if (main_target_opt->x_rs6000_single_float != rs6000_single_float)
-       error ("target attribute or pragma changes single precision floating "
-              "point");
-      if (main_target_opt->x_rs6000_double_float != rs6000_double_float)
-       error ("target attribute or pragma changes double precision floating "
-              "point");
-    }
-
   /* If not explicitly specified via option, decide whether to generate indexed
      load/store instructions.  */
   if (TARGET_AVOID_XFORM == -1)
@@ -3237,6 +3160,19 @@ rs6000_option_override_internal (bool global_init_p)
        }
     }
 
+  /* Set the builtin mask of the various options used that could affect which
+     builtins were used.  In the past we used target_flags, but we've run out
+     of bits, and some options like SPE and PAIRED are no longer in
+     target_flags.  */
+  rs6000_builtin_mask = rs6000_builtin_mask_calculate ();
+  if (TARGET_DEBUG_BUILTIN || TARGET_DEBUG_TARGET)
+    fprintf (stderr, "new builtin mask = 0x%x%s%s%s%s\n", rs6000_builtin_mask,
+            (rs6000_builtin_mask & RS6000_BTM_ALTIVEC) ? ", altivec" : "",
+            (rs6000_builtin_mask & RS6000_BTM_VSX)     ? ", vsx"     : "",
+            (rs6000_builtin_mask & RS6000_BTM_PAIRED)  ? ", paired"  : "",
+            (rs6000_builtin_mask & RS6000_BTM_SPE)     ? ", spe" : "");
+
+  /* Initialize all of the registers.  */
   rs6000_init_hard_regno_mode_ok (global_init_p);
 
   /* Save the initial options in case the user does function specific options */
@@ -3244,6 +3180,11 @@ rs6000_option_override_internal (bool global_init_p)
     target_option_default_node = target_option_current_node
       = build_target_option_node ();
 
+  /* If not explicitly specified via option, decide whether to generate the
+     extra blr's required to preserve the link stack on some cpus (eg, 476).  */
+  if (TARGET_LINK_STACK == -1)
+    SET_TARGET_LINK_STACK (rs6000_cpu == PROCESSOR_PPC476 && flag_pic);
+
   return ret;
 }
 
@@ -3299,133 +3240,23 @@ rs6000_loop_align_max_skip (rtx label)
   return (1 << rs6000_loop_align (label)) - 1;
 }
 
-/* Implement targetm.vectorize.builtin_conversion.
-   Returns a decl of a function that implements conversion of an integer vector
-   into a floating-point vector, or vice-versa.  DEST_TYPE is the
-   destination type and SRC_TYPE the source type of the conversion.
-   Return NULL_TREE if it is not available.  */
-static tree
-rs6000_builtin_conversion (unsigned int tcode, tree dest_type, tree src_type)
+/* Return true iff, data reference of TYPE can reach vector alignment (16)
+   after applying N number of iterations.  This routine does not determine
+   how may iterations are required to reach desired alignment.  */
+
+static bool
+rs6000_vector_alignment_reachable (const_tree type ATTRIBUTE_UNUSED, bool is_packed)
 {
-  enum tree_code code = (enum tree_code) tcode;
+  if (is_packed)
+    return false;
 
-  switch (code)
+  if (TARGET_32BIT)
     {
-    case FIX_TRUNC_EXPR:
-      switch (TYPE_MODE (dest_type))
-       {
-       case V2DImode:
-         if (!VECTOR_UNIT_VSX_P (V2DFmode))
-           return NULL_TREE;
+      if (rs6000_alignment_flags == MASK_ALIGN_NATURAL)
+        return true;
 
-         return TYPE_UNSIGNED (dest_type)
-           ? rs6000_builtin_decls[VSX_BUILTIN_XVCVDPUXDS_UNS]
-           : rs6000_builtin_decls[VSX_BUILTIN_XVCVDPSXDS];
-
-       case V4SImode:
-         if (VECTOR_UNIT_NONE_P (V4SImode) || VECTOR_UNIT_NONE_P (V4SFmode))
-           return NULL_TREE;
-
-         return TYPE_UNSIGNED (dest_type)
-           ? rs6000_builtin_decls[VECTOR_BUILTIN_FIXUNS_V4SF_V4SI]
-           : rs6000_builtin_decls[VECTOR_BUILTIN_FIX_V4SF_V4SI];
-
-       default:
-         return NULL_TREE;
-       }
-
-    case FLOAT_EXPR:
-      switch (TYPE_MODE (src_type))
-       {
-       case V2DImode:
-         if (!VECTOR_UNIT_VSX_P (V2DFmode))
-           return NULL_TREE;
-
-         return TYPE_UNSIGNED (src_type)
-           ? rs6000_builtin_decls[VSX_BUILTIN_XVCVUXDDP]
-           : rs6000_builtin_decls[VSX_BUILTIN_XVCVSXDDP];
-
-       case V4SImode:
-         if (VECTOR_UNIT_NONE_P (V4SImode) || VECTOR_UNIT_NONE_P (V4SFmode))
-           return NULL_TREE;
-
-         return TYPE_UNSIGNED (src_type)
-           ? rs6000_builtin_decls[VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF]
-           : rs6000_builtin_decls[VECTOR_BUILTIN_FLOAT_V4SI_V4SF];
-
-       default:
-         return NULL_TREE;
-       }
-
-    default:
-      return NULL_TREE;
-    }
-}
-
-/* Implement targetm.vectorize.builtin_mul_widen_even.  */
-static tree
-rs6000_builtin_mul_widen_even (tree type)
-{
-  if (!TARGET_ALTIVEC)
-    return NULL_TREE;
-
-  switch (TYPE_MODE (type))
-    {
-    case V8HImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULEUH_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULESH];
-
-    case V16QImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULEUB_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULESB];
-    default:
-      return NULL_TREE;
-    }
-}
-
-/* Implement targetm.vectorize.builtin_mul_widen_odd.  */
-static tree
-rs6000_builtin_mul_widen_odd (tree type)
-{
-  if (!TARGET_ALTIVEC)
-    return NULL_TREE;
-
-  switch (TYPE_MODE (type))
-    {
-    case V8HImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOUH_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOSH];
-
-    case V16QImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOUB_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOSB];
-    default:
-      return NULL_TREE;
-    }
-}
-
-
-/* Return true iff, data reference of TYPE can reach vector alignment (16)
-   after applying N number of iterations.  This routine does not determine
-   how may iterations are required to reach desired alignment.  */
-
-static bool
-rs6000_vector_alignment_reachable (const_tree type ATTRIBUTE_UNUSED, bool is_packed)
-{
-  if (is_packed)
-    return false;
-
-  if (TARGET_32BIT)
-    {
-      if (rs6000_alignment_flags == MASK_ALIGN_NATURAL)
-        return true;
-
-      if (rs6000_alignment_flags ==  MASK_ALIGN_POWER)
-        return true;
+      if (rs6000_alignment_flags ==  MASK_ALIGN_POWER)
+        return true;
 
       return false;
     }
@@ -3441,7 +3272,7 @@ rs6000_vector_alignment_reachable (const_tree type ATTRIBUTE_UNUSED, bool is_pac
 
 /* Return true if the vector misalignment factor is supported by the
    target.  */ 
-bool
+static bool
 rs6000_builtin_support_vector_misalignment (enum machine_mode mode,
                                            const_tree type,
                                            int misalignment,
@@ -3475,71 +3306,13 @@ rs6000_builtin_support_vector_misalignment (enum machine_mode mode,
   return false;
 }
 
-/* Implement targetm.vectorize.builtin_vec_perm.  */
-tree
-rs6000_builtin_vec_perm (tree type, tree *mask_element_type)
-{
-  tree inner_type = TREE_TYPE (type);
-  bool uns_p = TYPE_UNSIGNED (inner_type);
-  tree d;
-
-  *mask_element_type = unsigned_char_type_node;
-
-  switch (TYPE_MODE (type))
-    {
-    case V16QImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_16QI]);
-      break;
-
-    case V8HImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_8HI]);
-      break;
-
-    case V4SImode:
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SI]);
-      break;
-
-    case V4SFmode:
-      d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_4SF];
-      break;
-
-    case V2DFmode:
-      if (!TARGET_ALLOW_DF_PERMUTE)
-       return NULL_TREE;
-
-      d = rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DF];
-      break;
-
-    case V2DImode:
-      if (!TARGET_ALLOW_DF_PERMUTE)
-       return NULL_TREE;
-
-      d = (uns_p
-          ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI_UNS]
-          : rs6000_builtin_decls[ALTIVEC_BUILTIN_VPERM_2DI]);
-      break;
-
-    default:
-      return NULL_TREE;
-    }
-
-  gcc_assert (d);
-  return d;
-}
-
-
 /* Implement targetm.vectorize.builtin_vectorization_cost.  */
 static int
 rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
                                    tree vectype, int misalign)
 {
   unsigned elements;
+  tree elem_type;
 
   switch (type_of_cost)
     {
@@ -3552,9 +3325,20 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
       case vec_to_scalar:
       case scalar_to_vec:
       case cond_branch_not_taken:
-      case vec_perm:
         return 1;
 
+      case vec_perm:
+       if (TARGET_VSX)
+         return 3;
+       else
+         return 1;
+
+      case vec_promote_demote:
+        if (TARGET_VSX)
+          return 4;
+        else
+          return 1;
+
       case cond_branch_taken:
         return 3;
 
@@ -3628,6 +3412,18 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
 
         return 2;
 
+      case vec_construct:
+       elements = TYPE_VECTOR_SUBPARTS (vectype);
+       elem_type = TREE_TYPE (vectype);
+       /* 32-bit vectors loaded into registers are stored as double
+          precision, so we need n/2 converts in addition to the usual
+          n/2 merges to construct a vector of short floats from them.  */
+       if (SCALAR_FLOAT_TYPE_P (elem_type)
+           && TYPE_PRECISION (elem_type) == 32)
+         return elements + 1;
+       else
+         return elements / 2 + 1;
+
       default:
         gcc_unreachable ();
     }
@@ -3675,6 +3471,126 @@ rs6000_preferred_simd_mode (enum machine_mode mode)
   return word_mode;
 }
 
+typedef struct _rs6000_cost_data
+{
+  struct loop *loop_info;
+  unsigned cost[3];
+} rs6000_cost_data;
+
+/* Test for likely overcommitment of vector hardware resources.  If a
+   loop iteration is relatively large, and too large a percentage of
+   instructions in the loop are vectorized, the cost model may not
+   adequately reflect delays from unavailable vector resources.
+   Penalize the loop body cost for this case.  */
+
+static void
+rs6000_density_test (rs6000_cost_data *data)
+{
+  const int DENSITY_PCT_THRESHOLD = 85;
+  const int DENSITY_SIZE_THRESHOLD = 70;
+  const int DENSITY_PENALTY = 10;
+  struct loop *loop = data->loop_info;
+  basic_block *bbs = get_loop_body (loop);
+  int nbbs = loop->num_nodes;
+  int vec_cost = data->cost[vect_body], not_vec_cost = 0;
+  int i, density_pct;
+
+  for (i = 0; i < nbbs; i++)
+    {
+      basic_block bb = bbs[i];
+      gimple_stmt_iterator gsi;
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+
+         if (!STMT_VINFO_RELEVANT_P (stmt_info)
+             && !STMT_VINFO_IN_PATTERN_P (stmt_info))
+           not_vec_cost++;
+       }
+    }
+
+  free (bbs);
+  density_pct = (vec_cost * 100) / (vec_cost + not_vec_cost);
+
+  if (density_pct > DENSITY_PCT_THRESHOLD
+      && vec_cost + not_vec_cost > DENSITY_SIZE_THRESHOLD)
+    {
+      data->cost[vect_body] = vec_cost * (100 + DENSITY_PENALTY) / 100;
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump,
+                "density %d%%, cost %d exceeds threshold, penalizing "
+                "loop body cost by %d%%", density_pct, 
+                vec_cost + not_vec_cost, DENSITY_PENALTY);
+    }
+}
+
+/* Implement targetm.vectorize.init_cost.  */
+
+static void *
+rs6000_init_cost (struct loop *loop_info)
+{
+  rs6000_cost_data *data = XNEW (struct _rs6000_cost_data);
+  data->loop_info = loop_info;
+  data->cost[vect_prologue] = 0;
+  data->cost[vect_body]     = 0;
+  data->cost[vect_epilogue] = 0;
+  return data;
+}
+
+/* Implement targetm.vectorize.add_stmt_cost.  */
+
+static unsigned
+rs6000_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind,
+                     struct _stmt_vec_info *stmt_info, int misalign,
+                     enum vect_cost_model_location where)
+{
+  rs6000_cost_data *cost_data = (rs6000_cost_data*) data;
+  unsigned retval = 0;
+
+  if (flag_vect_cost_model)
+    {
+      tree vectype = stmt_info ? stmt_vectype (stmt_info) : NULL_TREE;
+      int stmt_cost = rs6000_builtin_vectorization_cost (kind, vectype,
+                                                        misalign);
+      /* Statements in an inner loop relative to the loop being
+        vectorized are weighted more heavily.  The value here is
+        arbitrary and could potentially be improved with analysis.  */
+      if (where == vect_body && stmt_info && stmt_in_inner_loop_p (stmt_info))
+       count *= 50;  /* FIXME.  */
+
+      retval = (unsigned) (count * stmt_cost);
+      cost_data->cost[where] += retval;
+    }
+
+  return retval;
+}
+
+/* Implement targetm.vectorize.finish_cost.  */
+
+static void
+rs6000_finish_cost (void *data, unsigned *prologue_cost,
+                   unsigned *body_cost, unsigned *epilogue_cost)
+{
+  rs6000_cost_data *cost_data = (rs6000_cost_data*) data;
+
+  if (cost_data->loop_info)
+    rs6000_density_test (cost_data);
+
+  *prologue_cost = cost_data->cost[vect_prologue];
+  *body_cost     = cost_data->cost[vect_body];
+  *epilogue_cost = cost_data->cost[vect_epilogue];
+}
+
+/* Implement targetm.vectorize.destroy_cost_data.  */
+
+static void
+rs6000_destroy_cost_data (void *data)
+{
+  free (data);
+}
+
 /* Handler for the Mathematical Acceleration Subsystem (mass) interface to a
    library with vectorized intrinsics.  */
 
@@ -3739,7 +3655,7 @@ rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
        case BUILT_IN_SQRT:
        case BUILT_IN_TAN:
        case BUILT_IN_TANH:
-         bdecl = implicit_built_in_decls[fn];
+         bdecl = builtin_decl_implicit (fn);
          suffix = "d2";                                /* pow -> powd2 */
          if (el_mode != DFmode
              || n != 2)
@@ -3776,7 +3692,7 @@ rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
        case BUILT_IN_SQRTF:
        case BUILT_IN_TANF:
        case BUILT_IN_TANHF:
-         bdecl = implicit_built_in_decls[fn];
+         bdecl = builtin_decl_implicit (fn);
          suffix = "4";                                 /* powf -> powf4 */
          if (el_mode != SFmode
              || n != 4)
@@ -3824,6 +3740,12 @@ rs6000_builtin_vectorized_function (tree fndecl, tree type_out,
   enum machine_mode in_mode, out_mode;
   int in_n, out_n;
 
+  if (TARGET_DEBUG_BUILTIN)
+    fprintf (stderr, "rs6000_builtin_vectorized_function (%s, %s, %s)\n",
+            IDENTIFIER_POINTER (DECL_NAME (fndecl)),
+            GET_MODE_NAME (TYPE_MODE (type_out)),
+            GET_MODE_NAME (TYPE_MODE (type_in)));
+
   if (TREE_CODE (type_out) != VECTOR_TYPE
       || TREE_CODE (type_in) != VECTOR_TYPE
       || !TARGET_VECTORIZE_BUILTINS)
@@ -3976,7 +3898,7 @@ rs6000_builtin_vectorized_function (tree fndecl, tree type_out,
          if (VECTOR_UNIT_VSX_P (V2DFmode)
              && out_mode == DFmode && out_n == 2
              && in_mode == DFmode && in_n == 2)
-           return rs6000_builtin_decls[VSX_BUILTIN_VEC_RSQRT_V2DF];
+           return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF];
          break;
        case RS6000_BUILTIN_RECIPF:
          if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)
@@ -4018,11 +3940,6 @@ rs6000_file_start (void)
 
   default_file_start ();
 
-#ifdef TARGET_BI_ARCH
-  if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
-    rs6000_default_cpu = 0;
-#endif
-
   if (flag_verbose_asm)
     {
       sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
@@ -4110,11 +4027,11 @@ direct_return (void)
 int
 num_insns_constant_wide (HOST_WIDE_INT value)
 {
-  /* signed constant loadable with {cal|addi} */
+  /* signed constant loadable with addi */
   if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
     return 1;
 
-  /* constant loadable with {cau|addis} */
+  /* constant loadable with addis */
   else if ((value & 0xffff) == 0
           && (value >> 31 == -1 || value >> 31 == 0))
     return 1;
@@ -4503,7 +4420,9 @@ paired_expand_vector_init (rtx target, rtx vals)
   for (i = 0; i < n_elts; ++i)
     {
       x = XVECEXP (vals, 0, i);
-      if (!CONSTANT_P (x))
+      if (!(CONST_INT_P (x)
+           || GET_CODE (x) == CONST_DOUBLE
+           || GET_CODE (x) == CONST_FIXED))
        ++n_var;
     }
   if (n_var == 0)
@@ -4655,7 +4574,9 @@ rs6000_expand_vector_init (rtx target, rtx vals)
   for (i = 0; i < n_elts; ++i)
     {
       x = XVECEXP (vals, 0, i);
-      if (!CONSTANT_P (x))
+      if (!(CONST_INT_P (x)
+           || GET_CODE (x) == CONST_DOUBLE
+           || GET_CODE (x) == CONST_FIXED))
        ++n_var, one_var = i;
       else if (x != CONST0_RTX (inner_mode))
        all_const_zero = false;
@@ -4692,28 +4613,25 @@ rs6000_expand_vector_init (rtx target, rtx vals)
   /* Double word values on VSX can use xxpermdi or lxvdsx.  */
   if (VECTOR_MEM_VSX_P (mode) && (mode == V2DFmode || mode == V2DImode))
     {
+      rtx op0 = XVECEXP (vals, 0, 0);
+      rtx op1 = XVECEXP (vals, 0, 1);
       if (all_same)
        {
-         rtx element = XVECEXP (vals, 0, 0);
+         if (!MEM_P (op0) && !REG_P (op0))
+           op0 = force_reg (inner_mode, op0);
          if (mode == V2DFmode)
-           emit_insn (gen_vsx_splat_v2df (target, element));
+           emit_insn (gen_vsx_splat_v2df (target, op0));
          else
-           emit_insn (gen_vsx_splat_v2di (target, element));
+           emit_insn (gen_vsx_splat_v2di (target, op0));
        }
       else
        {
+         op0 = force_reg (inner_mode, op0);
+         op1 = force_reg (inner_mode, op1);
          if (mode == V2DFmode)
-           {
-             rtx op0 = copy_to_mode_reg (DFmode, XVECEXP (vals, 0, 0));
-             rtx op1 = copy_to_mode_reg (DFmode, XVECEXP (vals, 0, 1));
-             emit_insn (gen_vsx_concat_v2df (target, op0, op1));
-           }
+           emit_insn (gen_vsx_concat_v2df (target, op0, op1));
          else
-           {
-             rtx op0 = copy_to_mode_reg (DImode, XVECEXP (vals, 0, 0));
-             rtx op1 = copy_to_mode_reg (DImode, XVECEXP (vals, 0, 1));
-             emit_insn (gen_vsx_concat_v2di (target, op0, op1));
-           }
+           emit_insn (gen_vsx_concat_v2di (target, op0, op1));
        }
       return;
     }
@@ -4727,7 +4645,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
       if (all_same)
        {
          rtx freg = gen_reg_rtx (V4SFmode);
-         rtx sreg = copy_to_reg (XVECEXP (vals, 0, 0));
+         rtx sreg = force_reg (SFmode, XVECEXP (vals, 0, 0));
 
          emit_insn (gen_vsx_xscvdpsp_scalar (freg, sreg));
          emit_insn (gen_vsx_xxspltw_v4sf (target, freg, const0_rtx));
@@ -4738,25 +4656,25 @@ rs6000_expand_vector_init (rtx target, rtx vals)
          rtx dbl_odd  = gen_reg_rtx (V2DFmode);
          rtx flt_even = gen_reg_rtx (V4SFmode);
          rtx flt_odd  = gen_reg_rtx (V4SFmode);
+         rtx op0 = force_reg (SFmode, XVECEXP (vals, 0, 0));
+         rtx op1 = force_reg (SFmode, XVECEXP (vals, 0, 1));
+         rtx op2 = force_reg (SFmode, XVECEXP (vals, 0, 2));
+         rtx op3 = force_reg (SFmode, XVECEXP (vals, 0, 3));
 
-         emit_insn (gen_vsx_concat_v2sf (dbl_even,
-                                         copy_to_reg (XVECEXP (vals, 0, 0)),
-                                         copy_to_reg (XVECEXP (vals, 0, 1))));
-         emit_insn (gen_vsx_concat_v2sf (dbl_odd,
-                                         copy_to_reg (XVECEXP (vals, 0, 2)),
-                                         copy_to_reg (XVECEXP (vals, 0, 3))));
+         emit_insn (gen_vsx_concat_v2sf (dbl_even, op0, op1));
+         emit_insn (gen_vsx_concat_v2sf (dbl_odd, op2, op3));
          emit_insn (gen_vsx_xvcvdpsp (flt_even, dbl_even));
          emit_insn (gen_vsx_xvcvdpsp (flt_odd, dbl_odd));
-         emit_insn (gen_vec_extract_evenv4sf (target, flt_even, flt_odd));
+         rs6000_expand_extract_even (target, flt_even, flt_odd);
        }
       return;
     }
 
   /* Store value to stack temp.  Load vector element.  Splat.  However, splat
      of 64-bit items is not supported on Altivec.  */
-  if (all_same && GET_MODE_SIZE (mode) <= 4)
+  if (all_same && GET_MODE_SIZE (inner_mode) <= 4)
     {
-      mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+      mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode));
       emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
                      XVECEXP (vals, 0, 0));
       x = gen_rtx_UNSPEC (VOIDmode,
@@ -4792,7 +4710,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
 
   /* 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);
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode));
   for (i = 0; i < n_elts; i++)
     emit_move_insn (adjust_address_nv (mem, inner_mode,
                                    i * GET_MODE_SIZE (inner_mode)),
@@ -4821,7 +4739,7 @@ rs6000_expand_vector_set (rtx target, rtx val, int elt)
     }
 
   /* Load single variable value.  */
-  mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode), 0);
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (inner_mode));
   emit_move_insn (adjust_address_nv (mem, inner_mode, 0), val);
   x = gen_rtx_UNSPEC (VOIDmode,
                      gen_rtvec (1, const0_rtx), UNSPEC_LVE);
@@ -4876,7 +4794,7 @@ rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
     }
 
   /* Allocate mode-sized buffer.  */
-  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+  mem = assign_stack_temp (mode, GET_MODE_SIZE (mode));
 
   emit_move_insn (mem, vec);
 
@@ -5117,6 +5035,78 @@ gpr_or_gpr_p (rtx op0, rtx op1)
          || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
 }
 
+/* Given an address, return a constant offset term if one exists.  */
+
+static rtx
+address_offset (rtx op)
+{
+  if (GET_CODE (op) == PRE_INC
+      || GET_CODE (op) == PRE_DEC)
+    op = XEXP (op, 0);
+  else if (GET_CODE (op) == PRE_MODIFY
+          || GET_CODE (op) == LO_SUM)
+    op = XEXP (op, 1);
+
+  if (GET_CODE (op) == CONST)
+    op = XEXP (op, 0);
+
+  if (GET_CODE (op) == PLUS)
+    op = XEXP (op, 1);
+
+  if (CONST_INT_P (op))
+    return op;
+
+  return NULL_RTX;
+}
+
+/* Return true if the MEM operand is a memory operand suitable for use
+   with a (full width, possibly multiple) gpr load/store.  On
+   powerpc64 this means the offset must be divisible by 4.
+   Implements 'Y' constraint.
+
+   Accept direct, indexed, offset, lo_sum and tocref.  Since this is
+   a constraint function we know the operand has satisfied a suitable
+   memory predicate.  Also accept some odd rtl generated by reload
+   (see rs6000_legitimize_reload_address for various forms).  It is
+   important that reload rtl be accepted by appropriate constraints
+   but not by the operand predicate.
+
+   Offsetting a lo_sum should not be allowed, except where we know by
+   alignment that a 32k boundary is not crossed, but see the ???
+   comment in rs6000_legitimize_reload_address.  Note that by
+   "offsetting" here we mean a further offset to access parts of the
+   MEM.  It's fine to have a lo_sum where the inner address is offset
+   from a sym, since the same sym+offset will appear in the high part
+   of the address calculation.  */
+
+bool
+mem_operand_gpr (rtx op, enum machine_mode mode)
+{
+  unsigned HOST_WIDE_INT offset;
+  int extra;
+  rtx addr = XEXP (op, 0);
+
+  op = address_offset (addr);
+  if (op == NULL_RTX)
+    return true;
+
+  offset = INTVAL (op);
+  if (TARGET_POWERPC64 && (offset & 3) != 0)
+    return false;
+
+  if (GET_CODE (addr) == LO_SUM)
+    /* We know by alignment that ABI_AIX medium/large model toc refs
+       will not cross a 32k boundary, since all entries in the
+       constant pool are naturally aligned and we check alignment for
+       other medium model toc-relative addresses.  For ABI_V4 and
+       ABI_DARWIN lo_sum addresses, we just check that 64-bit
+       offsets are 4-byte aligned.  */
+    return true;
+
+  extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
+  gcc_assert (extra >= 0);
+  return offset + 0x8000 < 0x10000u - extra;
+}
 \f
 /* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address_p.  */
 
@@ -5271,15 +5261,37 @@ constant_pool_expr_p (rtx op)
          && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (base), Pmode));
 }
 
-static rtx tocrel_base, tocrel_offset;
+static const_rtx tocrel_base, tocrel_offset;
+
+/* Return true if OP is a toc pointer relative address (the output
+   of create_TOC_reference).  If STRICT, do not match high part or
+   non-split -mcmodel=large/medium toc pointer relative addresses.  */
 
 bool
-toc_relative_expr_p (rtx op)
+toc_relative_expr_p (const_rtx op, bool strict)
 {
-  if (GET_CODE (op) != CONST)
+  if (!TARGET_TOC)
     return false;
 
-  split_const (op, &tocrel_base, &tocrel_offset);
+  if (TARGET_CMODEL != CMODEL_SMALL)
+    {
+      /* Only match the low part.  */
+      if (GET_CODE (op) == LO_SUM
+         && REG_P (XEXP (op, 0))
+         && INT_REG_OK_FOR_BASE_P (XEXP (op, 0), strict))
+       op = XEXP (op, 1);
+      else if (strict)
+       return false;
+    }
+
+  tocrel_base = op;
+  tocrel_offset = const0_rtx;
+  if (GET_CODE (op) == PLUS && CONST_INT_P (XEXP (op, 1)))
+    {
+      tocrel_base = XEXP (op, 0);
+      tocrel_offset = XEXP (op, 1);
+    }
+
   return (GET_CODE (tocrel_base) == UNSPEC
          && XINT (tocrel_base, 1) == UNSPEC_TOCREL);
 }
@@ -5291,14 +5303,7 @@ bool
 legitimate_constant_pool_address_p (const_rtx x, enum machine_mode mode,
                                    bool strict)
 {
-  return (TARGET_TOC
-         && (GET_CODE (x) == PLUS || GET_CODE (x) == LO_SUM)
-         && GET_CODE (XEXP (x, 0)) == REG
-         && (REGNO (XEXP (x, 0)) == TOC_REGISTER
-             || ((TARGET_MINIMAL_TOC
-                  || TARGET_CMODEL != CMODEL_SMALL)
-                 && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict)))
-         && toc_relative_expr_p (XEXP (x, 1))
+  return (toc_relative_expr_p (x, strict)
          && (TARGET_CMODEL != CMODEL_MEDIUM
              || constant_pool_expr_p (XVECEXP (tocrel_base, 0, 0))
              || mode == QImode
@@ -5319,13 +5324,15 @@ legitimate_small_data_p (enum machine_mode mode, rtx x)
 #define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
 
 bool
-rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
+rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x,
+                                   bool strict, bool worst_case)
 {
-  unsigned HOST_WIDE_INT offset, extra;
+  unsigned HOST_WIDE_INT offset;
+  unsigned int extra;
 
   if (GET_CODE (x) != PLUS)
     return false;
-  if (GET_CODE (XEXP (x, 0)) != REG)
+  if (!REG_P (XEXP (x, 0)))
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
@@ -5348,14 +5355,6 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       return SPE_CONST_OFFSET_OK (offset);
 
     case DFmode:
-      if (TARGET_E500_DOUBLE)
-       return SPE_CONST_OFFSET_OK (offset);
-
-      /* If we are using VSX scalar loads, restrict ourselves to reg+reg
-        addressing.  */
-      if (VECTOR_MEM_VSX_P (DFmode))
-       return false;
-
     case DDmode:
     case DImode:
       /* On e500v2, we may have:
@@ -5366,25 +5365,33 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       if (TARGET_E500_DOUBLE)
        return SPE_CONST_OFFSET_OK (offset);
 
-      if (mode == DFmode || mode == DDmode || !TARGET_POWERPC64)
+      /* If we are using VSX scalar loads, restrict ourselves to reg+reg
+        addressing.  */
+      if (mode == DFmode && VECTOR_MEM_VSX_P (DFmode))
+       return false;
+
+      if (!worst_case)
+       break;
+      if (!TARGET_POWERPC64)
        extra = 4;
       else if (offset & 3)
        return false;
       break;
 
     case TFmode:
+    case TDmode:
+    case TImode:
       if (TARGET_E500_DOUBLE)
        return (SPE_CONST_OFFSET_OK (offset)
                && SPE_CONST_OFFSET_OK (offset + 8));
 
-    case TDmode:
-    case TImode:
-      if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
+      extra = 8;
+      if (!worst_case)
+       break;
+      if (!TARGET_POWERPC64)
        extra = 12;
       else if (offset & 3)
        return false;
-      else
-       extra = 8;
       break;
 
     default:
@@ -5392,7 +5399,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     }
 
   offset += 0x8000;
-  return (offset < 0x10000) && (offset + extra < 0x10000);
+  return offset < 0x10000 - extra;
 }
 
 bool
@@ -5464,9 +5471,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
   /* Restrict addressing for DI because of our SUBREG hackery.  */
-  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                            || mode == DDmode || mode == TDmode
-                            || mode == DImode))
+  if (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     return false;
   x = XEXP (x, 1);
 
@@ -5478,10 +5483,10 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_NUNITS (mode) != 1)
        return false;
-      if (GET_MODE_BITSIZE (mode) > 64
-         || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
-             && !(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-                  && (mode == DFmode || mode == DDmode))))
+      if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+         && !(/* ??? Assume floating point reg based on mode?  */
+              TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+              && (mode == DFmode || mode == DDmode)))
        return false;
 
       return CONSTANT_P (x);
@@ -5516,7 +5521,7 @@ static rtx
 rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
                           enum machine_mode mode)
 {
-  unsigned int extra = 0;
+  unsigned int extra;
 
   if (!reg_offset_addressing_ok_p (mode))
     {
@@ -5543,22 +5548,18 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
        return rs6000_legitimize_tls_address (x, model);
     }
 
+  extra = 0;
   switch (mode)
     {
-    case DFmode:
-    case DDmode:
-      extra = 4;
-      break;
-    case DImode:
-      if (!TARGET_POWERPC64)
-       extra = 4;
-      break;
     case TFmode:
     case TDmode:
-      extra = 12;
-      break;
     case TImode:
-      extra = TARGET_POWERPC64 ? 8 : 12;
+      /* As in legitimate_offset_address_p we do not assume
+        worst-case.  The mode here is just a hint as to the registers
+        used.  A TImode is usually in gprs, but may actually be in
+        fprs.  Leave worst-case scenario for reload to handle via
+        insn constraints.  */
+      extra = 8;
       break;
     default:
       break;
@@ -5569,13 +5570,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000)
          >= 0x10000 - extra)
-      && !((TARGET_POWERPC64
-           && (mode == DImode || mode == TImode)
-           && (INTVAL (XEXP (x, 1)) & 3) != 0)
-          || SPE_VECTOR_MODE (mode)
-          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                                     || mode == DImode || mode == DDmode
-                                     || mode == TDmode))))
+      && !(SPE_VECTOR_MODE (mode)
+          || (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)))
     {
       HOST_WIDE_INT high_int, low_int;
       rtx sum;
@@ -5585,29 +5581,23 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       high_int = INTVAL (XEXP (x, 1)) - low_int;
       sum = force_operand (gen_rtx_PLUS (Pmode, XEXP (x, 0),
                                         GEN_INT (high_int)), 0);
-      return plus_constant (sum, low_int);
+      return plus_constant (Pmode, sum, low_int);
     }
   else if (GET_CODE (x) == PLUS
           && GET_CODE (XEXP (x, 0)) == REG
           && GET_CODE (XEXP (x, 1)) != CONST_INT
           && GET_MODE_NUNITS (mode) == 1
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
-              || TARGET_POWERPC64
-              || ((mode != DImode && mode != DFmode && mode != DDmode)
-                  || (TARGET_E500_DOUBLE && mode != DDmode)))
-          && (TARGET_POWERPC64 || mode != DImode)
-          && !avoiding_indexed_address_p (mode)
-          && mode != TImode
-          && mode != TFmode
-          && mode != TDmode)
+          && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+              || (/* ??? Assume floating point reg based on mode?  */
+                  (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
+                  && (mode == DFmode || mode == DDmode)))
+          && !avoiding_indexed_address_p (mode))
     {
       return gen_rtx_PLUS (Pmode, XEXP (x, 0),
                           force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
     }
   else if (SPE_VECTOR_MODE (mode)
-          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                                     || mode == DDmode || mode == TDmode
-                                     || mode == DImode)))
+          || (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
     {
       if (mode == DImode)
        return x;
@@ -5640,7 +5630,11 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 
       return force_reg (Pmode, x);
     }
-  else if (TARGET_ELF
+  else if ((TARGET_ELF
+#if TARGET_MACHO
+           || !MACHO_DYNAMIC_NO_PIC_P
+#endif
+           )
           && TARGET_32BIT
           && TARGET_NO_TOC
           && ! flag_pic
@@ -5648,40 +5642,23 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_CODE (x) != CONST_DOUBLE
           && CONSTANT_P (x)
           && GET_MODE_NUNITS (mode) == 1
-          && (GET_MODE_BITSIZE (mode) <= 32
-              || ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
+          && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+              || (/* ??? Assume floating point reg based on mode?  */
+                  (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
                   && (mode == DFmode || mode == DDmode))))
     {
       rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_elf_high (reg, x));
-      return gen_rtx_LO_SUM (Pmode, reg, x);
-    }
-  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
-          && ! flag_pic
-#if TARGET_MACHO
-          && ! MACHO_DYNAMIC_NO_PIC_P
-#endif
-          && GET_CODE (x) != CONST_INT
-          && GET_CODE (x) != CONST_DOUBLE
-          && CONSTANT_P (x)
-          && GET_MODE_NUNITS (mode) == 1
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
-              || (mode != DFmode && mode != DDmode))
-          && mode != DImode
-          && mode != TImode)
-    {
-      rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_macho_high (reg, x));
+      if (TARGET_ELF)
+       emit_insn (gen_elf_high (reg, x));
+      else
+       emit_insn (gen_macho_high (reg, x));
       return gen_rtx_LO_SUM (Pmode, reg, x);
     }
   else if (TARGET_TOC
           && GET_CODE (x) == SYMBOL_REF
           && constant_pool_expr_p (x)
           && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
-    {
-      rtx reg = TARGET_CMODEL != CMODEL_SMALL ? gen_reg_rtx (Pmode) : NULL_RTX;
-      return create_TOC_reference (x, reg);
-    }
+    return create_TOC_reference (x, NULL_RTX);
   else
     return x;
 }
@@ -5739,6 +5716,7 @@ rs6000_debug_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
 /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
+static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static void
 rs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
@@ -5764,53 +5742,59 @@ rs6000_output_dwarf_dtprel (FILE *file, int size, rtx x)
 static rtx
 rs6000_delegitimize_address (rtx orig_x)
 {
-  rtx x, y;
+  rtx x, y, offset;
 
   orig_x = delegitimize_mem_from_attrs (orig_x);
   x = orig_x;
   if (MEM_P (x))
     x = XEXP (x, 0);
 
-  if (GET_CODE (x) == (TARGET_CMODEL != CMODEL_SMALL ? LO_SUM : PLUS)
-      && GET_CODE (XEXP (x, 1)) == CONST)
+  y = x;
+  if (TARGET_CMODEL != CMODEL_SMALL
+      && GET_CODE (y) == LO_SUM)
+    y = XEXP (y, 1);
+
+  offset = NULL_RTX;
+  if (GET_CODE (y) == PLUS
+      && GET_MODE (y) == Pmode
+      && CONST_INT_P (XEXP (y, 1)))
     {
-      rtx offset = NULL_RTX;
+      offset = XEXP (y, 1);
+      y = XEXP (y, 0);
+    }
 
-      y = XEXP (XEXP (x, 1), 0);
-      if (GET_CODE (y) == PLUS
-         && GET_MODE (y) == Pmode
-         && CONST_INT_P (XEXP (y, 1)))
+  if (GET_CODE (y) == UNSPEC
+      && XINT (y, 1) == UNSPEC_TOCREL)
+    {
+#ifdef ENABLE_CHECKING
+      if (REG_P (XVECEXP (y, 0, 1))
+         && REGNO (XVECEXP (y, 0, 1)) == TOC_REGISTER)
        {
-         offset = XEXP (y, 1);
-         y = XEXP (y, 0);
+         /* All good.  */
        }
-      if (GET_CODE (y) == UNSPEC
-          && XINT (y, 1) == UNSPEC_TOCREL
-         && ((GET_CODE (XEXP (x, 0)) == REG
-              && (REGNO (XEXP (x, 0)) == TOC_REGISTER
-                  || TARGET_MINIMAL_TOC
-                  || TARGET_CMODEL != CMODEL_SMALL))
-             || (TARGET_CMODEL != CMODEL_SMALL
-                 && GET_CODE (XEXP (x, 0)) == CONST
-                 && GET_CODE (XEXP (XEXP (x, 0), 0)) == PLUS
-                 && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == REG
-                 && REGNO (XEXP (XEXP (XEXP (x, 0), 0), 0)) == TOC_REGISTER
-                 && GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)) == HIGH
-                 && rtx_equal_p (XEXP (x, 1),
-                                 XEXP (XEXP (XEXP (XEXP (x, 0), 0), 1), 0)))))
-       {
-         y = XVECEXP (y, 0, 0);
-         if (offset != NULL_RTX)
-           y = gen_rtx_PLUS (Pmode, y, offset);
-         if (!MEM_P (orig_x))
-           return y;
-         else
-           return replace_equiv_address_nv (orig_x, y);
+      else if (GET_CODE (XVECEXP (y, 0, 1)) == DEBUG_EXPR)
+       {
+         /* Weirdness alert.  df_note_compute can replace r2 with a
+            debug_expr when this unspec is in a debug_insn.
+            Seen in gcc.dg/pr51957-1.c  */
        }
-    }
-
-  if (TARGET_MACHO
-      && GET_CODE (orig_x) == LO_SUM
+      else
+       {
+         debug_rtx (orig_x);
+         abort ();
+       }
+#endif
+      y = XVECEXP (y, 0, 0);
+      if (offset != NULL_RTX)
+       y = gen_rtx_PLUS (Pmode, y, offset);
+      if (!MEM_P (orig_x))
+       return y;
+      else
+       return replace_equiv_address_nv (orig_x, y);
+    }
+
+  if (TARGET_MACHO
+      && GET_CODE (orig_x) == LO_SUM
       && GET_CODE (XEXP (orig_x, 1)) == CONST)
     {
       y = XEXP (XEXP (orig_x, 1), 0);
@@ -5822,6 +5806,25 @@ rs6000_delegitimize_address (rtx orig_x)
   return orig_x;
 }
 
+/* Return true if X shouldn't be emitted into the debug info.
+   The linker doesn't like .toc section references from
+   .debug_* sections, so reject .toc section symbols.  */
+
+static bool
+rs6000_const_not_ok_for_debug_p (rtx x)
+{
+  if (GET_CODE (x) == SYMBOL_REF
+      && CONSTANT_POOL_ADDRESS_P (x))
+    {
+      rtx c = get_pool_constant (x);
+      enum machine_mode cmode = get_pool_mode (x);
+      if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (c, cmode))
+       return true;
+    }
+
+  return false;
+}
+
 /* Construct the SYMBOL_REF for the tls_get_addr function.  */
 
 static GTY(()) rtx rs6000_tls_symbol;
@@ -5928,6 +5931,8 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                  lab = gen_label_rtx ();
                  emit_insn (gen_load_toc_v4_PIC_1b (gsym, lab));
                  emit_move_insn (tmp1, gen_rtx_REG (Pmode, LR_REGNO));
+                 if (TARGET_LINK_STACK)
+                   emit_insn (gen_addsi3 (tmp1, tmp1, GEN_INT (4)));
                  emit_move_insn (tmp2, mem);
                  last = emit_insn (gen_addsi3 (got, tmp1, tmp2));
                  set_unique_reg_note (last, REG_EQUAL, gsym);
@@ -6047,9 +6052,8 @@ rs6000_tls_referenced_p (rtx x)
 static bool
 rs6000_cannot_force_const_mem (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
 {
-  if (GET_CODE (x) == CONST
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == HIGH)
+  if (GET_CODE (x) == HIGH
+      && GET_CODE (XEXP (x, 0)) == UNSPEC)
     return true;
 
   return rs6000_tls_referenced_p (x);
@@ -6064,6 +6068,21 @@ rs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
   return RS6000_SYMBOL_REF_TLS_P (*x);
 }
 
+/* Return true iff the given SYMBOL_REF refers to a constant pool entry
+   that we have put in the TOC, or for cmodel=medium, if the SYMBOL_REF
+   can be addressed relative to the toc pointer.  */
+
+static bool
+use_toc_relative_ref (rtx sym)
+{
+  return ((constant_pool_expr_p (sym)
+          && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (sym),
+                                              get_pool_mode (sym)))
+         || (TARGET_CMODEL == CMODEL_MEDIUM
+             && !CONSTANT_POOL_ADDRESS_P (sym)
+             && SYMBOL_REF_LOCAL_P (sym)));
+}
+
 /* Our implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
    replace the input X, or the original X if no replacement is called for.
    The output parameter *WIN is 1 if the calling macro should goto WIN,
@@ -6101,7 +6120,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
     {
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                  opnum, (enum reload_type)type);
+                  opnum, (enum reload_type) type);
       *win = 1;
       return x;
     }
@@ -6112,7 +6131,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
     {
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-                  opnum, (enum reload_type)type);
+                  opnum, (enum reload_type) type);
       *win = 1;
       return x;
     }
@@ -6130,24 +6149,18 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
         floating point constant.  */
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-                  opnum, (enum reload_type)type);
+                  opnum, (enum reload_type) type);
       *win = 1;
       return x;
     }
 #endif
 
   if (TARGET_CMODEL != CMODEL_SMALL
-      && GET_CODE (x) == LO_SUM
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
-      && REGNO (XEXP (XEXP (x, 0), 0)) == TOC_REGISTER
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST
-      && GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 0)) == HIGH
-      && GET_CODE (XEXP (x, 1)) == CONST
-      && GET_CODE (XEXP (XEXP (x, 1), 0)) == UNSPEC
-      && XINT (XEXP (XEXP (x, 1), 0), 1) == UNSPEC_TOCREL
-      && rtx_equal_p (XEXP (XEXP (XEXP (XEXP (x, 0), 1), 0), 0), XEXP (x, 1)))
+      && reg_offset_p
+      && small_toc_ref (x, VOIDmode))
     {
+      rtx hi = gen_rtx_HIGH (Pmode, copy_rtx (x));
+      x = gen_rtx_LO_SUM (Pmode, hi, x);
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
                   opnum, (enum reload_type) type);
@@ -6210,7 +6223,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                  opnum, (enum reload_type)type);
+                  opnum, (enum reload_type) type);
       *win = 1;
       return x;
     }
@@ -6222,13 +6235,25 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 #if TARGET_MACHO
       && DEFAULT_ABI == ABI_DARWIN
       && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
+      && machopic_symbol_defined_p (x)
 #else
       && DEFAULT_ABI == ABI_V4
       && !flag_pic
 #endif
       /* Don't do this for TFmode or TDmode, since the result isn't offsettable.
         The same goes for DImode without 64-bit gprs and DFmode and DDmode
-        without fprs.  */
+        without fprs.
+        ??? Assume floating point reg based on mode?  This assumption is
+        violated by eg. powerpc-linux -m32 compile of gcc.dg/pr28796-2.c
+        where reload ends up doing a DFmode load of a constant from
+        mem using two gprs.  Unfortunately, at this point reload
+        hasn't yet selected regs so poking around in reload data
+        won't help and even if we could figure out the regs reliably,
+        we'd still want to allow this transformation when the mem is
+        naturally aligned.  Since we say the address is good here, we
+        can't disable offsets from LO_SUMs in mem_operand_gpr.
+        FIXME: Allow offset from lo_sum for other modes too, when
+        mem is sufficiently aligned.  */
       && mode != TFmode
       && mode != TDmode
       && (mode != DImode || TARGET_POWERPC64)
@@ -6250,7 +6275,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-                  opnum, (enum reload_type)type);
+                  opnum, (enum reload_type) type);
       *win = 1;
       return x;
     }
@@ -6277,8 +6302,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
   if (TARGET_TOC
       && reg_offset_p
       && GET_CODE (x) == SYMBOL_REF
-      && constant_pool_expr_p (x)
-      && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
+      && use_toc_relative_ref (x))
     {
       x = create_TOC_reference (x, NULL_RTX);
       if (TARGET_CMODEL != CMODEL_SMALL)
@@ -6336,7 +6360,7 @@ rs6000_debug_legitimize_reload_address (rtx x, enum machine_mode mode,
    32-bit DImode, TImode, TFmode, TDmode), indexed addressing cannot be used
    because adjacent memory cells are accessed by adding word-sized offsets
    during assembly output.  */
-bool
+static bool
 rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
 {
   bool reg_offset_p = reg_offset_addressing_ok_p (mode);
@@ -6379,7 +6403,7 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
          || XEXP (x, 0) == arg_pointer_rtx)
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     return 1;
-  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
+  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict, false))
     return 1;
   if (mode != TImode
       && mode != TFmode
@@ -6407,7 +6431,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
           && (mode == DFmode || mode == DDmode || mode == DImode))
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
-      && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), reg_ok_strict)
+      && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1),
+                                             reg_ok_strict, false)
          || (!avoiding_indexed_address_p (mode)
              && legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
       && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
@@ -6471,7 +6496,7 @@ rs6000_mode_dependent_address (const_rtx addr)
          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
        {
          unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
-         return val + 12 + 0x8000 >= 0x10000;
+         return val + 0x8000 >= 0x10000 - (TARGET_POWERPC64 ? 8 : 12);
        }
       break;
 
@@ -6513,9 +6538,13 @@ rs6000_debug_mode_dependent_address (const_rtx addr)
 rtx
 rs6000_find_base_term (rtx op)
 {
-  rtx base, offset;
+  rtx base;
 
-  split_const (op, &base, &offset);
+  base = op;
+  if (GET_CODE (base) == CONST)
+    base = XEXP (base, 0);
+  if (GET_CODE (base) == PLUS)
+    base = XEXP (base, 0);
   if (GET_CODE (base) == UNSPEC)
     switch (XINT (base, 1))
       {
@@ -6537,14 +6566,16 @@ rs6000_find_base_term (rtx op)
 
    in 32-bit mode, that the recog predicate rejects.  */
 
-bool
-rs6000_offsettable_memref_p (rtx op)
+static bool
+rs6000_offsettable_memref_p (rtx op, enum machine_mode reg_mode)
 {
+  bool worst_case;
+
   if (!MEM_P (op))
     return false;
 
   /* First mimic offsettable_memref_p.  */
-  if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
+  if (offsettable_address_p (true, GET_MODE (op), XEXP (op, 0)))
     return true;
 
   /* offsettable_address_p invokes rs6000_mode_dependent_address, but
@@ -6552,8 +6583,13 @@ rs6000_offsettable_memref_p (rtx op)
      reference and, therefore, assumes that it is the largest supported
      mode (TFmode).  As a consequence, legitimate offsettable memory
      references are rejected.  rs6000_legitimate_offset_address_p contains
-     the correct logic for the PLUS case of rs6000_mode_dependent_address.  */
-  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1);
+     the correct logic for the PLUS case of rs6000_mode_dependent_address,
+     at least with a little bit of help here given that we know the
+     actual registers used.  */
+  worst_case = ((TARGET_POWERPC64 && GET_MODE_CLASS (reg_mode) == MODE_INT)
+               || GET_MODE_SIZE (reg_mode) == 4);
+  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0),
+                                            true, worst_case);
 }
 
 /* Change register usage conditional on target flags.  */
@@ -6565,11 +6601,9 @@ rs6000_conditional_register_usage (void)
   if (TARGET_DEBUG_TARGET)
     fprintf (stderr, "rs6000_conditional_register_usage called\n");
 
-  /* Set MQ register fixed (already call_used) if not POWER
-     architecture (RIOS1, RIOS2, RSC, and PPC601) so that it will not
-     be allocated.  */
-  if (! TARGET_POWER)
-    fixed_regs[64] = 1;
+  /* Set MQ register fixed (already call_used) so that it will not be
+     allocated.  */
+  fixed_regs[64] = 1;
 
   /* 64-bit AIX and Linux reserve GPR13 for thread-private data.  */
   if (TARGET_64BIT)
@@ -6922,32 +6956,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       && !gpc_reg_operand (operands[1], mode))
     operands[1] = force_reg (mode, operands[1]);
 
-  if (mode == SFmode && ! TARGET_POWERPC
-      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
-      && GET_CODE (operands[0]) == MEM)
-    {
-      int regnum;
-
-      if (reload_in_progress || reload_completed)
-       regnum = true_regnum (operands[1]);
-      else if (GET_CODE (operands[1]) == REG)
-       regnum = REGNO (operands[1]);
-      else
-       regnum = -1;
-
-      /* If operands[1] is a register, on POWER it may have
-        double-precision data in it, so truncate it to single
-        precision.  */
-      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
-       {
-         rtx newreg;
-         newreg = (!can_create_pseudo_p () ? copy_rtx (operands[1])
-                   : gen_reg_rtx (mode));
-         emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
-         operands[1] = newreg;
-       }
-    }
-
   /* Recognize the case where operand[1] is a reference to thread-local
      data and load its address to a register.  */
   if (rs6000_tls_referenced_p (operands[1]))
@@ -6986,17 +6994,14 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
   if (!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
       && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
     {
-      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
-        know how to get a DFmode SUBREG of a TFmode.  */
-      enum machine_mode imode = (TARGET_E500_DOUBLE ? DFmode : DImode);
-      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode, 0),
-                       simplify_gen_subreg (imode, operands[1], mode, 0),
-                       imode);
-      rs6000_emit_move (simplify_gen_subreg (imode, operands[0], mode,
-                                            GET_MODE_SIZE (imode)),
-                       simplify_gen_subreg (imode, operands[1], mode,
-                                            GET_MODE_SIZE (imode)),
-                       imode);
+      rs6000_emit_move (simplify_gen_subreg (DFmode, operands[0], mode, 0),
+                       simplify_gen_subreg (DFmode, operands[1], mode, 0),
+                       DFmode);
+      rs6000_emit_move (simplify_gen_subreg (DFmode, operands[0], mode,
+                                            GET_MODE_SIZE (DFmode)),
+                       simplify_gen_subreg (DFmode, operands[1], mode,
+                                            GET_MODE_SIZE (DFmode)),
+                       DFmode);
       return;
     }
 
@@ -7170,33 +7175,13 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       /* If this is a SYMBOL_REF that refers to a constant pool entry,
         and we have put it in the TOC, we just need to make a TOC-relative
         reference to it.  */
-      if ((TARGET_TOC
-          && GET_CODE (operands[1]) == SYMBOL_REF
-          && constant_pool_expr_p (operands[1])
-          && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
-                                              get_pool_mode (operands[1])))
-         || (TARGET_CMODEL == CMODEL_MEDIUM
-             && GET_CODE (operands[1]) == SYMBOL_REF
-             && !CONSTANT_POOL_ADDRESS_P (operands[1])
-             && SYMBOL_REF_LOCAL_P (operands[1])))
-       {
-         rtx reg = NULL_RTX;
-         if (TARGET_CMODEL != CMODEL_SMALL)
-           {
-             if (can_create_pseudo_p ())
-               reg = gen_reg_rtx (Pmode);
-             else
-               reg = operands[0];
-           }
-         operands[1] = create_TOC_reference (operands[1], reg);
-       }
+      if (TARGET_TOC
+         && GET_CODE (operands[1]) == SYMBOL_REF
+         && use_toc_relative_ref (operands[1]))
+       operands[1] = create_TOC_reference (operands[1], operands[0]);
       else if (mode == Pmode
               && CONSTANT_P (operands[1])
               && GET_CODE (operands[1]) != HIGH
-              && !(TARGET_CMODEL != CMODEL_SMALL
-                   && GET_CODE (operands[1]) == CONST
-                   && GET_CODE (XEXP (operands[1], 0)) == PLUS
-                   && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == HIGH)
               && ((GET_CODE (operands[1]) != CONST_INT
                    && ! easy_fp_constant (operands[1], mode))
                   || (GET_CODE (operands[1]) == CONST_INT
@@ -7204,9 +7189,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                           > (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2)))
                   || (GET_CODE (operands[0]) == REG
                       && FP_REGNO_P (REGNO (operands[0]))))
-              && ! legitimate_constant_pool_address_p (operands[1], mode,
-                                                       false)
-              && ! toc_relative_expr_p (operands[1])
+              && !toc_relative_expr_p (operands[1], false)
               && (TARGET_CMODEL == CMODEL_SMALL
                   || can_create_pseudo_p ()
                   || (REG_P (operands[0])
@@ -7256,16 +7239,8 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                        get_pool_constant (XEXP (operands[1], 0)),
                        get_pool_mode (XEXP (operands[1], 0))))
            {
-             rtx tocref;
-             rtx reg = NULL_RTX;
-             if (TARGET_CMODEL != CMODEL_SMALL)
-               {
-                 if (can_create_pseudo_p ())
-                   reg = gen_reg_rtx (Pmode);
-                 else
-                   reg = operands[0];
-               }
-             tocref = create_TOC_reference (XEXP (operands[1], 0), reg);
+             rtx tocref = create_TOC_reference (XEXP (operands[1], 0),
+                                                operands[0]);
              operands[1] = gen_const_mem (mode, tocref);
              set_mem_alias_set (operands[1], get_TOC_alias_set ());
            }
@@ -7274,17 +7249,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 
     case TImode:
       rs6000_eliminate_indexed_memrefs (operands);
-
-      if (TARGET_POWER)
-       {
-         emit_insn (gen_rtx_PARALLEL (VOIDmode,
-                      gen_rtvec (2,
-                                 gen_rtx_SET (VOIDmode,
-                                              operands[0], operands[1]),
-                                 gen_rtx_CLOBBER (VOIDmode,
-                                                  gen_rtx_SCRATCH (SImode)))));
-         return;
-       }
       break;
 
     default:
@@ -7300,6 +7264,26 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
  emit_set:
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
 }
+
+/* Return true if a structure, union or array containing FIELD should be
+   accessed using `BLKMODE'.
+
+   For the SPE, simd types are V2SI, and gcc can be tempted to put the
+   entire thing in a DI and use subregs to access the internals.
+   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
+   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
+   best thing to do is set structs to BLKmode and avoid Severe Tire
+   Damage.
+
+   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
+   fit into 1, whereas DI still needs two.  */
+
+static bool
+rs6000_member_type_forces_blk (const_tree field, enum machine_mode mode)
+{
+  return ((TARGET_SPE && TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+         || (TARGET_E500_DOUBLE && mode == DFmode));
+}
 \f
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
@@ -8923,7 +8907,7 @@ setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
            }
 
          cfun->machine->varargs_save_offset = offset;
-         save_area = plus_constant (virtual_stack_vars_rtx, offset);
+         save_area = plus_constant (Pmode, virtual_stack_vars_rtx, offset);
        }
     }
   else
@@ -8955,7 +8939,7 @@ setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
        }
 
       mem = gen_rtx_MEM (BLKmode,
-                        plus_constant (save_area,
+                        plus_constant (Pmode, save_area,
                                        first_reg_offset * reg_size));
       MEM_NOTRAP_P (mem) = 1;
       set_mem_alias_set (mem, set);
@@ -8993,7 +8977,7 @@ setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
        {
          mem = gen_rtx_MEM ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
                              ? DFmode : SFmode, 
-                             plus_constant (save_area, off));
+                             plus_constant (Pmode, save_area, off));
          MEM_NOTRAP_P (mem) = 1;
          set_mem_alias_set (mem, set);
          set_mem_align (mem, GET_MODE_ALIGNMENT (
@@ -9153,7 +9137,7 @@ rs6000_va_start (tree valist, rtx nextarg)
 
 /* Implement va_arg.  */
 
-tree
+static tree
 rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
                        gimple_seq *post_p)
 {
@@ -9396,7 +9380,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
       tree tmp = create_tmp_var (type, "va_arg_tmp");
       tree dest_addr = build_fold_addr_expr (tmp);
 
-      tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+      tree copy = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMCPY),
                                   3, dest_addr, addr, size_int (rsize * 4));
 
       gimplify_and_add (copy, pre_p);
@@ -9410,931 +9394,361 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
 /* Builtins.  */
 
 static void
-def_builtin (int mask, const char *name, tree type, int code)
+def_builtin (const char *name, tree type, enum rs6000_builtins code)
 {
-  if ((mask & target_flags) || TARGET_PAIRED_FLOAT)
-    {
-      tree t;
-      if (rs6000_builtin_decls[code])
-       fatal_error ("internal error: builtin function to %s already processed",
-                    name);
-
-      rs6000_builtin_decls[code] = t =
-        add_builtin_function (name, type, code, BUILT_IN_MD,
-                             NULL, NULL_TREE);
+  tree t;
+  unsigned classify = rs6000_builtin_info[(int)code].attr;
+  const char *attr_string = "";
 
-      gcc_assert (code >= 0 && code < (int)RS6000_BUILTIN_COUNT);
-      switch (builtin_classify[code])
-       {
-       default:
-         gcc_unreachable ();
+  gcc_assert (name != NULL);
+  gcc_assert (IN_RANGE ((int)code, 0, (int)RS6000_BUILTIN_COUNT));
 
-         /* assume builtin can do anything.  */
-       case RS6000_BTC_MISC:
-         break;
+  if (rs6000_builtin_decls[(int)code])
+    fatal_error ("internal error: builtin function %s already processed", name);
 
-         /* const function, function only depends on the inputs.  */
-       case RS6000_BTC_CONST:
-         TREE_READONLY (t) = 1;
-         TREE_NOTHROW (t) = 1;
-         break;
+  rs6000_builtin_decls[(int)code] = t =
+    add_builtin_function (name, type, (int)code, BUILT_IN_MD, NULL, NULL_TREE);
 
-         /* pure function, function can read global memory.  */
-       case RS6000_BTC_PURE:
+  /* Set any special attributes.  */
+  if ((classify & RS6000_BTC_CONST) != 0)
+    {
+      /* const function, function only depends on the inputs.  */
+      TREE_READONLY (t) = 1;
+      TREE_NOTHROW (t) = 1;
+      attr_string = ", pure";
+    }
+  else if ((classify & RS6000_BTC_PURE) != 0)
+    {
+      /* pure function, function can read global memory, but does not set any
+        external state.  */
+      DECL_PURE_P (t) = 1;
+      TREE_NOTHROW (t) = 1;
+      attr_string = ", const";
+    }
+  else if ((classify & RS6000_BTC_FP) != 0)
+    {
+      /* Function is a math function.  If rounding mode is on, then treat the
+        function as not reading global memory, but it can have arbitrary side
+        effects.  If it is off, then assume the function is a const function.
+        This mimics the ATTR_MATHFN_FPROUNDING attribute in
+        builtin-attribute.def that is used for the math functions. */
+      TREE_NOTHROW (t) = 1;
+      if (flag_rounding_math)
+       {
          DECL_PURE_P (t) = 1;
-         TREE_NOTHROW (t) = 1;
-         break;
-
-         /* Function is a math function.  If rounding mode is on, then treat
-            the function as not reading global memory, but it can have
-            arbitrary side effects.  If it is off, then assume the function is
-            a const function.  This mimics the ATTR_MATHFN_FPROUNDING
-            attribute in builtin-attribute.def that is used for the math
-            functions. */
-       case RS6000_BTC_FP_PURE:
-         TREE_NOTHROW (t) = 1;
-         if (flag_rounding_math)
-           {
-             DECL_PURE_P (t) = 1;
-             DECL_IS_NOVOPS (t) = 1;
-           }
-         else
-           TREE_READONLY (t) = 1;
-         break;
+         DECL_IS_NOVOPS (t) = 1;
+         attr_string = ", fp, pure";
+       }
+      else
+       {
+         TREE_READONLY (t) = 1;
+         attr_string = ", fp, const";
        }
     }
+  else if ((classify & RS6000_BTC_ATTR_MASK) != 0)
+    gcc_unreachable ();
+
+  if (TARGET_DEBUG_BUILTIN)
+    fprintf (stderr, "rs6000_builtin, code = %4d, %s%s\n",
+            (int)code, name, attr_string);
 }
 
 /* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
 
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
 static const struct builtin_description bdesc_3arg[] =
 {
-  { MASK_ALTIVEC, CODE_FOR_fmav4sf4, "__builtin_altivec_vmaddfp", ALTIVEC_BUILTIN_VMADDFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmhaddshs, "__builtin_altivec_vmhaddshs", ALTIVEC_BUILTIN_VMHADDSHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmhraddshs, "__builtin_altivec_vmhraddshs", ALTIVEC_BUILTIN_VMHRADDSHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmladduhm, "__builtin_altivec_vmladduhm", ALTIVEC_BUILTIN_VMLADDUHM},
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumubm, "__builtin_altivec_vmsumubm", ALTIVEC_BUILTIN_VMSUMUBM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsummbm, "__builtin_altivec_vmsummbm", ALTIVEC_BUILTIN_VMSUMMBM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhm, "__builtin_altivec_vmsumuhm", ALTIVEC_BUILTIN_VMSUMUHM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshm, "__builtin_altivec_vmsumshm", ALTIVEC_BUILTIN_VMSUMSHM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
-  { MASK_ALTIVEC, CODE_FOR_nfmsv4sf4, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v2df, "__builtin_altivec_vperm_2df", ALTIVEC_BUILTIN_VPERM_2DF },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v2di, "__builtin_altivec_vperm_2di", ALTIVEC_BUILTIN_VPERM_2DI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v16qi_uns, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v2di_uns, "__builtin_altivec_vperm_2di_uns", ALTIVEC_BUILTIN_VPERM_2DI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4si_uns, "__builtin_altivec_vperm_4si_uns", ALTIVEC_BUILTIN_VPERM_4SI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v8hi_uns, "__builtin_altivec_vperm_8hi_uns", ALTIVEC_BUILTIN_VPERM_8HI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v16qi_uns, "__builtin_altivec_vperm_16qi_uns", ALTIVEC_BUILTIN_VPERM_16QI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v2df, "__builtin_altivec_vsel_2df", ALTIVEC_BUILTIN_VSEL_2DF },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v2di, "__builtin_altivec_vsel_2di", ALTIVEC_BUILTIN_VSEL_2DI },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v4si_uns, "__builtin_altivec_vsel_4si_uns", ALTIVEC_BUILTIN_VSEL_4SI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v8hi_uns, "__builtin_altivec_vsel_8hi_uns", ALTIVEC_BUILTIN_VSEL_8HI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v16qi_uns, "__builtin_altivec_vsel_16qi_uns", ALTIVEC_BUILTIN_VSEL_16QI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_vector_select_v2di_uns, "__builtin_altivec_vsel_2di_uns", ALTIVEC_BUILTIN_VSEL_2DI_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
-  { 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 },
-
-  { MASK_VSX, CODE_FOR_fmav2df4, "__builtin_vsx_xvmadddp", VSX_BUILTIN_XVMADDDP },
-  { MASK_VSX, CODE_FOR_fmsv2df4, "__builtin_vsx_xvmsubdp", VSX_BUILTIN_XVMSUBDP },
-  { MASK_VSX, CODE_FOR_nfmav2df4, "__builtin_vsx_xvnmadddp", VSX_BUILTIN_XVNMADDDP },
-  { MASK_VSX, CODE_FOR_nfmsv2df4, "__builtin_vsx_xvnmsubdp", VSX_BUILTIN_XVNMSUBDP },
-
-  { MASK_VSX, CODE_FOR_fmav4sf4, "__builtin_vsx_xvmaddsp", VSX_BUILTIN_XVMADDSP },
-  { MASK_VSX, CODE_FOR_fmsv4sf4, "__builtin_vsx_xvmsubsp", VSX_BUILTIN_XVMSUBSP },
-  { MASK_VSX, CODE_FOR_nfmav4sf4, "__builtin_vsx_xvnmaddsp", VSX_BUILTIN_XVNMADDSP },
-  { MASK_VSX, CODE_FOR_nfmsv4sf4, "__builtin_vsx_xvnmsubsp", VSX_BUILTIN_XVNMSUBSP },
-
-  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_msub", VSX_BUILTIN_VEC_MSUB },
-  { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nmadd", VSX_BUILTIN_VEC_NMADD },
-
-  { MASK_VSX, CODE_FOR_vector_select_v2di, "__builtin_vsx_xxsel_2di", VSX_BUILTIN_XXSEL_2DI },
-  { MASK_VSX, CODE_FOR_vector_select_v2df, "__builtin_vsx_xxsel_2df", VSX_BUILTIN_XXSEL_2DF },
-  { MASK_VSX, CODE_FOR_vector_select_v4sf, "__builtin_vsx_xxsel_4sf", VSX_BUILTIN_XXSEL_4SF },
-  { MASK_VSX, CODE_FOR_vector_select_v4si, "__builtin_vsx_xxsel_4si", VSX_BUILTIN_XXSEL_4SI },
-  { MASK_VSX, CODE_FOR_vector_select_v8hi, "__builtin_vsx_xxsel_8hi", VSX_BUILTIN_XXSEL_8HI },
-  { MASK_VSX, CODE_FOR_vector_select_v16qi, "__builtin_vsx_xxsel_16qi", VSX_BUILTIN_XXSEL_16QI },
-  { MASK_VSX, CODE_FOR_vector_select_v2di_uns, "__builtin_vsx_xxsel_2di_uns", VSX_BUILTIN_XXSEL_2DI_UNS },
-  { MASK_VSX, CODE_FOR_vector_select_v4si_uns, "__builtin_vsx_xxsel_4si_uns", VSX_BUILTIN_XXSEL_4SI_UNS },
-  { MASK_VSX, CODE_FOR_vector_select_v8hi_uns, "__builtin_vsx_xxsel_8hi_uns", VSX_BUILTIN_XXSEL_8HI_UNS },
-  { MASK_VSX, CODE_FOR_vector_select_v16qi_uns, "__builtin_vsx_xxsel_16qi_uns", VSX_BUILTIN_XXSEL_16QI_UNS },
-
-  { MASK_VSX, CODE_FOR_altivec_vperm_v2di, "__builtin_vsx_vperm_2di", VSX_BUILTIN_VPERM_2DI },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v2df, "__builtin_vsx_vperm_2df", VSX_BUILTIN_VPERM_2DF },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v4sf, "__builtin_vsx_vperm_4sf", VSX_BUILTIN_VPERM_4SF },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v4si, "__builtin_vsx_vperm_4si", VSX_BUILTIN_VPERM_4SI },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v8hi, "__builtin_vsx_vperm_8hi", VSX_BUILTIN_VPERM_8HI },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v16qi, "__builtin_vsx_vperm_16qi", VSX_BUILTIN_VPERM_16QI },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v2di_uns, "__builtin_vsx_vperm_2di_uns", VSX_BUILTIN_VPERM_2DI_UNS },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v4si_uns, "__builtin_vsx_vperm_4si_uns", VSX_BUILTIN_VPERM_4SI_UNS },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v8hi_uns, "__builtin_vsx_vperm_8hi_uns", VSX_BUILTIN_VPERM_8HI_UNS },
-  { MASK_VSX, CODE_FOR_altivec_vperm_v16qi_uns, "__builtin_vsx_vperm_16qi_uns", VSX_BUILTIN_VPERM_16QI_UNS },
-
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v2df, "__builtin_vsx_xxpermdi_2df", VSX_BUILTIN_XXPERMDI_2DF },
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v2di, "__builtin_vsx_xxpermdi_2di", VSX_BUILTIN_XXPERMDI_2DI },
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v4sf, "__builtin_vsx_xxpermdi_4sf", VSX_BUILTIN_XXPERMDI_4SF },
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v4si, "__builtin_vsx_xxpermdi_4si", VSX_BUILTIN_XXPERMDI_4SI },
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v8hi, "__builtin_vsx_xxpermdi_8hi", VSX_BUILTIN_XXPERMDI_8HI },
-  { MASK_VSX, CODE_FOR_vsx_xxpermdi_v16qi, "__builtin_vsx_xxpermdi_16qi", VSX_BUILTIN_XXPERMDI_16QI },
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vsx_xxpermdi", VSX_BUILTIN_VEC_XXPERMDI },
-  { MASK_VSX, CODE_FOR_vsx_set_v2df, "__builtin_vsx_set_2df", VSX_BUILTIN_SET_2DF },
-  { MASK_VSX, CODE_FOR_vsx_set_v2di, "__builtin_vsx_set_2di", VSX_BUILTIN_SET_2DI },
-
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v2di, "__builtin_vsx_xxsldwi_2di", VSX_BUILTIN_XXSLDWI_2DI },
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v2df, "__builtin_vsx_xxsldwi_2df", VSX_BUILTIN_XXSLDWI_2DF },
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v4sf, "__builtin_vsx_xxsldwi_4sf", VSX_BUILTIN_XXSLDWI_4SF },
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v4si, "__builtin_vsx_xxsldwi_4si", VSX_BUILTIN_XXSLDWI_4SI },
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v8hi, "__builtin_vsx_xxsldwi_8hi", VSX_BUILTIN_XXSLDWI_8HI },
-  { MASK_VSX, CODE_FOR_vsx_xxsldwi_v16qi, "__builtin_vsx_xxsldwi_16qi", VSX_BUILTIN_XXSLDWI_16QI },
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vsx_xxsldwi", VSX_BUILTIN_VEC_XXSLDWI },
-
-  { 0, CODE_FOR_fmsv2sf4, "__builtin_paired_msub", PAIRED_BUILTIN_MSUB },
-  { 0, CODE_FOR_fmav2sf4, "__builtin_paired_madd", PAIRED_BUILTIN_MADD },
-  { 0, CODE_FOR_paired_madds0, "__builtin_paired_madds0", PAIRED_BUILTIN_MADDS0 },
-  { 0, CODE_FOR_paired_madds1, "__builtin_paired_madds1", PAIRED_BUILTIN_MADDS1 },
-  { 0, CODE_FOR_nfmsv2sf4, "__builtin_paired_nmsub", PAIRED_BUILTIN_NMSUB },
-  { 0, CODE_FOR_nfmav2sf4, "__builtin_paired_nmadd", PAIRED_BUILTIN_NMADD },
-  { 0, CODE_FOR_paired_sum0, "__builtin_paired_sum0", PAIRED_BUILTIN_SUM0 },
-  { 0, CODE_FOR_paired_sum1, "__builtin_paired_sum1", PAIRED_BUILTIN_SUM1 },
-  { 0, CODE_FOR_selv2sf4, "__builtin_paired_selv2sf4", PAIRED_BUILTIN_SELV2SF4 },
+#include "rs6000-builtin.def"
 };
 
 /* DST operations: void foo (void *, const int, const char).  */
 
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
 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_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 }
+#include "rs6000-builtin.def"
 };
 
 /* Simple binary operations: VECc = foo (VECa, VECb).  */
 
-static struct builtin_description bdesc_2arg[] =
-{
-  { MASK_ALTIVEC, CODE_FOR_addv16qi3, "__builtin_altivec_vaddubm", ALTIVEC_BUILTIN_VADDUBM },
-  { MASK_ALTIVEC, CODE_FOR_addv8hi3, "__builtin_altivec_vadduhm", ALTIVEC_BUILTIN_VADDUHM },
-  { MASK_ALTIVEC, CODE_FOR_addv4si3, "__builtin_altivec_vadduwm", ALTIVEC_BUILTIN_VADDUWM },
-  { MASK_ALTIVEC, CODE_FOR_addv4sf3, "__builtin_altivec_vaddfp", ALTIVEC_BUILTIN_VADDFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vaddcuw, "__builtin_altivec_vaddcuw", ALTIVEC_BUILTIN_VADDCUW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vaddubs, "__builtin_altivec_vaddubs", ALTIVEC_BUILTIN_VADDUBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsbs, "__builtin_altivec_vaddsbs", ALTIVEC_BUILTIN_VADDSBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vadduhs, "__builtin_altivec_vadduhs", ALTIVEC_BUILTIN_VADDUHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vaddshs, "__builtin_altivec_vaddshs", ALTIVEC_BUILTIN_VADDSHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
-  { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
-  { MASK_ALTIVEC, CODE_FOR_andcv4si3, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsh, "__builtin_altivec_vavgsh", ALTIVEC_BUILTIN_VAVGSH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavguw, "__builtin_altivec_vavguw", ALTIVEC_BUILTIN_VAVGUW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vavgsw, "__builtin_altivec_vavgsw", ALTIVEC_BUILTIN_VAVGSW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vcfux, "__builtin_altivec_vcfux", ALTIVEC_BUILTIN_VCFUX },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vcfsx, "__builtin_altivec_vcfsx", ALTIVEC_BUILTIN_VCFSX },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp, "__builtin_altivec_vcmpbfp", ALTIVEC_BUILTIN_VCMPBFP },
-  { MASK_ALTIVEC, CODE_FOR_vector_eqv16qi, "__builtin_altivec_vcmpequb", ALTIVEC_BUILTIN_VCMPEQUB },
-  { MASK_ALTIVEC, CODE_FOR_vector_eqv8hi, "__builtin_altivec_vcmpequh", ALTIVEC_BUILTIN_VCMPEQUH },
-  { MASK_ALTIVEC, CODE_FOR_vector_eqv4si, "__builtin_altivec_vcmpequw", ALTIVEC_BUILTIN_VCMPEQUW },
-  { MASK_ALTIVEC, CODE_FOR_vector_eqv4sf, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP },
-  { MASK_ALTIVEC, CODE_FOR_vector_gev4sf, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtuv16qi, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtv16qi, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtuv8hi, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtv8hi, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtuv4si, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtv4si, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtv4sf, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vctuxs, "__builtin_altivec_vctuxs", ALTIVEC_BUILTIN_VCTUXS },
-  { MASK_ALTIVEC, CODE_FOR_umaxv16qi3, "__builtin_altivec_vmaxub", ALTIVEC_BUILTIN_VMAXUB },
-  { MASK_ALTIVEC, CODE_FOR_smaxv16qi3, "__builtin_altivec_vmaxsb", ALTIVEC_BUILTIN_VMAXSB },
-  { MASK_ALTIVEC, CODE_FOR_umaxv8hi3, "__builtin_altivec_vmaxuh", ALTIVEC_BUILTIN_VMAXUH },
-  { MASK_ALTIVEC, CODE_FOR_smaxv8hi3, "__builtin_altivec_vmaxsh", ALTIVEC_BUILTIN_VMAXSH },
-  { MASK_ALTIVEC, CODE_FOR_umaxv4si3, "__builtin_altivec_vmaxuw", ALTIVEC_BUILTIN_VMAXUW },
-  { MASK_ALTIVEC, CODE_FOR_smaxv4si3, "__builtin_altivec_vmaxsw", ALTIVEC_BUILTIN_VMAXSW },
-  { MASK_ALTIVEC, CODE_FOR_smaxv4sf3, "__builtin_altivec_vmaxfp", ALTIVEC_BUILTIN_VMAXFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghb, "__builtin_altivec_vmrghb", ALTIVEC_BUILTIN_VMRGHB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghh, "__builtin_altivec_vmrghh", ALTIVEC_BUILTIN_VMRGHH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrghw, "__builtin_altivec_vmrghw", ALTIVEC_BUILTIN_VMRGHW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglb, "__builtin_altivec_vmrglb", ALTIVEC_BUILTIN_VMRGLB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglh, "__builtin_altivec_vmrglh", ALTIVEC_BUILTIN_VMRGLH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmrglw, "__builtin_altivec_vmrglw", ALTIVEC_BUILTIN_VMRGLW },
-  { MASK_ALTIVEC, CODE_FOR_uminv16qi3, "__builtin_altivec_vminub", ALTIVEC_BUILTIN_VMINUB },
-  { MASK_ALTIVEC, CODE_FOR_sminv16qi3, "__builtin_altivec_vminsb", ALTIVEC_BUILTIN_VMINSB },
-  { MASK_ALTIVEC, CODE_FOR_uminv8hi3, "__builtin_altivec_vminuh", ALTIVEC_BUILTIN_VMINUH },
-  { MASK_ALTIVEC, CODE_FOR_sminv8hi3, "__builtin_altivec_vminsh", ALTIVEC_BUILTIN_VMINSH },
-  { MASK_ALTIVEC, CODE_FOR_uminv4si3, "__builtin_altivec_vminuw", ALTIVEC_BUILTIN_VMINUW },
-  { MASK_ALTIVEC, CODE_FOR_sminv4si3, "__builtin_altivec_vminsw", ALTIVEC_BUILTIN_VMINSW },
-  { MASK_ALTIVEC, CODE_FOR_sminv4sf3, "__builtin_altivec_vminfp", ALTIVEC_BUILTIN_VMINFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub", ALTIVEC_BUILTIN_VMULEUB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleub, "__builtin_altivec_vmuleub_uns", ALTIVEC_BUILTIN_VMULEUB_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesb, "__builtin_altivec_vmulesb", ALTIVEC_BUILTIN_VMULESB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh", ALTIVEC_BUILTIN_VMULEUH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuleuh, "__builtin_altivec_vmuleuh_uns", ALTIVEC_BUILTIN_VMULEUH_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulesh, "__builtin_altivec_vmulesh", ALTIVEC_BUILTIN_VMULESH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub", ALTIVEC_BUILTIN_VMULOUB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmuloub, "__builtin_altivec_vmuloub_uns", ALTIVEC_BUILTIN_VMULOUB_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh_uns", ALTIVEC_BUILTIN_VMULOUH_UNS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
-  { MASK_ALTIVEC, CODE_FOR_norv4si3, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
-  { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkpx, "__builtin_altivec_vpkpx", ALTIVEC_BUILTIN_VPKPX },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshss, "__builtin_altivec_vpkshss", ALTIVEC_BUILTIN_VPKSHSS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswss, "__builtin_altivec_vpkswss", ALTIVEC_BUILTIN_VPKSWSS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhus, "__builtin_altivec_vpkuhus", ALTIVEC_BUILTIN_VPKUHUS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkshus, "__builtin_altivec_vpkshus", ALTIVEC_BUILTIN_VPKSHUS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwus, "__builtin_altivec_vpkuwus", ALTIVEC_BUILTIN_VPKUWUS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vpkswus, "__builtin_altivec_vpkswus", ALTIVEC_BUILTIN_VPKSWUS },
-  { MASK_ALTIVEC, CODE_FOR_recipv4sf3, "__builtin_altivec_vrecipdivfp", ALTIVEC_BUILTIN_VRECIPFP },
-  { MASK_ALTIVEC, CODE_FOR_vrotlv16qi3, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
-  { MASK_ALTIVEC, CODE_FOR_vrotlv8hi3, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
-  { MASK_ALTIVEC, CODE_FOR_vrotlv4si3, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
-  { MASK_ALTIVEC, CODE_FOR_vashlv16qi3, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
-  { MASK_ALTIVEC, CODE_FOR_vashlv8hi3, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
-  { MASK_ALTIVEC, CODE_FOR_vashlv4si3, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
-  { 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_vlshrv16qi3, "__builtin_altivec_vsrb", ALTIVEC_BUILTIN_VSRB },
-  { MASK_ALTIVEC, CODE_FOR_vlshrv8hi3, "__builtin_altivec_vsrh", ALTIVEC_BUILTIN_VSRH },
-  { MASK_ALTIVEC, CODE_FOR_vlshrv4si3, "__builtin_altivec_vsrw", ALTIVEC_BUILTIN_VSRW },
-  { MASK_ALTIVEC, CODE_FOR_vashrv16qi3, "__builtin_altivec_vsrab", ALTIVEC_BUILTIN_VSRAB },
-  { MASK_ALTIVEC, CODE_FOR_vashrv8hi3, "__builtin_altivec_vsrah", ALTIVEC_BUILTIN_VSRAH },
-  { MASK_ALTIVEC, CODE_FOR_vashrv4si3, "__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 },
-  { MASK_ALTIVEC, CODE_FOR_subv8hi3, "__builtin_altivec_vsubuhm", ALTIVEC_BUILTIN_VSUBUHM },
-  { MASK_ALTIVEC, CODE_FOR_subv4si3, "__builtin_altivec_vsubuwm", ALTIVEC_BUILTIN_VSUBUWM },
-  { MASK_ALTIVEC, CODE_FOR_subv4sf3, "__builtin_altivec_vsubfp", ALTIVEC_BUILTIN_VSUBFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubcuw, "__builtin_altivec_vsubcuw", ALTIVEC_BUILTIN_VSUBCUW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsububs, "__builtin_altivec_vsububs", ALTIVEC_BUILTIN_VSUBUBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsbs, "__builtin_altivec_vsubsbs", ALTIVEC_BUILTIN_VSUBSBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuhs, "__builtin_altivec_vsubuhs", ALTIVEC_BUILTIN_VSUBUHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubshs, "__builtin_altivec_vsubshs", ALTIVEC_BUILTIN_VSUBSHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubuws, "__builtin_altivec_vsubuws", ALTIVEC_BUILTIN_VSUBUWS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsubsws, "__builtin_altivec_vsubsws", ALTIVEC_BUILTIN_VSUBSWS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4ubs, "__builtin_altivec_vsum4ubs", ALTIVEC_BUILTIN_VSUM4UBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4sbs, "__builtin_altivec_vsum4sbs", ALTIVEC_BUILTIN_VSUM4SBS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsum4shs, "__builtin_altivec_vsum4shs", ALTIVEC_BUILTIN_VSUM4SHS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsum2sws, "__builtin_altivec_vsum2sws", ALTIVEC_BUILTIN_VSUM2SWS },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsumsws, "__builtin_altivec_vsumsws", ALTIVEC_BUILTIN_VSUMSWS },
-  { MASK_ALTIVEC, CODE_FOR_xorv4si3, "__builtin_altivec_vxor", ALTIVEC_BUILTIN_VXOR },
-  { MASK_ALTIVEC, CODE_FOR_vector_copysignv4sf3, "__builtin_altivec_copysignfp", ALTIVEC_BUILTIN_COPYSIGN_V4SF },
-
-  { MASK_VSX, CODE_FOR_addv2df3, "__builtin_vsx_xvadddp", VSX_BUILTIN_XVADDDP },
-  { MASK_VSX, CODE_FOR_subv2df3, "__builtin_vsx_xvsubdp", VSX_BUILTIN_XVSUBDP },
-  { MASK_VSX, CODE_FOR_mulv2df3, "__builtin_vsx_xvmuldp", VSX_BUILTIN_XVMULDP },
-  { MASK_VSX, CODE_FOR_divv2df3, "__builtin_vsx_xvdivdp", VSX_BUILTIN_XVDIVDP },
-  { MASK_VSX, CODE_FOR_recipv2df3, "__builtin_vsx_xvrecipdivdp", VSX_BUILTIN_RECIP_V2DF },
-  { MASK_VSX, CODE_FOR_sminv2df3, "__builtin_vsx_xvmindp", VSX_BUILTIN_XVMINDP },
-  { MASK_VSX, CODE_FOR_smaxv2df3, "__builtin_vsx_xvmaxdp", VSX_BUILTIN_XVMAXDP },
-  { MASK_VSX, CODE_FOR_vsx_tdivv2df3_fe, "__builtin_vsx_xvtdivdp_fe", VSX_BUILTIN_XVTDIVDP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tdivv2df3_fg, "__builtin_vsx_xvtdivdp_fg", VSX_BUILTIN_XVTDIVDP_FG },
-  { MASK_VSX, CODE_FOR_vector_eqv2df, "__builtin_vsx_xvcmpeqdp", VSX_BUILTIN_XVCMPEQDP },
-  { MASK_VSX, CODE_FOR_vector_gtv2df, "__builtin_vsx_xvcmpgtdp", VSX_BUILTIN_XVCMPGTDP },
-  { MASK_VSX, CODE_FOR_vector_gev2df, "__builtin_vsx_xvcmpgedp", VSX_BUILTIN_XVCMPGEDP },
-
-  { MASK_VSX, CODE_FOR_addv4sf3, "__builtin_vsx_xvaddsp", VSX_BUILTIN_XVADDSP },
-  { MASK_VSX, CODE_FOR_subv4sf3, "__builtin_vsx_xvsubsp", VSX_BUILTIN_XVSUBSP },
-  { MASK_VSX, CODE_FOR_mulv4sf3, "__builtin_vsx_xvmulsp", VSX_BUILTIN_XVMULSP },
-  { MASK_VSX, CODE_FOR_divv4sf3, "__builtin_vsx_xvdivsp", VSX_BUILTIN_XVDIVSP },
-  { MASK_VSX, CODE_FOR_recipv4sf3, "__builtin_vsx_xvrecipdivsp", VSX_BUILTIN_RECIP_V4SF },
-  { MASK_VSX, CODE_FOR_sminv4sf3, "__builtin_vsx_xvminsp", VSX_BUILTIN_XVMINSP },
-  { MASK_VSX, CODE_FOR_smaxv4sf3, "__builtin_vsx_xvmaxsp", VSX_BUILTIN_XVMAXSP },
-  { MASK_VSX, CODE_FOR_vsx_tdivv4sf3_fe, "__builtin_vsx_xvtdivsp_fe", VSX_BUILTIN_XVTDIVSP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tdivv4sf3_fg, "__builtin_vsx_xvtdivsp_fg", VSX_BUILTIN_XVTDIVSP_FG },
-  { MASK_VSX, CODE_FOR_vector_eqv4sf, "__builtin_vsx_xvcmpeqsp", VSX_BUILTIN_XVCMPEQSP },
-  { MASK_VSX, CODE_FOR_vector_gtv4sf, "__builtin_vsx_xvcmpgtsp", VSX_BUILTIN_XVCMPGTSP },
-  { MASK_VSX, CODE_FOR_vector_gev4sf, "__builtin_vsx_xvcmpgesp", VSX_BUILTIN_XVCMPGESP },
-
-  { MASK_VSX, CODE_FOR_smindf3, "__builtin_vsx_xsmindp", VSX_BUILTIN_XSMINDP },
-  { MASK_VSX, CODE_FOR_smaxdf3, "__builtin_vsx_xsmaxdp", VSX_BUILTIN_XSMAXDP },
-  { MASK_VSX, CODE_FOR_vsx_tdivdf3_fe, "__builtin_vsx_xstdivdp_fe", VSX_BUILTIN_XSTDIVDP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tdivdf3_fg, "__builtin_vsx_xstdivdp_fg", VSX_BUILTIN_XSTDIVDP_FG },
-  { MASK_VSX, CODE_FOR_vector_copysignv2df3, "__builtin_vsx_cpsgndp", VSX_BUILTIN_CPSGNDP },
-  { MASK_VSX, CODE_FOR_vector_copysignv4sf3, "__builtin_vsx_cpsgnsp", VSX_BUILTIN_CPSGNSP },
-
-  { MASK_VSX, CODE_FOR_vsx_concat_v2df, "__builtin_vsx_concat_2df", VSX_BUILTIN_CONCAT_2DF },
-  { MASK_VSX, CODE_FOR_vsx_concat_v2di, "__builtin_vsx_concat_2di", VSX_BUILTIN_CONCAT_2DI },
-  { MASK_VSX, CODE_FOR_vsx_splat_v2df, "__builtin_vsx_splat_2df", VSX_BUILTIN_SPLAT_2DF },
-  { MASK_VSX, CODE_FOR_vsx_splat_v2di, "__builtin_vsx_splat_2di", VSX_BUILTIN_SPLAT_2DI },
-  { MASK_VSX, CODE_FOR_vsx_xxmrghw_v4sf, "__builtin_vsx_xxmrghw", VSX_BUILTIN_XXMRGHW_4SF },
-  { MASK_VSX, CODE_FOR_vsx_xxmrghw_v4si, "__builtin_vsx_xxmrghw_4si", VSX_BUILTIN_XXMRGHW_4SI },
-  { MASK_VSX, CODE_FOR_vsx_xxmrglw_v4sf, "__builtin_vsx_xxmrglw", VSX_BUILTIN_XXMRGLW_4SF },
-  { MASK_VSX, CODE_FOR_vsx_xxmrglw_v4si, "__builtin_vsx_xxmrglw_4si", VSX_BUILTIN_XXMRGLW_4SI },
-  { MASK_VSX, CODE_FOR_vec_interleave_lowv2df, "__builtin_vsx_mergel_2df", VSX_BUILTIN_VEC_MERGEL_V2DF },
-  { MASK_VSX, CODE_FOR_vec_interleave_lowv2di, "__builtin_vsx_mergel_2di", VSX_BUILTIN_VEC_MERGEL_V2DI },
-  { MASK_VSX, CODE_FOR_vec_interleave_highv2df, "__builtin_vsx_mergeh_2df", VSX_BUILTIN_VEC_MERGEH_V2DF },
-  { MASK_VSX, CODE_FOR_vec_interleave_highv2di, "__builtin_vsx_mergeh_2di", VSX_BUILTIN_VEC_MERGEH_V2DI },
-
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_add", ALTIVEC_BUILTIN_VEC_ADD },
-  { MASK_ALTIVEC|MASK_VSX, 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|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_and", ALTIVEC_BUILTIN_VEC_AND },
-  { MASK_ALTIVEC|MASK_VSX, 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_copysign", ALTIVEC_BUILTIN_VEC_COPYSIGN },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_max", ALTIVEC_BUILTIN_VEC_MAX },
-  { MASK_ALTIVEC|MASK_VSX, 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|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_min", ALTIVEC_BUILTIN_VEC_MIN },
-  { MASK_ALTIVEC|MASK_VSX, 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|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_nor", ALTIVEC_BUILTIN_VEC_NOR },
-  { MASK_ALTIVEC|MASK_VSX, 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_recipdiv", ALTIVEC_BUILTIN_VEC_RECIP },
-  { 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|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_sub", ALTIVEC_BUILTIN_VEC_SUB },
-  { MASK_ALTIVEC|MASK_VSX, 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|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_xor", ALTIVEC_BUILTIN_VEC_XOR },
-
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_mul", VSX_BUILTIN_VEC_MUL },
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_div", VSX_BUILTIN_VEC_DIV },
-
-  { 0, CODE_FOR_paired_divv2sf3, "__builtin_paired_divv2sf3", PAIRED_BUILTIN_DIVV2SF3 },
-  { 0, CODE_FOR_paired_addv2sf3, "__builtin_paired_addv2sf3", PAIRED_BUILTIN_ADDV2SF3 },
-  { 0, CODE_FOR_paired_subv2sf3, "__builtin_paired_subv2sf3", PAIRED_BUILTIN_SUBV2SF3 },
-  { 0, CODE_FOR_paired_mulv2sf3, "__builtin_paired_mulv2sf3", PAIRED_BUILTIN_MULV2SF3 },
-  { 0, CODE_FOR_paired_muls0, "__builtin_paired_muls0", PAIRED_BUILTIN_MULS0 },
-  { 0, CODE_FOR_paired_muls1, "__builtin_paired_muls1", PAIRED_BUILTIN_MULS1 },
-  { 0, CODE_FOR_paired_merge00, "__builtin_paired_merge00", PAIRED_BUILTIN_MERGE00 },
-  { 0, CODE_FOR_paired_merge01, "__builtin_paired_merge01", PAIRED_BUILTIN_MERGE01 },
-  { 0, CODE_FOR_paired_merge10, "__builtin_paired_merge10", PAIRED_BUILTIN_MERGE10 },
-  { 0, CODE_FOR_paired_merge11, "__builtin_paired_merge11", PAIRED_BUILTIN_MERGE11 },
-
-  /* Place holder, leave as first spe builtin.  */
-  { 0, CODE_FOR_addv2si3, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
-  { 0, CODE_FOR_andv2si3, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
-  { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC },
-  { 0, CODE_FOR_divv2si3, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS },
-  { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU },
-  { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV },
-  { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD },
-  { 0, CODE_FOR_spe_evfsdiv, "__builtin_spe_evfsdiv", SPE_BUILTIN_EVFSDIV },
-  { 0, CODE_FOR_spe_evfsmul, "__builtin_spe_evfsmul", SPE_BUILTIN_EVFSMUL },
-  { 0, CODE_FOR_spe_evfssub, "__builtin_spe_evfssub", SPE_BUILTIN_EVFSSUB },
-  { 0, CODE_FOR_spe_evmergehi, "__builtin_spe_evmergehi", SPE_BUILTIN_EVMERGEHI },
-  { 0, CODE_FOR_spe_evmergehilo, "__builtin_spe_evmergehilo", SPE_BUILTIN_EVMERGEHILO },
-  { 0, CODE_FOR_spe_evmergelo, "__builtin_spe_evmergelo", SPE_BUILTIN_EVMERGELO },
-  { 0, CODE_FOR_spe_evmergelohi, "__builtin_spe_evmergelohi", SPE_BUILTIN_EVMERGELOHI },
-  { 0, CODE_FOR_spe_evmhegsmfaa, "__builtin_spe_evmhegsmfaa", SPE_BUILTIN_EVMHEGSMFAA },
-  { 0, CODE_FOR_spe_evmhegsmfan, "__builtin_spe_evmhegsmfan", SPE_BUILTIN_EVMHEGSMFAN },
-  { 0, CODE_FOR_spe_evmhegsmiaa, "__builtin_spe_evmhegsmiaa", SPE_BUILTIN_EVMHEGSMIAA },
-  { 0, CODE_FOR_spe_evmhegsmian, "__builtin_spe_evmhegsmian", SPE_BUILTIN_EVMHEGSMIAN },
-  { 0, CODE_FOR_spe_evmhegumiaa, "__builtin_spe_evmhegumiaa", SPE_BUILTIN_EVMHEGUMIAA },
-  { 0, CODE_FOR_spe_evmhegumian, "__builtin_spe_evmhegumian", SPE_BUILTIN_EVMHEGUMIAN },
-  { 0, CODE_FOR_spe_evmhesmf, "__builtin_spe_evmhesmf", SPE_BUILTIN_EVMHESMF },
-  { 0, CODE_FOR_spe_evmhesmfa, "__builtin_spe_evmhesmfa", SPE_BUILTIN_EVMHESMFA },
-  { 0, CODE_FOR_spe_evmhesmfaaw, "__builtin_spe_evmhesmfaaw", SPE_BUILTIN_EVMHESMFAAW },
-  { 0, CODE_FOR_spe_evmhesmfanw, "__builtin_spe_evmhesmfanw", SPE_BUILTIN_EVMHESMFANW },
-  { 0, CODE_FOR_spe_evmhesmi, "__builtin_spe_evmhesmi", SPE_BUILTIN_EVMHESMI },
-  { 0, CODE_FOR_spe_evmhesmia, "__builtin_spe_evmhesmia", SPE_BUILTIN_EVMHESMIA },
-  { 0, CODE_FOR_spe_evmhesmiaaw, "__builtin_spe_evmhesmiaaw", SPE_BUILTIN_EVMHESMIAAW },
-  { 0, CODE_FOR_spe_evmhesmianw, "__builtin_spe_evmhesmianw", SPE_BUILTIN_EVMHESMIANW },
-  { 0, CODE_FOR_spe_evmhessf, "__builtin_spe_evmhessf", SPE_BUILTIN_EVMHESSF },
-  { 0, CODE_FOR_spe_evmhessfa, "__builtin_spe_evmhessfa", SPE_BUILTIN_EVMHESSFA },
-  { 0, CODE_FOR_spe_evmhessfaaw, "__builtin_spe_evmhessfaaw", SPE_BUILTIN_EVMHESSFAAW },
-  { 0, CODE_FOR_spe_evmhessfanw, "__builtin_spe_evmhessfanw", SPE_BUILTIN_EVMHESSFANW },
-  { 0, CODE_FOR_spe_evmhessiaaw, "__builtin_spe_evmhessiaaw", SPE_BUILTIN_EVMHESSIAAW },
-  { 0, CODE_FOR_spe_evmhessianw, "__builtin_spe_evmhessianw", SPE_BUILTIN_EVMHESSIANW },
-  { 0, CODE_FOR_spe_evmheumi, "__builtin_spe_evmheumi", SPE_BUILTIN_EVMHEUMI },
-  { 0, CODE_FOR_spe_evmheumia, "__builtin_spe_evmheumia", SPE_BUILTIN_EVMHEUMIA },
-  { 0, CODE_FOR_spe_evmheumiaaw, "__builtin_spe_evmheumiaaw", SPE_BUILTIN_EVMHEUMIAAW },
-  { 0, CODE_FOR_spe_evmheumianw, "__builtin_spe_evmheumianw", SPE_BUILTIN_EVMHEUMIANW },
-  { 0, CODE_FOR_spe_evmheusiaaw, "__builtin_spe_evmheusiaaw", SPE_BUILTIN_EVMHEUSIAAW },
-  { 0, CODE_FOR_spe_evmheusianw, "__builtin_spe_evmheusianw", SPE_BUILTIN_EVMHEUSIANW },
-  { 0, CODE_FOR_spe_evmhogsmfaa, "__builtin_spe_evmhogsmfaa", SPE_BUILTIN_EVMHOGSMFAA },
-  { 0, CODE_FOR_spe_evmhogsmfan, "__builtin_spe_evmhogsmfan", SPE_BUILTIN_EVMHOGSMFAN },
-  { 0, CODE_FOR_spe_evmhogsmiaa, "__builtin_spe_evmhogsmiaa", SPE_BUILTIN_EVMHOGSMIAA },
-  { 0, CODE_FOR_spe_evmhogsmian, "__builtin_spe_evmhogsmian", SPE_BUILTIN_EVMHOGSMIAN },
-  { 0, CODE_FOR_spe_evmhogumiaa, "__builtin_spe_evmhogumiaa", SPE_BUILTIN_EVMHOGUMIAA },
-  { 0, CODE_FOR_spe_evmhogumian, "__builtin_spe_evmhogumian", SPE_BUILTIN_EVMHOGUMIAN },
-  { 0, CODE_FOR_spe_evmhosmf, "__builtin_spe_evmhosmf", SPE_BUILTIN_EVMHOSMF },
-  { 0, CODE_FOR_spe_evmhosmfa, "__builtin_spe_evmhosmfa", SPE_BUILTIN_EVMHOSMFA },
-  { 0, CODE_FOR_spe_evmhosmfaaw, "__builtin_spe_evmhosmfaaw", SPE_BUILTIN_EVMHOSMFAAW },
-  { 0, CODE_FOR_spe_evmhosmfanw, "__builtin_spe_evmhosmfanw", SPE_BUILTIN_EVMHOSMFANW },
-  { 0, CODE_FOR_spe_evmhosmi, "__builtin_spe_evmhosmi", SPE_BUILTIN_EVMHOSMI },
-  { 0, CODE_FOR_spe_evmhosmia, "__builtin_spe_evmhosmia", SPE_BUILTIN_EVMHOSMIA },
-  { 0, CODE_FOR_spe_evmhosmiaaw, "__builtin_spe_evmhosmiaaw", SPE_BUILTIN_EVMHOSMIAAW },
-  { 0, CODE_FOR_spe_evmhosmianw, "__builtin_spe_evmhosmianw", SPE_BUILTIN_EVMHOSMIANW },
-  { 0, CODE_FOR_spe_evmhossf, "__builtin_spe_evmhossf", SPE_BUILTIN_EVMHOSSF },
-  { 0, CODE_FOR_spe_evmhossfa, "__builtin_spe_evmhossfa", SPE_BUILTIN_EVMHOSSFA },
-  { 0, CODE_FOR_spe_evmhossfaaw, "__builtin_spe_evmhossfaaw", SPE_BUILTIN_EVMHOSSFAAW },
-  { 0, CODE_FOR_spe_evmhossfanw, "__builtin_spe_evmhossfanw", SPE_BUILTIN_EVMHOSSFANW },
-  { 0, CODE_FOR_spe_evmhossiaaw, "__builtin_spe_evmhossiaaw", SPE_BUILTIN_EVMHOSSIAAW },
-  { 0, CODE_FOR_spe_evmhossianw, "__builtin_spe_evmhossianw", SPE_BUILTIN_EVMHOSSIANW },
-  { 0, CODE_FOR_spe_evmhoumi, "__builtin_spe_evmhoumi", SPE_BUILTIN_EVMHOUMI },
-  { 0, CODE_FOR_spe_evmhoumia, "__builtin_spe_evmhoumia", SPE_BUILTIN_EVMHOUMIA },
-  { 0, CODE_FOR_spe_evmhoumiaaw, "__builtin_spe_evmhoumiaaw", SPE_BUILTIN_EVMHOUMIAAW },
-  { 0, CODE_FOR_spe_evmhoumianw, "__builtin_spe_evmhoumianw", SPE_BUILTIN_EVMHOUMIANW },
-  { 0, CODE_FOR_spe_evmhousiaaw, "__builtin_spe_evmhousiaaw", SPE_BUILTIN_EVMHOUSIAAW },
-  { 0, CODE_FOR_spe_evmhousianw, "__builtin_spe_evmhousianw", SPE_BUILTIN_EVMHOUSIANW },
-  { 0, CODE_FOR_spe_evmwhsmf, "__builtin_spe_evmwhsmf", SPE_BUILTIN_EVMWHSMF },
-  { 0, CODE_FOR_spe_evmwhsmfa, "__builtin_spe_evmwhsmfa", SPE_BUILTIN_EVMWHSMFA },
-  { 0, CODE_FOR_spe_evmwhsmi, "__builtin_spe_evmwhsmi", SPE_BUILTIN_EVMWHSMI },
-  { 0, CODE_FOR_spe_evmwhsmia, "__builtin_spe_evmwhsmia", SPE_BUILTIN_EVMWHSMIA },
-  { 0, CODE_FOR_spe_evmwhssf, "__builtin_spe_evmwhssf", SPE_BUILTIN_EVMWHSSF },
-  { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
-  { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
-  { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
-  { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
-  { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
-  { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
-  { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
-  { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
-  { 0, CODE_FOR_spe_evmwlumia, "__builtin_spe_evmwlumia", SPE_BUILTIN_EVMWLUMIA },
-  { 0, CODE_FOR_spe_evmwlumiaaw, "__builtin_spe_evmwlumiaaw", SPE_BUILTIN_EVMWLUMIAAW },
-  { 0, CODE_FOR_spe_evmwlumianw, "__builtin_spe_evmwlumianw", SPE_BUILTIN_EVMWLUMIANW },
-  { 0, CODE_FOR_spe_evmwlusiaaw, "__builtin_spe_evmwlusiaaw", SPE_BUILTIN_EVMWLUSIAAW },
-  { 0, CODE_FOR_spe_evmwlusianw, "__builtin_spe_evmwlusianw", SPE_BUILTIN_EVMWLUSIANW },
-  { 0, CODE_FOR_spe_evmwsmf, "__builtin_spe_evmwsmf", SPE_BUILTIN_EVMWSMF },
-  { 0, CODE_FOR_spe_evmwsmfa, "__builtin_spe_evmwsmfa", SPE_BUILTIN_EVMWSMFA },
-  { 0, CODE_FOR_spe_evmwsmfaa, "__builtin_spe_evmwsmfaa", SPE_BUILTIN_EVMWSMFAA },
-  { 0, CODE_FOR_spe_evmwsmfan, "__builtin_spe_evmwsmfan", SPE_BUILTIN_EVMWSMFAN },
-  { 0, CODE_FOR_spe_evmwsmi, "__builtin_spe_evmwsmi", SPE_BUILTIN_EVMWSMI },
-  { 0, CODE_FOR_spe_evmwsmia, "__builtin_spe_evmwsmia", SPE_BUILTIN_EVMWSMIA },
-  { 0, CODE_FOR_spe_evmwsmiaa, "__builtin_spe_evmwsmiaa", SPE_BUILTIN_EVMWSMIAA },
-  { 0, CODE_FOR_spe_evmwsmian, "__builtin_spe_evmwsmian", SPE_BUILTIN_EVMWSMIAN },
-  { 0, CODE_FOR_spe_evmwssf, "__builtin_spe_evmwssf", SPE_BUILTIN_EVMWSSF },
-  { 0, CODE_FOR_spe_evmwssfa, "__builtin_spe_evmwssfa", SPE_BUILTIN_EVMWSSFA },
-  { 0, CODE_FOR_spe_evmwssfaa, "__builtin_spe_evmwssfaa", SPE_BUILTIN_EVMWSSFAA },
-  { 0, CODE_FOR_spe_evmwssfan, "__builtin_spe_evmwssfan", SPE_BUILTIN_EVMWSSFAN },
-  { 0, CODE_FOR_spe_evmwumi, "__builtin_spe_evmwumi", SPE_BUILTIN_EVMWUMI },
-  { 0, CODE_FOR_spe_evmwumia, "__builtin_spe_evmwumia", SPE_BUILTIN_EVMWUMIA },
-  { 0, CODE_FOR_spe_evmwumiaa, "__builtin_spe_evmwumiaa", SPE_BUILTIN_EVMWUMIAA },
-  { 0, CODE_FOR_spe_evmwumian, "__builtin_spe_evmwumian", SPE_BUILTIN_EVMWUMIAN },
-  { 0, CODE_FOR_spe_evnand, "__builtin_spe_evnand", SPE_BUILTIN_EVNAND },
-  { 0, CODE_FOR_spe_evnor, "__builtin_spe_evnor", SPE_BUILTIN_EVNOR },
-  { 0, CODE_FOR_spe_evor, "__builtin_spe_evor", SPE_BUILTIN_EVOR },
-  { 0, CODE_FOR_spe_evorc, "__builtin_spe_evorc", SPE_BUILTIN_EVORC },
-  { 0, CODE_FOR_spe_evrlw, "__builtin_spe_evrlw", SPE_BUILTIN_EVRLW },
-  { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW },
-  { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS },
-  { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU },
-  { 0, CODE_FOR_subv2si3, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW },
-
-  /* SPE binary operations expecting a 5-bit unsigned literal.  */
-  { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW },
-
-  { 0, CODE_FOR_spe_evrlwi, "__builtin_spe_evrlwi", SPE_BUILTIN_EVRLWI },
-  { 0, CODE_FOR_spe_evslwi, "__builtin_spe_evslwi", SPE_BUILTIN_EVSLWI },
-  { 0, CODE_FOR_spe_evsrwis, "__builtin_spe_evsrwis", SPE_BUILTIN_EVSRWIS },
-  { 0, CODE_FOR_spe_evsrwiu, "__builtin_spe_evsrwiu", SPE_BUILTIN_EVSRWIU },
-  { 0, CODE_FOR_spe_evsubifw, "__builtin_spe_evsubifw", SPE_BUILTIN_EVSUBIFW },
-  { 0, CODE_FOR_spe_evmwhssfaa, "__builtin_spe_evmwhssfaa", SPE_BUILTIN_EVMWHSSFAA },
-  { 0, CODE_FOR_spe_evmwhssmaa, "__builtin_spe_evmwhssmaa", SPE_BUILTIN_EVMWHSSMAA },
-  { 0, CODE_FOR_spe_evmwhsmfaa, "__builtin_spe_evmwhsmfaa", SPE_BUILTIN_EVMWHSMFAA },
-  { 0, CODE_FOR_spe_evmwhsmiaa, "__builtin_spe_evmwhsmiaa", SPE_BUILTIN_EVMWHSMIAA },
-  { 0, CODE_FOR_spe_evmwhusiaa, "__builtin_spe_evmwhusiaa", SPE_BUILTIN_EVMWHUSIAA },
-  { 0, CODE_FOR_spe_evmwhumiaa, "__builtin_spe_evmwhumiaa", SPE_BUILTIN_EVMWHUMIAA },
-  { 0, CODE_FOR_spe_evmwhssfan, "__builtin_spe_evmwhssfan", SPE_BUILTIN_EVMWHSSFAN },
-  { 0, CODE_FOR_spe_evmwhssian, "__builtin_spe_evmwhssian", SPE_BUILTIN_EVMWHSSIAN },
-  { 0, CODE_FOR_spe_evmwhsmfan, "__builtin_spe_evmwhsmfan", SPE_BUILTIN_EVMWHSMFAN },
-  { 0, CODE_FOR_spe_evmwhsmian, "__builtin_spe_evmwhsmian", SPE_BUILTIN_EVMWHSMIAN },
-  { 0, CODE_FOR_spe_evmwhusian, "__builtin_spe_evmwhusian", SPE_BUILTIN_EVMWHUSIAN },
-  { 0, CODE_FOR_spe_evmwhumian, "__builtin_spe_evmwhumian", SPE_BUILTIN_EVMWHUMIAN },
-  { 0, CODE_FOR_spe_evmwhgssfaa, "__builtin_spe_evmwhgssfaa", SPE_BUILTIN_EVMWHGSSFAA },
-  { 0, CODE_FOR_spe_evmwhgsmfaa, "__builtin_spe_evmwhgsmfaa", SPE_BUILTIN_EVMWHGSMFAA },
-  { 0, CODE_FOR_spe_evmwhgsmiaa, "__builtin_spe_evmwhgsmiaa", SPE_BUILTIN_EVMWHGSMIAA },
-  { 0, CODE_FOR_spe_evmwhgumiaa, "__builtin_spe_evmwhgumiaa", SPE_BUILTIN_EVMWHGUMIAA },
-  { 0, CODE_FOR_spe_evmwhgssfan, "__builtin_spe_evmwhgssfan", SPE_BUILTIN_EVMWHGSSFAN },
-  { 0, CODE_FOR_spe_evmwhgsmfan, "__builtin_spe_evmwhgsmfan", SPE_BUILTIN_EVMWHGSMFAN },
-  { 0, CODE_FOR_spe_evmwhgsmian, "__builtin_spe_evmwhgsmian", SPE_BUILTIN_EVMWHGSMIAN },
-  { 0, CODE_FOR_spe_evmwhgumian, "__builtin_spe_evmwhgumian", SPE_BUILTIN_EVMWHGUMIAN },
-  { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
-
-  /* Place-holder.  Leave as last binary SPE builtin.  */
-  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR }
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
+static const struct builtin_description bdesc_2arg[] =
+{
+#include "rs6000-builtin.def"
 };
 
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
 /* AltiVec predicates.  */
 
-struct builtin_description_predicates
+static const struct builtin_description bdesc_altivec_preds[] =
 {
-  const unsigned int mask;
-  const enum insn_code icode;
-  const char *const name;
-  const enum rs6000_builtins code;
-};
-
-static const struct builtin_description_predicates bdesc_altivec_preds[] =
-{
-  { MASK_ALTIVEC, CODE_FOR_altivec_vcmpbfp_p, "__builtin_altivec_vcmpbfp_p",
-    ALTIVEC_BUILTIN_VCMPBFP_P },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_vector_eq_v4sf_p,
-    "__builtin_altivec_vcmpeqfp_p", ALTIVEC_BUILTIN_VCMPEQFP_P },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_vector_ge_v4sf_p,
-    "__builtin_altivec_vcmpgefp_p", ALTIVEC_BUILTIN_VCMPGEFP_P },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_vector_gt_v4sf_p,
-    "__builtin_altivec_vcmpgtfp_p", ALTIVEC_BUILTIN_VCMPGTFP_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_eq_v4si_p, "__builtin_altivec_vcmpequw_p",
-    ALTIVEC_BUILTIN_VCMPEQUW_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gt_v4si_p, "__builtin_altivec_vcmpgtsw_p",
-    ALTIVEC_BUILTIN_VCMPGTSW_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtu_v4si_p, "__builtin_altivec_vcmpgtuw_p",
-    ALTIVEC_BUILTIN_VCMPGTUW_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_eq_v8hi_p, "__builtin_altivec_vcmpequh_p",
-    ALTIVEC_BUILTIN_VCMPEQUH_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gt_v8hi_p, "__builtin_altivec_vcmpgtsh_p",
-    ALTIVEC_BUILTIN_VCMPGTSH_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtu_v8hi_p, "__builtin_altivec_vcmpgtuh_p",
-    ALTIVEC_BUILTIN_VCMPGTUH_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_eq_v16qi_p, "__builtin_altivec_vcmpequb_p",
-    ALTIVEC_BUILTIN_VCMPEQUB_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gt_v16qi_p, "__builtin_altivec_vcmpgtsb_p",
-    ALTIVEC_BUILTIN_VCMPGTSB_P },
-  { MASK_ALTIVEC, CODE_FOR_vector_gtu_v16qi_p, "__builtin_altivec_vcmpgtub_p",
-    ALTIVEC_BUILTIN_VCMPGTUB_P },
-
-  { MASK_VSX, CODE_FOR_vector_eq_v4sf_p, "__builtin_vsx_xvcmpeqsp_p",
-    VSX_BUILTIN_XVCMPEQSP_P },
-  { MASK_VSX, CODE_FOR_vector_ge_v4sf_p, "__builtin_vsx_xvcmpgesp_p",
-    VSX_BUILTIN_XVCMPGESP_P },
-  { MASK_VSX, CODE_FOR_vector_gt_v4sf_p, "__builtin_vsx_xvcmpgtsp_p",
-    VSX_BUILTIN_XVCMPGTSP_P },
-  { MASK_VSX, CODE_FOR_vector_eq_v2df_p, "__builtin_vsx_xvcmpeqdp_p",
-    VSX_BUILTIN_XVCMPEQDP_P },
-  { MASK_VSX, CODE_FOR_vector_ge_v2df_p, "__builtin_vsx_xvcmpgedp_p",
-    VSX_BUILTIN_XVCMPGEDP_P },
-  { MASK_VSX, CODE_FOR_vector_gt_v2df_p, "__builtin_vsx_xvcmpgtdp_p",
-    VSX_BUILTIN_XVCMPGTDP_P },
-
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_vcmpeq_p",
-    ALTIVEC_BUILTIN_VCMPEQ_P },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_vcmpgt_p",
-    ALTIVEC_BUILTIN_VCMPGT_P },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_vcmpge_p",
-    ALTIVEC_BUILTIN_VCMPGE_P }
+#include "rs6000-builtin.def"
 };
 
 /* SPE predicates.  */
-static struct builtin_description bdesc_spe_predicates[] =
-{
-  /* Place-holder.  Leave as first.  */
-  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evcmpeq", SPE_BUILTIN_EVCMPEQ },
-  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evcmpgts", SPE_BUILTIN_EVCMPGTS },
-  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evcmpgtu", SPE_BUILTIN_EVCMPGTU },
-  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evcmplts", SPE_BUILTIN_EVCMPLTS },
-  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evcmpltu", SPE_BUILTIN_EVCMPLTU },
-  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evfscmpeq", SPE_BUILTIN_EVFSCMPEQ },
-  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evfscmpgt", SPE_BUILTIN_EVFSCMPGT },
-  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evfscmplt", SPE_BUILTIN_EVFSCMPLT },
-  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evfststeq", SPE_BUILTIN_EVFSTSTEQ },
-  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evfststgt", SPE_BUILTIN_EVFSTSTGT },
-  /* Place-holder.  Leave as last.  */
-  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evfststlt", SPE_BUILTIN_EVFSTSTLT },
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
+static const struct builtin_description bdesc_spe_predicates[] =
+{
+#include "rs6000-builtin.def"
 };
 
 /* SPE evsel predicates.  */
-static struct builtin_description bdesc_spe_evsel[] =
-{
-  /* Place-holder.  Leave as first.  */
-  { 0, CODE_FOR_spe_evcmpgts, "__builtin_spe_evsel_gts", SPE_BUILTIN_EVSEL_CMPGTS },
-  { 0, CODE_FOR_spe_evcmpgtu, "__builtin_spe_evsel_gtu", SPE_BUILTIN_EVSEL_CMPGTU },
-  { 0, CODE_FOR_spe_evcmplts, "__builtin_spe_evsel_lts", SPE_BUILTIN_EVSEL_CMPLTS },
-  { 0, CODE_FOR_spe_evcmpltu, "__builtin_spe_evsel_ltu", SPE_BUILTIN_EVSEL_CMPLTU },
-  { 0, CODE_FOR_spe_evcmpeq, "__builtin_spe_evsel_eq", SPE_BUILTIN_EVSEL_CMPEQ },
-  { 0, CODE_FOR_spe_evfscmpgt, "__builtin_spe_evsel_fsgt", SPE_BUILTIN_EVSEL_FSCMPGT },
-  { 0, CODE_FOR_spe_evfscmplt, "__builtin_spe_evsel_fslt", SPE_BUILTIN_EVSEL_FSCMPLT },
-  { 0, CODE_FOR_spe_evfscmpeq, "__builtin_spe_evsel_fseq", SPE_BUILTIN_EVSEL_FSCMPEQ },
-  { 0, CODE_FOR_spe_evfststgt, "__builtin_spe_evsel_fststgt", SPE_BUILTIN_EVSEL_FSTSTGT },
-  { 0, CODE_FOR_spe_evfststlt, "__builtin_spe_evsel_fststlt", SPE_BUILTIN_EVSEL_FSTSTLT },
-  /* Place-holder.  Leave as last.  */
-  { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
+static const struct builtin_description bdesc_spe_evsel[] =
+{
+#include "rs6000-builtin.def"
 };
 
 /* PAIRED predicates.  */
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
 static const struct builtin_description bdesc_paired_preds[] =
 {
-  /* Place-holder.  Leave as first.  */
-  { 0, CODE_FOR_paired_cmpu0, "__builtin_paired_cmpu0", PAIRED_BUILTIN_CMPU0 },
-  /* Place-holder.  Leave as last.  */
-  { 0, CODE_FOR_paired_cmpu1, "__builtin_paired_cmpu1", PAIRED_BUILTIN_CMPU1 },
+#include "rs6000-builtin.def"
 };
 
 /* ABS* operations.  */
 
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
 static const struct builtin_description bdesc_abs[] =
 {
-  { MASK_ALTIVEC, CODE_FOR_absv4si2, "__builtin_altivec_abs_v4si", ALTIVEC_BUILTIN_ABS_V4SI },
-  { MASK_ALTIVEC, CODE_FOR_absv8hi2, "__builtin_altivec_abs_v8hi", ALTIVEC_BUILTIN_ABS_V8HI },
-  { MASK_ALTIVEC, CODE_FOR_absv4sf2, "__builtin_altivec_abs_v4sf", ALTIVEC_BUILTIN_ABS_V4SF },
-  { MASK_ALTIVEC, CODE_FOR_absv16qi2, "__builtin_altivec_abs_v16qi", ALTIVEC_BUILTIN_ABS_V16QI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v4si, "__builtin_altivec_abss_v4si", ALTIVEC_BUILTIN_ABSS_V4SI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v8hi, "__builtin_altivec_abss_v8hi", ALTIVEC_BUILTIN_ABSS_V8HI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_abss_v16qi, "__builtin_altivec_abss_v16qi", ALTIVEC_BUILTIN_ABSS_V16QI },
-  { MASK_VSX, CODE_FOR_absv2df2, "__builtin_vsx_xvabsdp", VSX_BUILTIN_XVABSDP },
-  { MASK_VSX, CODE_FOR_vsx_nabsv2df2, "__builtin_vsx_xvnabsdp", VSX_BUILTIN_XVNABSDP },
-  { MASK_VSX, CODE_FOR_absv4sf2, "__builtin_vsx_xvabssp", VSX_BUILTIN_XVABSSP },
-  { MASK_VSX, CODE_FOR_vsx_nabsv4sf2, "__builtin_vsx_xvnabssp", VSX_BUILTIN_XVNABSSP },
+#include "rs6000-builtin.def"
 };
 
 /* Simple unary operations: VECb = foo (unsigned literal) or VECb =
    foo (VECa).  */
 
-static struct builtin_description bdesc_1arg[] =
-{
-  { MASK_ALTIVEC, CODE_FOR_altivec_vexptefp, "__builtin_altivec_vexptefp", ALTIVEC_BUILTIN_VEXPTEFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vlogefp, "__builtin_altivec_vlogefp", ALTIVEC_BUILTIN_VLOGEFP },
-  { MASK_ALTIVEC, CODE_FOR_rev4sf2, "__builtin_altivec_vrefp", ALTIVEC_BUILTIN_VREFP },
-  { MASK_ALTIVEC, CODE_FOR_vector_floorv4sf2, "__builtin_altivec_vrfim", ALTIVEC_BUILTIN_VRFIM },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vrfin, "__builtin_altivec_vrfin", ALTIVEC_BUILTIN_VRFIN },
-  { MASK_ALTIVEC, CODE_FOR_vector_ceilv4sf2, "__builtin_altivec_vrfip", ALTIVEC_BUILTIN_VRFIP },
-  { MASK_ALTIVEC, CODE_FOR_vector_btruncv4sf2, "__builtin_altivec_vrfiz", ALTIVEC_BUILTIN_VRFIZ },
-  { MASK_ALTIVEC, CODE_FOR_rsqrtv4sf2, "__builtin_altivec_vrsqrtfp", ALTIVEC_BUILTIN_VRSQRTFP },
-  { MASK_ALTIVEC, CODE_FOR_rsqrtev4sf2, "__builtin_altivec_vrsqrtefp", ALTIVEC_BUILTIN_VRSQRTEFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisb, "__builtin_altivec_vspltisb", ALTIVEC_BUILTIN_VSPLTISB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vspltish, "__builtin_altivec_vspltish", ALTIVEC_BUILTIN_VSPLTISH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vspltisw, "__builtin_altivec_vspltisw", ALTIVEC_BUILTIN_VSPLTISW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsb, "__builtin_altivec_vupkhsb", ALTIVEC_BUILTIN_VUPKHSB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhpx, "__builtin_altivec_vupkhpx", ALTIVEC_BUILTIN_VUPKHPX },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupkhsh, "__builtin_altivec_vupkhsh", ALTIVEC_BUILTIN_VUPKHSH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsb, "__builtin_altivec_vupklsb", ALTIVEC_BUILTIN_VUPKLSB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupklpx, "__builtin_altivec_vupklpx", ALTIVEC_BUILTIN_VUPKLPX },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vupklsh, "__builtin_altivec_vupklsh", ALTIVEC_BUILTIN_VUPKLSH },
-
-  { MASK_VSX, CODE_FOR_negv2df2, "__builtin_vsx_xvnegdp", VSX_BUILTIN_XVNEGDP },
-  { MASK_VSX, CODE_FOR_sqrtv2df2, "__builtin_vsx_xvsqrtdp", VSX_BUILTIN_XVSQRTDP },
-  { MASK_VSX, CODE_FOR_rsqrtv2df2, "__builtin_vsx_xvrsqrtdp", VSX_BUILTIN_VEC_RSQRT_V2DF },
-  { MASK_VSX, CODE_FOR_rsqrtev2df2, "__builtin_vsx_xvrsqrtedp", VSX_BUILTIN_XVRSQRTEDP },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtv2df2_fe, "__builtin_vsx_xvtsqrtdp_fe", VSX_BUILTIN_XVTSQRTDP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtv2df2_fg, "__builtin_vsx_xvtsqrtdp_fg", VSX_BUILTIN_XVTSQRTDP_FG },
-  { MASK_VSX, CODE_FOR_vsx_frev2df2, "__builtin_vsx_xvredp", VSX_BUILTIN_XVREDP },
-
-  { MASK_VSX, CODE_FOR_negv4sf2, "__builtin_vsx_xvnegsp", VSX_BUILTIN_XVNEGSP },
-  { MASK_VSX, CODE_FOR_sqrtv4sf2, "__builtin_vsx_xvsqrtsp", VSX_BUILTIN_XVSQRTSP },
-  { MASK_VSX, CODE_FOR_rsqrtv4sf2, "__builtin_vsx_xvrsqrtsp", VSX_BUILTIN_VEC_RSQRT_V4SF },
-  { MASK_VSX, CODE_FOR_rsqrtev4sf2, "__builtin_vsx_xvrsqrtesp", VSX_BUILTIN_XVRSQRTESP },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtv4sf2_fe, "__builtin_vsx_xvtsqrtsp_fe", VSX_BUILTIN_XVTSQRTSP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtv4sf2_fg, "__builtin_vsx_xvtsqrtsp_fg", VSX_BUILTIN_XVTSQRTSP_FG },
-  { MASK_VSX, CODE_FOR_vsx_frev4sf2, "__builtin_vsx_xvresp", VSX_BUILTIN_XVRESP },
-
-  { MASK_VSX, CODE_FOR_vsx_xscvdpsp, "__builtin_vsx_xscvdpsp", VSX_BUILTIN_XSCVDPSP },
-  { MASK_VSX, CODE_FOR_vsx_xscvdpsp, "__builtin_vsx_xscvspdp", VSX_BUILTIN_XSCVSPDP },
-  { MASK_VSX, CODE_FOR_vsx_xvcvdpsp, "__builtin_vsx_xvcvdpsp", VSX_BUILTIN_XVCVDPSP },
-  { MASK_VSX, CODE_FOR_vsx_xvcvspdp, "__builtin_vsx_xvcvspdp", VSX_BUILTIN_XVCVSPDP },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtdf2_fe, "__builtin_vsx_xstsqrtdp_fe", VSX_BUILTIN_XSTSQRTDP_FE },
-  { MASK_VSX, CODE_FOR_vsx_tsqrtdf2_fg, "__builtin_vsx_xstsqrtdp_fg", VSX_BUILTIN_XSTSQRTDP_FG },
-
-  { MASK_VSX, CODE_FOR_vsx_fix_truncv2dfv2di2, "__builtin_vsx_xvcvdpsxds", VSX_BUILTIN_XVCVDPSXDS },
-  { MASK_VSX, CODE_FOR_vsx_fixuns_truncv2dfv2di2, "__builtin_vsx_xvcvdpuxds", VSX_BUILTIN_XVCVDPUXDS },
-  { MASK_VSX, CODE_FOR_vsx_fixuns_truncv2dfv2di2, "__builtin_vsx_xvcvdpuxds_uns", VSX_BUILTIN_XVCVDPUXDS_UNS },
-  { MASK_VSX, CODE_FOR_vsx_floatv2div2df2, "__builtin_vsx_xvcvsxddp", VSX_BUILTIN_XVCVSXDDP },
-  { MASK_VSX, CODE_FOR_vsx_floatunsv2div2df2, "__builtin_vsx_xvcvuxddp", VSX_BUILTIN_XVCVUXDDP },
-  { MASK_VSX, CODE_FOR_vsx_floatunsv2div2df2, "__builtin_vsx_xvcvuxddp_uns", VSX_BUILTIN_XVCVUXDDP_UNS },
-
-  { MASK_VSX, CODE_FOR_vsx_fix_truncv4sfv4si2, "__builtin_vsx_xvcvspsxws", VSX_BUILTIN_XVCVSPSXWS },
-  { MASK_VSX, CODE_FOR_vsx_fixuns_truncv4sfv4si2, "__builtin_vsx_xvcvspuxws", VSX_BUILTIN_XVCVSPUXWS },
-  { MASK_VSX, CODE_FOR_vsx_floatv4siv4sf2, "__builtin_vsx_xvcvsxwsp", VSX_BUILTIN_XVCVSXWSP },
-  { MASK_VSX, CODE_FOR_vsx_floatunsv4siv4sf2, "__builtin_vsx_xvcvuxwsp", VSX_BUILTIN_XVCVUXWSP },
-
-  { MASK_VSX, CODE_FOR_vsx_xvcvdpsxws, "__builtin_vsx_xvcvdpsxws", VSX_BUILTIN_XVCVDPSXWS },
-  { MASK_VSX, CODE_FOR_vsx_xvcvdpuxws, "__builtin_vsx_xvcvdpuxws", VSX_BUILTIN_XVCVDPUXWS },
-  { MASK_VSX, CODE_FOR_vsx_xvcvsxwdp, "__builtin_vsx_xvcvsxwdp", VSX_BUILTIN_XVCVSXWDP },
-  { MASK_VSX, CODE_FOR_vsx_xvcvuxwdp, "__builtin_vsx_xvcvuxwdp", VSX_BUILTIN_XVCVUXWDP },
-  { MASK_VSX, CODE_FOR_vsx_xvrdpi, "__builtin_vsx_xvrdpi", VSX_BUILTIN_XVRDPI },
-  { MASK_VSX, CODE_FOR_vsx_xvrdpic, "__builtin_vsx_xvrdpic", VSX_BUILTIN_XVRDPIC },
-  { MASK_VSX, CODE_FOR_vsx_floorv2df2, "__builtin_vsx_xvrdpim", VSX_BUILTIN_XVRDPIM },
-  { MASK_VSX, CODE_FOR_vsx_ceilv2df2, "__builtin_vsx_xvrdpip", VSX_BUILTIN_XVRDPIP },
-  { MASK_VSX, CODE_FOR_vsx_btruncv2df2, "__builtin_vsx_xvrdpiz", VSX_BUILTIN_XVRDPIZ },
-
-  { MASK_VSX, CODE_FOR_vsx_xvcvspsxds, "__builtin_vsx_xvcvspsxds", VSX_BUILTIN_XVCVSPSXDS },
-  { MASK_VSX, CODE_FOR_vsx_xvcvspuxds, "__builtin_vsx_xvcvspuxds", VSX_BUILTIN_XVCVSPUXDS },
-  { MASK_VSX, CODE_FOR_vsx_xvcvsxdsp, "__builtin_vsx_xvcvsxdsp", VSX_BUILTIN_XVCVSXDSP },
-  { MASK_VSX, CODE_FOR_vsx_xvcvuxdsp, "__builtin_vsx_xvcvuxdsp", VSX_BUILTIN_XVCVUXDSP },
-  { MASK_VSX, CODE_FOR_vsx_xvrspi, "__builtin_vsx_xvrspi", VSX_BUILTIN_XVRSPI },
-  { MASK_VSX, CODE_FOR_vsx_xvrspic, "__builtin_vsx_xvrspic", VSX_BUILTIN_XVRSPIC },
-  { MASK_VSX, CODE_FOR_vsx_floorv4sf2, "__builtin_vsx_xvrspim", VSX_BUILTIN_XVRSPIM },
-  { MASK_VSX, CODE_FOR_vsx_ceilv4sf2, "__builtin_vsx_xvrspip", VSX_BUILTIN_XVRSPIP },
-  { MASK_VSX, CODE_FOR_vsx_btruncv4sf2, "__builtin_vsx_xvrspiz", VSX_BUILTIN_XVRSPIZ },
-
-  { MASK_VSX, CODE_FOR_vsx_xsrdpi, "__builtin_vsx_xsrdpi", VSX_BUILTIN_XSRDPI },
-  { MASK_VSX, CODE_FOR_vsx_xsrdpic, "__builtin_vsx_xsrdpic", VSX_BUILTIN_XSRDPIC },
-  { MASK_VSX, CODE_FOR_vsx_floordf2, "__builtin_vsx_xsrdpim", VSX_BUILTIN_XSRDPIM },
-  { MASK_VSX, CODE_FOR_vsx_ceildf2, "__builtin_vsx_xsrdpip", VSX_BUILTIN_XSRDPIP },
-  { MASK_VSX, CODE_FOR_vsx_btruncdf2, "__builtin_vsx_xsrdpiz", VSX_BUILTIN_XSRDPIZ },
-
-  { 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_rsqrt", ALTIVEC_BUILTIN_VEC_RSQRT },
-  { 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 },
-
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_nearbyint", ALTIVEC_BUILTIN_VEC_NEARBYINT },
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_rint", ALTIVEC_BUILTIN_VEC_RINT },
-  { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_sqrt", ALTIVEC_BUILTIN_VEC_SQRT },
-
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_floatv4siv4sf2, "__builtin_vec_float_sisf", VECTOR_BUILTIN_FLOAT_V4SI_V4SF },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_unsigned_floatv4siv4sf2, "__builtin_vec_uns_float_sisf", VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_fix_truncv4sfv4si2, "__builtin_vec_fix_sfsi", VECTOR_BUILTIN_FIX_V4SF_V4SI },
-  { MASK_ALTIVEC|MASK_VSX, CODE_FOR_fixuns_truncv4sfv4si2, "__builtin_vec_fixuns_sfsi", VECTOR_BUILTIN_FIXUNS_V4SF_V4SI },
-
-  /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and
-     end with SPE_BUILTIN_EVSUBFUSIAAW.  */
-  { 0, CODE_FOR_absv2si2, "__builtin_spe_evabs", SPE_BUILTIN_EVABS },
-  { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW },
-  { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW },
-  { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW },
-  { 0, CODE_FOR_spe_evaddusiaaw, "__builtin_spe_evaddusiaaw", SPE_BUILTIN_EVADDUSIAAW },
-  { 0, CODE_FOR_spe_evcntlsw, "__builtin_spe_evcntlsw", SPE_BUILTIN_EVCNTLSW },
-  { 0, CODE_FOR_spe_evcntlzw, "__builtin_spe_evcntlzw", SPE_BUILTIN_EVCNTLZW },
-  { 0, CODE_FOR_spe_evextsb, "__builtin_spe_evextsb", SPE_BUILTIN_EVEXTSB },
-  { 0, CODE_FOR_spe_evextsh, "__builtin_spe_evextsh", SPE_BUILTIN_EVEXTSH },
-  { 0, CODE_FOR_spe_evfsabs, "__builtin_spe_evfsabs", SPE_BUILTIN_EVFSABS },
-  { 0, CODE_FOR_spe_evfscfsf, "__builtin_spe_evfscfsf", SPE_BUILTIN_EVFSCFSF },
-  { 0, CODE_FOR_spe_evfscfsi, "__builtin_spe_evfscfsi", SPE_BUILTIN_EVFSCFSI },
-  { 0, CODE_FOR_spe_evfscfuf, "__builtin_spe_evfscfuf", SPE_BUILTIN_EVFSCFUF },
-  { 0, CODE_FOR_spe_evfscfui, "__builtin_spe_evfscfui", SPE_BUILTIN_EVFSCFUI },
-  { 0, CODE_FOR_spe_evfsctsf, "__builtin_spe_evfsctsf", SPE_BUILTIN_EVFSCTSF },
-  { 0, CODE_FOR_spe_evfsctsi, "__builtin_spe_evfsctsi", SPE_BUILTIN_EVFSCTSI },
-  { 0, CODE_FOR_spe_evfsctsiz, "__builtin_spe_evfsctsiz", SPE_BUILTIN_EVFSCTSIZ },
-  { 0, CODE_FOR_spe_evfsctuf, "__builtin_spe_evfsctuf", SPE_BUILTIN_EVFSCTUF },
-  { 0, CODE_FOR_spe_evfsctui, "__builtin_spe_evfsctui", SPE_BUILTIN_EVFSCTUI },
-  { 0, CODE_FOR_spe_evfsctuiz, "__builtin_spe_evfsctuiz", SPE_BUILTIN_EVFSCTUIZ },
-  { 0, CODE_FOR_spe_evfsnabs, "__builtin_spe_evfsnabs", SPE_BUILTIN_EVFSNABS },
-  { 0, CODE_FOR_spe_evfsneg, "__builtin_spe_evfsneg", SPE_BUILTIN_EVFSNEG },
-  { 0, CODE_FOR_spe_evmra, "__builtin_spe_evmra", SPE_BUILTIN_EVMRA },
-  { 0, CODE_FOR_negv2si2, "__builtin_spe_evneg", SPE_BUILTIN_EVNEG },
-  { 0, CODE_FOR_spe_evrndw, "__builtin_spe_evrndw", SPE_BUILTIN_EVRNDW },
-  { 0, CODE_FOR_spe_evsubfsmiaaw, "__builtin_spe_evsubfsmiaaw", SPE_BUILTIN_EVSUBFSMIAAW },
-  { 0, CODE_FOR_spe_evsubfssiaaw, "__builtin_spe_evsubfssiaaw", SPE_BUILTIN_EVSUBFSSIAAW },
-  { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
-
-  /* Place-holder.  Leave as last unary SPE builtin.  */
-  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
-
-  { 0, CODE_FOR_paired_absv2sf2, "__builtin_paired_absv2sf2", PAIRED_BUILTIN_ABSV2SF2 },
-  { 0, CODE_FOR_nabsv2sf2, "__builtin_paired_nabsv2sf2", PAIRED_BUILTIN_NABSV2SF2 },
-  { 0, CODE_FOR_paired_negv2sf2, "__builtin_paired_negv2sf2", PAIRED_BUILTIN_NEGV2SF2 },
-  { 0, CODE_FOR_sqrtv2sf2, "__builtin_paired_sqrtv2sf2", PAIRED_BUILTIN_SQRTV2SF2 },
-  { 0, CODE_FOR_resv2sf2, "__builtin_paired_resv2sf2", PAIRED_BUILTIN_RESV2SF2 }
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+#define RS6000_BUILTIN_1(ENUM, NAME, MASK, ATTR, ICODE) \
+  { MASK, ICODE, NAME, ENUM },
+
+#define RS6000_BUILTIN_2(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_3(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_A(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_D(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_E(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_P(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_Q(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_S(ENUM, NAME, MASK, ATTR, ICODE)
+#define RS6000_BUILTIN_X(ENUM, NAME, MASK, ATTR, ICODE)
+
+static const struct builtin_description bdesc_1arg[] =
+{
+#include "rs6000-builtin.def"
 };
 
+#undef RS6000_BUILTIN_1
+#undef RS6000_BUILTIN_2
+#undef RS6000_BUILTIN_3
+#undef RS6000_BUILTIN_A
+#undef RS6000_BUILTIN_D
+#undef RS6000_BUILTIN_E
+#undef RS6000_BUILTIN_P
+#undef RS6000_BUILTIN_Q
+#undef RS6000_BUILTIN_S
+#undef RS6000_BUILTIN_X
+
+/* Return true if a builtin function is overloaded.  */
+bool
+rs6000_overloaded_builtin_p (enum rs6000_builtins fncode)
+{
+  return (rs6000_builtin_info[(int)fncode].attr & RS6000_BTC_OVERLOADED) != 0;
+}
+
+
 static rtx
 rs6000_expand_unop_builtin (enum insn_code icode, tree exp, rtx target)
 {
@@ -11156,23 +10570,22 @@ static rtx
 altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
 {
   const struct builtin_description *d;
-  const struct builtin_description_predicates *dp;
   size_t i;
   enum insn_code icode;
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   tree arg0;
   rtx op0, pat;
   enum machine_mode tmode, mode0;
-  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  enum rs6000_builtins fcode
+    = (enum rs6000_builtins) DECL_FUNCTION_CODE (fndecl);
 
-  if ((fcode >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
-       && fcode <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
-      || (fcode >= VSX_BUILTIN_OVERLOADED_FIRST
-         && fcode <= VSX_BUILTIN_OVERLOADED_LAST))
+  if (rs6000_overloaded_builtin_p (fcode))
     {
       *expandedp = true;
       error ("unresolved overload for Altivec builtin %qF", fndecl);
-      return const0_rtx;
+
+      /* Given it is invalid, just generate a normal call.  */
+      return expand_call (exp, target, false);
     }
 
   target = altivec_expand_ld_builtin (exp, target, expandedp);
@@ -11321,10 +10734,10 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
       return altivec_expand_abs_builtin (d->icode, exp, target);
 
   /* Expand the AltiVec predicates.  */
-  dp = bdesc_altivec_preds;
-  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
-    if (dp->code == fcode)
-      return altivec_expand_predicate_builtin (dp->icode, exp, target);
+  d = bdesc_altivec_preds;
+  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++)
+    if (d->code == fcode)
+      return altivec_expand_predicate_builtin (d->icode, exp, target);
 
   /* LV* are funky.  We initialized them differently.  */
   switch (fcode)
@@ -11425,30 +10838,30 @@ paired_expand_builtin (tree exp, rtx target, bool * expandedp)
 
 /* Binops that need to be initialized manually, but can be expanded
    automagically by rs6000_expand_binop_builtin.  */
-static struct builtin_description bdesc_2arg_spe[] =
-{
-  { 0, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
-  { 0, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
-  { 0, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
-  { 0, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
-  { 0, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
-  { 0, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
-  { 0, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
-  { 0, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
-  { 0, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
-  { 0, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
-  { 0, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
-  { 0, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
-  { 0, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
-  { 0, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
-  { 0, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
-  { 0, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
-  { 0, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
-  { 0, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
-  { 0, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
-  { 0, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
-  { 0, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
-  { 0, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
+static const struct builtin_description bdesc_2arg_spe[] =
+{
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlddx, "__builtin_spe_evlddx", SPE_BUILTIN_EVLDDX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evldwx, "__builtin_spe_evldwx", SPE_BUILTIN_EVLDWX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evldhx, "__builtin_spe_evldhx", SPE_BUILTIN_EVLDHX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhex, "__builtin_spe_evlwhex", SPE_BUILTIN_EVLWHEX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhoux, "__builtin_spe_evlwhoux", SPE_BUILTIN_EVLWHOUX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhosx, "__builtin_spe_evlwhosx", SPE_BUILTIN_EVLWHOSX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwwsplatx, "__builtin_spe_evlwwsplatx", SPE_BUILTIN_EVLWWSPLATX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhsplatx, "__builtin_spe_evlwhsplatx", SPE_BUILTIN_EVLWHSPLATX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhesplatx, "__builtin_spe_evlhhesplatx", SPE_BUILTIN_EVLHHESPLATX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhousplatx, "__builtin_spe_evlhhousplatx", SPE_BUILTIN_EVLHHOUSPLATX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhossplatx, "__builtin_spe_evlhhossplatx", SPE_BUILTIN_EVLHHOSSPLATX },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evldd, "__builtin_spe_evldd", SPE_BUILTIN_EVLDD },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evldw, "__builtin_spe_evldw", SPE_BUILTIN_EVLDW },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evldh, "__builtin_spe_evldh", SPE_BUILTIN_EVLDH },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhe, "__builtin_spe_evlwhe", SPE_BUILTIN_EVLWHE },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhou, "__builtin_spe_evlwhou", SPE_BUILTIN_EVLWHOU },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhos, "__builtin_spe_evlwhos", SPE_BUILTIN_EVLWHOS },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwwsplat, "__builtin_spe_evlwwsplat", SPE_BUILTIN_EVLWWSPLAT },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlwhsplat, "__builtin_spe_evlwhsplat", SPE_BUILTIN_EVLWHSPLAT },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhesplat, "__builtin_spe_evlhhesplat", SPE_BUILTIN_EVLHHESPLAT },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhousplat, "__builtin_spe_evlhhousplat", SPE_BUILTIN_EVLHHOUSPLAT },
+  { RS6000_BTM_SPE, CODE_FOR_spe_evlhhossplat, "__builtin_spe_evlhhossplat", SPE_BUILTIN_EVLHHOSSPLAT }
 };
 
 /* Expand the builtin in EXP and store the result in TARGET.  Store
@@ -11465,7 +10878,7 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
   enum insn_code icode;
   enum machine_mode tmode, mode0;
   rtx pat, op0;
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
 
   *expandedp = true;
@@ -11505,17 +10918,17 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
       break;
     }
 
-  d = (struct builtin_description *) bdesc_2arg_spe;
+  d = bdesc_2arg_spe;
   for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
     if (d->code == fcode)
       return rs6000_expand_binop_builtin (d->icode, exp, target);
 
-  d = (struct builtin_description *) bdesc_spe_predicates;
+  d = bdesc_spe_predicates;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
     if (d->code == fcode)
       return spe_expand_predicate_builtin (d->icode, exp, target);
 
-  d = (struct builtin_description *) bdesc_spe_evsel;
+  d = bdesc_spe_evsel;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
     if (d->code == fcode)
       return spe_expand_evsel_builtin (d->icode, exp, target);
@@ -11818,6 +11231,32 @@ spe_expand_evsel_builtin (enum insn_code icode, tree exp, rtx target)
   return target;
 }
 
+/* Raise an error message for a builtin function that is called without the
+   appropriate target options being set.  */
+
+static void
+rs6000_invalid_builtin (enum rs6000_builtins fncode)
+{
+  size_t uns_fncode = (size_t)fncode;
+  const char *name = rs6000_builtin_info[uns_fncode].name;
+  unsigned fnmask = rs6000_builtin_info[uns_fncode].mask;
+
+  gcc_assert (name != NULL);
+  if ((fnmask & RS6000_BTM_CELL) != 0)
+    error ("Builtin function %s is only valid for the cell processor", name);
+  else if ((fnmask & RS6000_BTM_VSX) != 0)
+    error ("Builtin function %s requires the -mvsx option", name);
+  else if ((fnmask & RS6000_BTM_ALTIVEC) != 0)
+    error ("Builtin function %s requires the -maltivec option", name);
+  else if ((fnmask & RS6000_BTM_PAIRED) != 0)
+    error ("Builtin function %s requires the -mpaired option", name);
+  else if ((fnmask & RS6000_BTM_SPE) != 0)
+    error ("Builtin function %s requires the -mspe option", name);
+  else
+    error ("Builtin function %s is not supported with the current options",
+          name);
+}
+
 /* Expand an expression EXP that calls a built-in function,
    with result going to TARGET if that's convenient
    (and in mode MODE if that's convenient).
@@ -11830,11 +11269,54 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
                       int ignore ATTRIBUTE_UNUSED)
 {
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  enum rs6000_builtins fcode
+    = (enum rs6000_builtins)DECL_FUNCTION_CODE (fndecl);
+  size_t uns_fcode = (size_t)fcode;
   const struct builtin_description *d;
   size_t i;
   rtx ret;
   bool success;
+  unsigned mask = rs6000_builtin_info[uns_fcode].mask;
+  bool func_valid_p = ((rs6000_builtin_mask & mask) == mask);
+
+  if (TARGET_DEBUG_BUILTIN)
+    {
+      enum insn_code icode = rs6000_builtin_info[uns_fcode].icode;
+      const char *name1 = rs6000_builtin_info[uns_fcode].name;
+      const char *name2 = ((icode != CODE_FOR_nothing)
+                          ? get_insn_name ((int)icode)
+                          : "nothing");
+      const char *name3;
+
+      switch (rs6000_builtin_info[uns_fcode].attr & RS6000_BTC_TYPE_MASK)
+       {
+       default:                   name3 = "unknown";   break;
+       case RS6000_BTC_SPECIAL:   name3 = "special";   break;
+       case RS6000_BTC_UNARY:     name3 = "unary";     break;
+       case RS6000_BTC_BINARY:    name3 = "binary";    break;
+       case RS6000_BTC_TERNARY:   name3 = "ternary";   break;
+       case RS6000_BTC_PREDICATE: name3 = "predicate"; break;
+       case RS6000_BTC_ABS:       name3 = "abs";       break;
+       case RS6000_BTC_EVSEL:     name3 = "evsel";     break;
+       case RS6000_BTC_DST:       name3 = "dst";       break;
+       }
+
+
+      fprintf (stderr,
+              "rs6000_expand_builtin, %s (%d), insn = %s (%d), type=%s%s\n",
+              (name1) ? name1 : "---", fcode,
+              (name2) ? name2 : "---", (int)icode,
+              name3,
+              func_valid_p ? "" : ", not valid");
+    }       
+
+  if (!func_valid_p)
+    {
+      rs6000_invalid_builtin (fcode);
+
+      /* Given it is invalid, just generate a normal call.  */
+      return expand_call (exp, target, ignore);
+    }
 
   switch (fcode)
     {
@@ -11850,9 +11332,6 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     case RS6000_BUILTIN_RSQRT:
       return rs6000_expand_unop_builtin (CODE_FOR_rsqrtdf2, exp, target);
 
-    case RS6000_BUILTIN_BSWAP_HI:
-      return rs6000_expand_unop_builtin (CODE_FOR_bswaphi2, exp, target);
-
     case POWER7_BUILTIN_BPERMD:
       return rs6000_expand_binop_builtin (((TARGET_64BIT)
                                           ? CODE_FOR_bpermd_di
@@ -11940,13 +11419,13 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   gcc_assert (TARGET_ALTIVEC || TARGET_VSX || TARGET_SPE || TARGET_PAIRED_FLOAT);
 
   /* Handle simple unary operations.  */
-  d = (struct builtin_description *) bdesc_1arg;
+  d = bdesc_1arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
     if (d->code == fcode)
       return rs6000_expand_unop_builtin (d->icode, exp, target);
 
   /* Handle simple binary operations.  */
-  d = (struct builtin_description *) bdesc_2arg;
+  d = bdesc_2arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
     if (d->code == fcode)
       return rs6000_expand_binop_builtin (d->icode, exp, target);
@@ -11965,6 +11444,14 @@ rs6000_init_builtins (void)
 {
   tree tdecl;
   tree ftype;
+  enum machine_mode mode;
+
+  if (TARGET_DEBUG_BUILTIN)
+    fprintf (stderr, "rs6000_init_builtins%s%s%s%s\n",
+            (TARGET_PAIRED_FLOAT) ? ", paired"  : "",
+            (TARGET_SPE)          ? ", spe"     : "",
+            (TARGET_ALTIVEC)      ? ", altivec" : "",
+            (TARGET_VSX)          ? ", vsx"     : "");
 
   V2SI_type_node = build_vector_type (intSI_type_node, 2);
   V2SF_type_node = build_vector_type (float_type_node, 2);
@@ -12036,25 +11523,17 @@ rs6000_init_builtins (void)
   builtin_mode_to_type[V16QImode][0] = V16QI_type_node;
   builtin_mode_to_type[V16QImode][1] = unsigned_V16QI_type_node;
 
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__bool char"),
-                     bool_char_type_node);
+  tdecl = add_builtin_type ("__bool char", bool_char_type_node);
   TYPE_NAME (bool_char_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__bool short"),
-                     bool_short_type_node);
+
+  tdecl = add_builtin_type ("__bool short", bool_short_type_node);
   TYPE_NAME (bool_short_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__bool int"),
-                     bool_int_type_node);
+
+  tdecl = add_builtin_type ("__bool int", bool_int_type_node);
   TYPE_NAME (bool_int_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("__pixel"),
-                     pixel_type_node);
+
+  tdecl = add_builtin_type ("__pixel", pixel_type_node);
   TYPE_NAME (pixel_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
 
   bool_V16QI_type_node = build_vector_type (bool_char_type_node, 16);
   bool_V8HI_type_node = build_vector_type (bool_short_type_node, 8);
@@ -12062,155 +11541,90 @@ rs6000_init_builtins (void)
   bool_V2DI_type_node = build_vector_type (bool_long_type_node, 2);
   pixel_V8HI_type_node = build_vector_type (pixel_type_node, 8);
 
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__vector unsigned char"),
-                     unsigned_V16QI_type_node);
+  tdecl = add_builtin_type ("__vector unsigned char", unsigned_V16QI_type_node);
   TYPE_NAME (unsigned_V16QI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector signed char"),
-                     V16QI_type_node);
+
+  tdecl = add_builtin_type ("__vector signed char", V16QI_type_node);
   TYPE_NAME (V16QI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector __bool char"),
-                     bool_V16QI_type_node);
+
+  tdecl = add_builtin_type ("__vector __bool char", bool_V16QI_type_node);
   TYPE_NAME ( bool_V16QI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
 
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector unsigned short"),
-                     unsigned_V8HI_type_node);
+  tdecl = add_builtin_type ("__vector unsigned short", unsigned_V8HI_type_node);
   TYPE_NAME (unsigned_V8HI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector signed short"),
-                     V8HI_type_node);
+
+  tdecl = add_builtin_type ("__vector signed short", V8HI_type_node);
   TYPE_NAME (V8HI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__vector __bool short"),
-                     bool_V8HI_type_node);
+
+  tdecl = add_builtin_type ("__vector __bool short", bool_V8HI_type_node);
   TYPE_NAME (bool_V8HI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
 
-  tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                     get_identifier ("__vector unsigned int"),
-                     unsigned_V4SI_type_node);
+  tdecl = add_builtin_type ("__vector unsigned int", unsigned_V4SI_type_node);
   TYPE_NAME (unsigned_V4SI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector signed int"),
-                     V4SI_type_node);
+
+  tdecl = add_builtin_type ("__vector signed int", V4SI_type_node);
   TYPE_NAME (V4SI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector __bool int"),
-                     bool_V4SI_type_node);
+
+  tdecl = add_builtin_type ("__vector __bool int", bool_V4SI_type_node);
   TYPE_NAME (bool_V4SI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
 
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector float"),
-                     V4SF_type_node);
+  tdecl = add_builtin_type ("__vector float", V4SF_type_node);
   TYPE_NAME (V4SF_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
-  tdecl = build_decl (BUILTINS_LOCATION,
-                     TYPE_DECL, get_identifier ("__vector __pixel"),
-                     pixel_V8HI_type_node);
+
+  tdecl = add_builtin_type ("__vector __pixel", pixel_V8HI_type_node);
   TYPE_NAME (pixel_V8HI_type_node) = tdecl;
-  (*lang_hooks.decls.pushdecl) (tdecl);
 
-  if (TARGET_VSX)
-    {
-      tdecl = build_decl (BUILTINS_LOCATION,
-                         TYPE_DECL, get_identifier ("__vector double"),
-                         V2DF_type_node);
-      TYPE_NAME (V2DF_type_node) = tdecl;
-      (*lang_hooks.decls.pushdecl) (tdecl);
+  tdecl = add_builtin_type ("__vector double", V2DF_type_node);
+  TYPE_NAME (V2DF_type_node) = tdecl;
 
-      tdecl = build_decl (BUILTINS_LOCATION,
-                         TYPE_DECL, get_identifier ("__vector long"),
-                         V2DI_type_node);
-      TYPE_NAME (V2DI_type_node) = tdecl;
-      (*lang_hooks.decls.pushdecl) (tdecl);
+  tdecl = add_builtin_type ("__vector long", V2DI_type_node);
+  TYPE_NAME (V2DI_type_node) = tdecl;
 
-      tdecl = build_decl (BUILTINS_LOCATION,
-                         TYPE_DECL, get_identifier ("__vector unsigned long"),
-                         unsigned_V2DI_type_node);
-      TYPE_NAME (unsigned_V2DI_type_node) = tdecl;
-      (*lang_hooks.decls.pushdecl) (tdecl);
+  tdecl = add_builtin_type ("__vector unsigned long", unsigned_V2DI_type_node);
+  TYPE_NAME (unsigned_V2DI_type_node) = tdecl;
 
-      tdecl = build_decl (BUILTINS_LOCATION,
-                         TYPE_DECL, get_identifier ("__vector __bool long"),
-                         bool_V2DI_type_node);
-      TYPE_NAME (bool_V2DI_type_node) = tdecl;
-      (*lang_hooks.decls.pushdecl) (tdecl);
-    }
+  tdecl = add_builtin_type ("__vector __bool long", bool_V2DI_type_node);
+  TYPE_NAME (bool_V2DI_type_node) = tdecl;
 
+  /* Paired and SPE builtins are only available if you build a compiler with
+     the appropriate options, so only create those builtins with the
+     appropriate compiler option.  Create Altivec and VSX builtins on machines
+     with at least the general purpose extensions (970 and newer) to allow the
+     use of the target attribute.  */
   if (TARGET_PAIRED_FLOAT)
     paired_init_builtins ();
   if (TARGET_SPE)
     spe_init_builtins ();
-  if (TARGET_ALTIVEC)
+  if (TARGET_EXTRA_BUILTINS)
     altivec_init_builtins ();
-  if (TARGET_ALTIVEC || TARGET_SPE || TARGET_PAIRED_FLOAT || TARGET_VSX)
+  if (TARGET_EXTRA_BUILTINS || TARGET_SPE || TARGET_PAIRED_FLOAT)
     rs6000_common_init_builtins ();
-  if (TARGET_FRE)
-    {
-      ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
-                                    RS6000_BUILTIN_RECIP,
-                                    "__builtin_recipdiv");
-      def_builtin (MASK_POPCNTB, "__builtin_recipdiv", ftype,
-                  RS6000_BUILTIN_RECIP);
-    }
-  if (TARGET_FRES)
-    {
-      ftype = builtin_function_type (SFmode, SFmode, SFmode, VOIDmode,
-                                    RS6000_BUILTIN_RECIPF,
-                                    "__builtin_recipdivf");
-      def_builtin (MASK_PPC_GFXOPT, "__builtin_recipdivf", ftype,
-                  RS6000_BUILTIN_RECIPF);
-    }
-  if (TARGET_FRSQRTE)
-    {
-      ftype = builtin_function_type (DFmode, DFmode, VOIDmode, VOIDmode,
-                                    RS6000_BUILTIN_RSQRT,
-                                    "__builtin_rsqrt");
-      def_builtin (MASK_PPC_GFXOPT, "__builtin_rsqrt", ftype,
-                  RS6000_BUILTIN_RSQRT);
-    }
-  if (TARGET_FRSQRTES)
-    {
-      ftype = builtin_function_type (SFmode, SFmode, VOIDmode, VOIDmode,
-                                    RS6000_BUILTIN_RSQRTF,
-                                    "__builtin_rsqrtf");
-      def_builtin (MASK_PPC_GFXOPT, "__builtin_rsqrtf", ftype,
-                  RS6000_BUILTIN_RSQRTF);
-    }
-  if (TARGET_POPCNTD)
-    {
-      enum machine_mode mode = (TARGET_64BIT) ? DImode : SImode;
-      tree ftype = builtin_function_type (mode, mode, mode, VOIDmode,
-                                         POWER7_BUILTIN_BPERMD,
-                                         "__builtin_bpermd");
-      def_builtin (MASK_POPCNTD, "__builtin_bpermd", ftype,
-                  POWER7_BUILTIN_BPERMD);
-    }
-  if (TARGET_POWERPC)
-    {
-      /* Don't use builtin_function_type here, as it maps HI/QI to SI.  */
-      tree ftype = build_function_type_list (unsigned_intHI_type_node,
-                                            unsigned_intHI_type_node,
-                                            NULL_TREE);
-      def_builtin (MASK_POWERPC, "__builtin_bswap16", ftype,
-                  RS6000_BUILTIN_BSWAP_HI);
-    }
+
+  ftype = builtin_function_type (DFmode, DFmode, DFmode, VOIDmode,
+                                RS6000_BUILTIN_RECIP, "__builtin_recipdiv");
+  def_builtin ("__builtin_recipdiv", ftype, RS6000_BUILTIN_RECIP);
+
+  ftype = builtin_function_type (SFmode, SFmode, SFmode, VOIDmode,
+                                RS6000_BUILTIN_RECIPF, "__builtin_recipdivf");
+  def_builtin ("__builtin_recipdivf", ftype, RS6000_BUILTIN_RECIPF);
+
+  ftype = builtin_function_type (DFmode, DFmode, VOIDmode, VOIDmode,
+                                RS6000_BUILTIN_RSQRT, "__builtin_rsqrt");
+  def_builtin ("__builtin_rsqrt", ftype, RS6000_BUILTIN_RSQRT);
+
+  ftype = builtin_function_type (SFmode, SFmode, VOIDmode, VOIDmode,
+                                RS6000_BUILTIN_RSQRTF, "__builtin_rsqrtf");
+  def_builtin ("__builtin_rsqrtf", ftype, RS6000_BUILTIN_RSQRTF);
+
+  mode = (TARGET_64BIT) ? DImode : SImode;
+  ftype = builtin_function_type (mode, mode, mode, VOIDmode,
+                                POWER7_BUILTIN_BPERMD, "__builtin_bpermd");
+  def_builtin ("__builtin_bpermd", ftype, POWER7_BUILTIN_BPERMD);
 
 #if TARGET_XCOFF
   /* AIX libm provides clog as __clog.  */
-  if (built_in_decls [BUILT_IN_CLOG])
-    set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
+  if ((tdecl = builtin_decl_explicit (BUILT_IN_CLOG)) != NULL_TREE)
+    set_user_assembler_name (tdecl, "__clog");
 #endif
 
 #ifdef SUBTARGET_INIT_BUILTINS
@@ -12223,38 +11637,19 @@ rs6000_init_builtins (void)
 static tree
 rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
 {
+  unsigned fnmask;
+
   if (code >= RS6000_BUILTIN_COUNT)
     return error_mark_node;
 
-  return rs6000_builtin_decls[code];
-}
-
-/* Search through a set of builtins and enable the mask bits.
-   DESC is an array of builtins.
-   SIZE is the total number of builtins.
-   START is the builtin enum at which to start.
-   END is the builtin enum at which to end.  */
-static void
-enable_mask_for_builtins (struct builtin_description *desc, int size,
-                         enum rs6000_builtins start,
-                         enum rs6000_builtins end)
-{
-  int i;
-
-  for (i = 0; i < size; ++i)
-    if (desc[i].code == start)
-      break;
-
-  if (i == size)
-    return;
-
-  for (; i < size; ++i)
+  fnmask = rs6000_builtin_info[code].mask;
+  if ((fnmask & rs6000_builtin_mask) != fnmask)
     {
-      /* Flip all the bits on.  */
-      desc[i].mask = target_flags;
-      if (desc[i].code == end)
-       break;
+      rs6000_invalid_builtin ((enum rs6000_builtins)code);
+      return error_mark_node;
     }
+
+  return rs6000_builtin_decls[code];
 }
 
 static void
@@ -12262,7 +11657,7 @@ spe_init_builtins (void)
 {
   tree puint_type_node = build_pointer_type (unsigned_type_node);
   tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
 
   tree v2si_ftype_4_v2si
@@ -12352,80 +11747,55 @@ spe_init_builtins (void)
                                 signed_char_type_node,
                                 NULL_TREE);
 
-  /* The initialization of the simple binary and unary builtins is
-     done in rs6000_common_init_builtins, but we have to enable the
-     mask bits here manually because we have run out of `target_flags'
-     bits.  We really need to redesign this mask business.  */
-
-  enable_mask_for_builtins ((struct builtin_description *) bdesc_2arg,
-                           ARRAY_SIZE (bdesc_2arg),
-                           SPE_BUILTIN_EVADDW,
-                           SPE_BUILTIN_EVXOR);
-  enable_mask_for_builtins ((struct builtin_description *) bdesc_1arg,
-                           ARRAY_SIZE (bdesc_1arg),
-                           SPE_BUILTIN_EVABS,
-                           SPE_BUILTIN_EVSUBFUSIAAW);
-  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_predicates,
-                           ARRAY_SIZE (bdesc_spe_predicates),
-                           SPE_BUILTIN_EVCMPEQ,
-                           SPE_BUILTIN_EVFSTSTLT);
-  enable_mask_for_builtins ((struct builtin_description *) bdesc_spe_evsel,
-                           ARRAY_SIZE (bdesc_spe_evsel),
-                           SPE_BUILTIN_EVSEL_CMPGTS,
-                           SPE_BUILTIN_EVSEL_FSTSTEQ);
-
-  (*lang_hooks.decls.pushdecl)
-    (build_decl (BUILTINS_LOCATION, TYPE_DECL,
-                get_identifier ("__ev64_opaque__"),
-                opaque_V2SI_type_node));
+  add_builtin_type ("__ev64_opaque__", opaque_V2SI_type_node);
 
   /* Initialize irregular SPE builtins.  */
 
-  def_builtin (target_flags, "__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
-  def_builtin (target_flags, "__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
-  def_builtin (target_flags, "__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
-  def_builtin (target_flags, "__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
-  def_builtin (target_flags, "__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
-  def_builtin (target_flags, "__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
-  def_builtin (target_flags, "__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
-  def_builtin (target_flags, "__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
-  def_builtin (target_flags, "__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
-  def_builtin (target_flags, "__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
-  def_builtin (target_flags, "__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
-  def_builtin (target_flags, "__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
-  def_builtin (target_flags, "__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
-  def_builtin (target_flags, "__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
-  def_builtin (target_flags, "__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
-  def_builtin (target_flags, "__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
-  def_builtin (target_flags, "__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
-  def_builtin (target_flags, "__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
+  def_builtin ("__builtin_spe_mtspefscr", void_ftype_int, SPE_BUILTIN_MTSPEFSCR);
+  def_builtin ("__builtin_spe_mfspefscr", int_ftype_void, SPE_BUILTIN_MFSPEFSCR);
+  def_builtin ("__builtin_spe_evstddx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDDX);
+  def_builtin ("__builtin_spe_evstdhx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDHX);
+  def_builtin ("__builtin_spe_evstdwx", void_ftype_v2si_pv2si_int, SPE_BUILTIN_EVSTDWX);
+  def_builtin ("__builtin_spe_evstwhex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHEX);
+  def_builtin ("__builtin_spe_evstwhox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWHOX);
+  def_builtin ("__builtin_spe_evstwwex", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWEX);
+  def_builtin ("__builtin_spe_evstwwox", void_ftype_v2si_puint_int, SPE_BUILTIN_EVSTWWOX);
+  def_builtin ("__builtin_spe_evstdd", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDD);
+  def_builtin ("__builtin_spe_evstdh", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDH);
+  def_builtin ("__builtin_spe_evstdw", void_ftype_v2si_pv2si_char, SPE_BUILTIN_EVSTDW);
+  def_builtin ("__builtin_spe_evstwhe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHE);
+  def_builtin ("__builtin_spe_evstwho", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWHO);
+  def_builtin ("__builtin_spe_evstwwe", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWE);
+  def_builtin ("__builtin_spe_evstwwo", void_ftype_v2si_puint_char, SPE_BUILTIN_EVSTWWO);
+  def_builtin ("__builtin_spe_evsplatfi", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATFI);
+  def_builtin ("__builtin_spe_evsplati", v2si_ftype_signed_char, SPE_BUILTIN_EVSPLATI);
 
   /* Loads.  */
-  def_builtin (target_flags, "__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
-  def_builtin (target_flags, "__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
-  def_builtin (target_flags, "__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
-  def_builtin (target_flags, "__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
-  def_builtin (target_flags, "__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
-  def_builtin (target_flags, "__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
-  def_builtin (target_flags, "__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
-  def_builtin (target_flags, "__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
-  def_builtin (target_flags, "__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
-  def_builtin (target_flags, "__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
-  def_builtin (target_flags, "__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
-  def_builtin (target_flags, "__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
-  def_builtin (target_flags, "__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
-  def_builtin (target_flags, "__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
-  def_builtin (target_flags, "__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
-  def_builtin (target_flags, "__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
-  def_builtin (target_flags, "__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
-  def_builtin (target_flags, "__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
-  def_builtin (target_flags, "__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
-  def_builtin (target_flags, "__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
-  def_builtin (target_flags, "__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
-  def_builtin (target_flags, "__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
+  def_builtin ("__builtin_spe_evlddx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDDX);
+  def_builtin ("__builtin_spe_evldwx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDWX);
+  def_builtin ("__builtin_spe_evldhx", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDHX);
+  def_builtin ("__builtin_spe_evlwhex", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHEX);
+  def_builtin ("__builtin_spe_evlwhoux", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOUX);
+  def_builtin ("__builtin_spe_evlwhosx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOSX);
+  def_builtin ("__builtin_spe_evlwwsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLATX);
+  def_builtin ("__builtin_spe_evlwhsplatx", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLATX);
+  def_builtin ("__builtin_spe_evlhhesplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLATX);
+  def_builtin ("__builtin_spe_evlhhousplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLATX);
+  def_builtin ("__builtin_spe_evlhhossplatx", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLATX);
+  def_builtin ("__builtin_spe_evldd", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDD);
+  def_builtin ("__builtin_spe_evldw", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDW);
+  def_builtin ("__builtin_spe_evldh", v2si_ftype_pv2si_int, SPE_BUILTIN_EVLDH);
+  def_builtin ("__builtin_spe_evlhhesplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHESPLAT);
+  def_builtin ("__builtin_spe_evlhhossplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOSSPLAT);
+  def_builtin ("__builtin_spe_evlhhousplat", v2si_ftype_pushort_int, SPE_BUILTIN_EVLHHOUSPLAT);
+  def_builtin ("__builtin_spe_evlwhe", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHE);
+  def_builtin ("__builtin_spe_evlwhos", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOS);
+  def_builtin ("__builtin_spe_evlwhou", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHOU);
+  def_builtin ("__builtin_spe_evlwhsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWHSPLAT);
+  def_builtin ("__builtin_spe_evlwwsplat", v2si_ftype_puint_int, SPE_BUILTIN_EVLWWSPLAT);
 
   /* Predicates.  */
-  d = (struct builtin_description *) bdesc_spe_predicates;
+  d = bdesc_spe_predicates;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, d++)
     {
       tree type;
@@ -12442,11 +11812,11 @@ spe_init_builtins (void)
          gcc_unreachable ();
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 
   /* Evsel predicates.  */
-  d = (struct builtin_description *) bdesc_spe_evsel;
+  d = bdesc_spe_evsel;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, d++)
     {
       tree type;
@@ -12463,7 +11833,7 @@ spe_init_builtins (void)
          gcc_unreachable ();
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 }
 
@@ -12495,11 +11865,11 @@ paired_init_builtins (void)
                              NULL_TREE);
 
 
-  def_builtin (0, "__builtin_paired_lx", v2sf_ftype_long_pcfloat,
+  def_builtin ("__builtin_paired_lx", v2sf_ftype_long_pcfloat,
               PAIRED_BUILTIN_LX);
 
 
-  def_builtin (0, "__builtin_paired_stx", void_ftype_v2sf_long_pcfloat,
+  def_builtin ("__builtin_paired_stx", void_ftype_v2sf_long_pcfloat,
               PAIRED_BUILTIN_STX);
 
   /* Predicates.  */
@@ -12508,6 +11878,11 @@ paired_init_builtins (void)
     {
       tree type;
 
+      if (TARGET_DEBUG_BUILTIN)
+       fprintf (stderr, "paired pred #%d, insn = %s [%d], mode = %s\n",
+                (int)i, get_insn_name (d->icode), (int)d->icode,
+                GET_MODE_NAME (insn_data[d->icode].operand[1].mode));
+
       switch (insn_data[d->icode].operand[1].mode)
        {
        case V2SFmode:
@@ -12517,7 +11892,7 @@ paired_init_builtins (void)
          gcc_unreachable ();
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 }
 
@@ -12525,9 +11900,9 @@ static void
 altivec_init_builtins (void)
 {
   const struct builtin_description *d;
-  const struct builtin_description_predicates *dp;
   size_t i;
   tree ftype;
+  tree decl;
 
   tree pvoid_type_node = build_pointer_type (void_type_node);
 
@@ -12652,125 +12027,120 @@ altivec_init_builtins (void)
                                pcvoid_type_node, integer_type_node,
                                integer_type_node, NULL_TREE);
 
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
-  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);
-  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_VSX, "__builtin_vsx_lxvd2x_v2df", v2df_ftype_long_pcvoid,
+  def_builtin ("__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
+  def_builtin ("__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
+  def_builtin ("__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
+  def_builtin ("__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
+  def_builtin ("__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
+  def_builtin ("__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
+  def_builtin ("__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
+  def_builtin ("__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
+  def_builtin ("__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
+  def_builtin ("__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
+  def_builtin ("__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
+  def_builtin ("__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
+  def_builtin ("__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
+  def_builtin ("__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
+  def_builtin ("__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
+  def_builtin ("__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
+  def_builtin ("__builtin_vec_ld", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LD);
+  def_builtin ("__builtin_vec_lde", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDE);
+  def_builtin ("__builtin_vec_ldl", opaque_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LDL);
+  def_builtin ("__builtin_vec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSL);
+  def_builtin ("__builtin_vec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVSR);
+  def_builtin ("__builtin_vec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEBX);
+  def_builtin ("__builtin_vec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEHX);
+  def_builtin ("__builtin_vec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVEWX);
+  def_builtin ("__builtin_vec_st", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_ST);
+  def_builtin ("__builtin_vec_ste", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STE);
+  def_builtin ("__builtin_vec_stl", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STL);
+  def_builtin ("__builtin_vec_stvewx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEWX);
+  def_builtin ("__builtin_vec_stvebx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEBX);
+  def_builtin ("__builtin_vec_stvehx", void_ftype_opaque_long_pvoid, ALTIVEC_BUILTIN_VEC_STVEHX);
+
+  def_builtin ("__builtin_vsx_lxvd2x_v2df", v2df_ftype_long_pcvoid,
               VSX_BUILTIN_LXVD2X_V2DF);
-  def_builtin (MASK_VSX, "__builtin_vsx_lxvd2x_v2di", v2di_ftype_long_pcvoid,
+  def_builtin ("__builtin_vsx_lxvd2x_v2di", v2di_ftype_long_pcvoid,
               VSX_BUILTIN_LXVD2X_V2DI);
-  def_builtin (MASK_VSX, "__builtin_vsx_lxvw4x_v4sf", v4sf_ftype_long_pcvoid,
+  def_builtin ("__builtin_vsx_lxvw4x_v4sf", v4sf_ftype_long_pcvoid,
               VSX_BUILTIN_LXVW4X_V4SF);
-  def_builtin (MASK_VSX, "__builtin_vsx_lxvw4x_v4si", v4si_ftype_long_pcvoid,
+  def_builtin ("__builtin_vsx_lxvw4x_v4si", v4si_ftype_long_pcvoid,
               VSX_BUILTIN_LXVW4X_V4SI);
-  def_builtin (MASK_VSX, "__builtin_vsx_lxvw4x_v8hi",
-              v8hi_ftype_long_pcvoid, VSX_BUILTIN_LXVW4X_V8HI);
-  def_builtin (MASK_VSX, "__builtin_vsx_lxvw4x_v16qi",
-              v16qi_ftype_long_pcvoid, VSX_BUILTIN_LXVW4X_V16QI);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvd2x_v2df",
-              void_ftype_v2df_long_pvoid, VSX_BUILTIN_STXVD2X_V2DF);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvd2x_v2di",
-              void_ftype_v2di_long_pvoid, VSX_BUILTIN_STXVD2X_V2DI);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvw4x_v4sf",
-              void_ftype_v4sf_long_pvoid, VSX_BUILTIN_STXVW4X_V4SF);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvw4x_v4si",
-              void_ftype_v4si_long_pvoid, VSX_BUILTIN_STXVW4X_V4SI);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvw4x_v8hi",
-              void_ftype_v8hi_long_pvoid, VSX_BUILTIN_STXVW4X_V8HI);
-  def_builtin (MASK_VSX, "__builtin_vsx_stxvw4x_v16qi",
-              void_ftype_v16qi_long_pvoid, VSX_BUILTIN_STXVW4X_V16QI);
-  def_builtin (MASK_VSX, "__builtin_vec_vsx_ld", opaque_ftype_long_pcvoid,
+  def_builtin ("__builtin_vsx_lxvw4x_v8hi", v8hi_ftype_long_pcvoid,
+              VSX_BUILTIN_LXVW4X_V8HI);
+  def_builtin ("__builtin_vsx_lxvw4x_v16qi", v16qi_ftype_long_pcvoid,
+              VSX_BUILTIN_LXVW4X_V16QI);
+  def_builtin ("__builtin_vsx_stxvd2x_v2df", void_ftype_v2df_long_pvoid,
+              VSX_BUILTIN_STXVD2X_V2DF);
+  def_builtin ("__builtin_vsx_stxvd2x_v2di", void_ftype_v2di_long_pvoid,
+              VSX_BUILTIN_STXVD2X_V2DI);
+  def_builtin ("__builtin_vsx_stxvw4x_v4sf", void_ftype_v4sf_long_pvoid,
+              VSX_BUILTIN_STXVW4X_V4SF);
+  def_builtin ("__builtin_vsx_stxvw4x_v4si", void_ftype_v4si_long_pvoid,
+              VSX_BUILTIN_STXVW4X_V4SI);
+  def_builtin ("__builtin_vsx_stxvw4x_v8hi", void_ftype_v8hi_long_pvoid,
+              VSX_BUILTIN_STXVW4X_V8HI);
+  def_builtin ("__builtin_vsx_stxvw4x_v16qi", void_ftype_v16qi_long_pvoid,
+              VSX_BUILTIN_STXVW4X_V16QI);
+  def_builtin ("__builtin_vec_vsx_ld", opaque_ftype_long_pcvoid,
               VSX_BUILTIN_VEC_LD);
-  def_builtin (MASK_VSX, "__builtin_vec_vsx_st", void_ftype_opaque_long_pvoid,
+  def_builtin ("__builtin_vec_vsx_st", void_ftype_opaque_long_pvoid,
               VSX_BUILTIN_VEC_ST);
 
-  if (rs6000_cpu == PROCESSOR_CELL)
-    {
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLX);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLXL);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRX);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRXL);
-
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLX);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLXL);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRX);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRXL);
-
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLX);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLXL);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRX);
-      def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRXL);
-
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLX);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLXL);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRX);
-      def_builtin (MASK_ALTIVEC, "__builtin_vec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRXL);
-    }
-  def_builtin (MASK_ALTIVEC, "__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
-  def_builtin (MASK_ALTIVEC, "__builtin_vec_splats", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_SPLATS);
-  def_builtin (MASK_ALTIVEC, "__builtin_vec_promote", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_PROMOTE);
-
-  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_extract", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_EXTRACT);
-  def_builtin (MASK_ALTIVEC, "__builtin_vec_insert", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_INSERT);
-  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);
+  def_builtin ("__builtin_vec_step", int_ftype_opaque, ALTIVEC_BUILTIN_VEC_STEP);
+  def_builtin ("__builtin_vec_splats", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_SPLATS);
+  def_builtin ("__builtin_vec_promote", opaque_ftype_opaque, ALTIVEC_BUILTIN_VEC_PROMOTE);
+
+  def_builtin ("__builtin_vec_sld", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_SLD);
+  def_builtin ("__builtin_vec_splat", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_SPLAT);
+  def_builtin ("__builtin_vec_extract", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_EXTRACT);
+  def_builtin ("__builtin_vec_insert", opaque_ftype_opaque_opaque_int, ALTIVEC_BUILTIN_VEC_INSERT);
+  def_builtin ("__builtin_vec_vspltw", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTW);
+  def_builtin ("__builtin_vec_vsplth", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTH);
+  def_builtin ("__builtin_vec_vspltb", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VSPLTB);
+  def_builtin ("__builtin_vec_ctf", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTF);
+  def_builtin ("__builtin_vec_vcfsx", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFSX);
+  def_builtin ("__builtin_vec_vcfux", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_VCFUX);
+  def_builtin ("__builtin_vec_cts", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTS);
+  def_builtin ("__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
+
+  /* Cell builtins.  */
+  def_builtin ("__builtin_altivec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLX);
+  def_builtin ("__builtin_altivec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVLXL);
+  def_builtin ("__builtin_altivec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRX);
+  def_builtin ("__builtin_altivec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVRXL);
+
+  def_builtin ("__builtin_vec_lvlx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLX);
+  def_builtin ("__builtin_vec_lvlxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVLXL);
+  def_builtin ("__builtin_vec_lvrx",  v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRX);
+  def_builtin ("__builtin_vec_lvrxl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_VEC_LVRXL);
+
+  def_builtin ("__builtin_altivec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLX);
+  def_builtin ("__builtin_altivec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVLXL);
+  def_builtin ("__builtin_altivec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRX);
+  def_builtin ("__builtin_altivec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVRXL);
+
+  def_builtin ("__builtin_vec_stvlx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLX);
+  def_builtin ("__builtin_vec_stvlxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVLXL);
+  def_builtin ("__builtin_vec_stvrx",  void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRX);
+  def_builtin ("__builtin_vec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRXL);
 
   /* Add the DST variants.  */
   d = bdesc_dst;
   for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
-    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
+    def_builtin (d->name, void_ftype_pcvoid_int_int, d->code);
 
   /* Initialize the predicates.  */
-  dp = bdesc_altivec_preds;
-  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
+  d = bdesc_altivec_preds;
+  for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, d++)
     {
       enum machine_mode mode1;
       tree type;
-      bool is_overloaded = ((dp->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
-                            && dp->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
-                           || (dp->code >= VSX_BUILTIN_OVERLOADED_FIRST
-                               && dp->code <= VSX_BUILTIN_OVERLOADED_LAST));
 
-      if (is_overloaded)
+      if (rs6000_overloaded_builtin_p (d->code))
        mode1 = VOIDmode;
       else
-       mode1 = insn_data[dp->icode].operand[1].mode;
+       mode1 = insn_data[d->icode].operand[1].mode;
 
       switch (mode1)
        {
@@ -12796,7 +12166,7 @@ altivec_init_builtins (void)
          gcc_unreachable ();
        }
 
-      def_builtin (dp->mask, dp->name, type, dp->code);
+      def_builtin (d->name, type, d->code);
     }
 
   /* Initialize the abs* operators.  */
@@ -12829,31 +12199,25 @@ altivec_init_builtins (void)
          gcc_unreachable ();
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 
-  if (TARGET_ALTIVEC)
-    {
-      tree decl;
-
-      /* Initialize target builtin that implements
-         targetm.vectorize.builtin_mask_for_load.  */
+  /* Initialize target builtin that implements
+     targetm.vectorize.builtin_mask_for_load.  */
 
-      decl = add_builtin_function ("__builtin_altivec_mask_for_load",
-                                  v16qi_ftype_long_pcvoid,
-                                  ALTIVEC_BUILTIN_MASK_FOR_LOAD,
-                                  BUILT_IN_MD, NULL, NULL_TREE);
-      TREE_READONLY (decl) = 1;
-      /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
-      altivec_builtin_mask_for_load = decl;
-    }
+  decl = add_builtin_function ("__builtin_altivec_mask_for_load",
+                              v16qi_ftype_long_pcvoid,
+                              ALTIVEC_BUILTIN_MASK_FOR_LOAD,
+                              BUILT_IN_MD, NULL, NULL_TREE);
+  TREE_READONLY (decl) = 1;
+  /* 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);
+  def_builtin ("__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,
@@ -12863,8 +12227,7 @@ altivec_init_builtins (void)
                                    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);
+  def_builtin ("__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,
@@ -12875,101 +12238,78 @@ altivec_init_builtins (void)
                                    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,
+  def_builtin ("__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);
+  def_builtin ("__builtin_vec_init_v4sf", ftype, ALTIVEC_BUILTIN_VEC_INIT_V4SF);
 
-  if (TARGET_VSX)
-    {
-      ftype = build_function_type_list (V2DF_type_node, double_type_node,
-                                       double_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_init_v2df", ftype,
-                  VSX_BUILTIN_VEC_INIT_V2DF);
+  /* VSX builtins.  */
+  ftype = build_function_type_list (V2DF_type_node, double_type_node,
+                                   double_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_init_v2df", ftype, VSX_BUILTIN_VEC_INIT_V2DF);
 
-      ftype = build_function_type_list (V2DI_type_node, intDI_type_node,
-                                       intDI_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_init_v2di", ftype,
-                  VSX_BUILTIN_VEC_INIT_V2DI);
-    }
+  ftype = build_function_type_list (V2DI_type_node, intDI_type_node,
+                                   intDI_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_init_v2di", ftype, VSX_BUILTIN_VEC_INIT_V2DI);
 
   /* 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);
+  def_builtin ("__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);
+  def_builtin ("__builtin_vec_set_v8hi", ftype, ALTIVEC_BUILTIN_VEC_SET_V8HI);
 
   ftype = build_function_type_list (V16QI_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);
+  def_builtin ("__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|MASK_VSX, "__builtin_vec_set_v4sf", ftype,
-              ALTIVEC_BUILTIN_VEC_SET_V4SF);
+  def_builtin ("__builtin_vec_set_v4sf", ftype, ALTIVEC_BUILTIN_VEC_SET_V4SF);
 
-  if (TARGET_VSX)
-    {
-      ftype = build_function_type_list (V2DF_type_node, V2DF_type_node,
-                                       double_type_node,
-                                       integer_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_set_v2df", ftype,
-                  VSX_BUILTIN_VEC_SET_V2DF);
+  ftype = build_function_type_list (V2DF_type_node, V2DF_type_node,
+                                   double_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_set_v2df", ftype, VSX_BUILTIN_VEC_SET_V2DF);
 
-      ftype = build_function_type_list (V2DI_type_node, V2DI_type_node,
-                                       intDI_type_node,
-                                       integer_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_set_v2di", ftype,
-                  VSX_BUILTIN_VEC_SET_V2DI);
-    }
+  ftype = build_function_type_list (V2DI_type_node, V2DI_type_node,
+                                   intDI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_set_v2di", ftype, VSX_BUILTIN_VEC_SET_V2DI);
 
   /* 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);
+  def_builtin ("__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);
+  def_builtin ("__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);
+  def_builtin ("__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|MASK_VSX, "__builtin_vec_ext_v4sf", ftype,
-              ALTIVEC_BUILTIN_VEC_EXT_V4SF);
+  def_builtin ("__builtin_vec_ext_v4sf", ftype, ALTIVEC_BUILTIN_VEC_EXT_V4SF);
 
-  if (TARGET_VSX)
-    {
-      ftype = build_function_type_list (double_type_node, V2DF_type_node,
-                                       integer_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_ext_v2df", ftype,
-                  VSX_BUILTIN_VEC_EXT_V2DF);
+  ftype = build_function_type_list (double_type_node, V2DF_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_ext_v2df", ftype, VSX_BUILTIN_VEC_EXT_V2DF);
 
-      ftype = build_function_type_list (intDI_type_node, V2DI_type_node,
-                                       integer_type_node, NULL_TREE);
-      def_builtin (MASK_VSX, "__builtin_vec_ext_v2di", ftype,
-                  VSX_BUILTIN_VEC_EXT_V2DI);
-    }
+  ftype = build_function_type_list (intDI_type_node, V2DI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin ("__builtin_vec_ext_v2di", ftype, VSX_BUILTIN_VEC_EXT_V2DI);
 }
 
 /* Hash function for builtin functions with up to 3 arguments and a return
@@ -13096,13 +12436,13 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
 
       /* unsigned args, signed return.  */
     case VSX_BUILTIN_XVCVUXDDP_UNS:
-    case VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF:
+    case ALTIVEC_BUILTIN_UNSFLOAT_V4SI_V4SF:
       h.uns_p[1] = 1;
       break;
 
       /* signed args, unsigned return.  */
     case VSX_BUILTIN_XVCVDPUXDS_UNS:
-    case VECTOR_BUILTIN_FIXUNS_V4SF_V4SI:
+    case ALTIVEC_BUILTIN_FIXUNS_V4SF_V4SI:
       h.uns_p[0] = 1;
       break;
 
@@ -13169,6 +12509,7 @@ rs6000_common_init_builtins (void)
   tree v2si_ftype_qi = NULL_TREE;
   tree v2si_ftype_v2si_qi = NULL_TREE;
   tree v2si_ftype_int_qi = NULL_TREE;
+  unsigned builtin_mask = rs6000_builtin_mask;
 
   if (!TARGET_PAIRED_FLOAT)
     {
@@ -13176,21 +12517,30 @@ rs6000_common_init_builtins (void)
       builtin_mode_to_type[V2SFmode][0] = opaque_V2SF_type_node;
     }
 
+  /* Paired and SPE builtins are only available if you build a compiler with
+     the appropriate options, so only create those builtins with the
+     appropriate compiler option.  Create Altivec and VSX builtins on machines
+     with at least the general purpose extensions (970 and newer) to allow the
+     use of the target attribute..  */
+
+  if (TARGET_EXTRA_BUILTINS)
+    builtin_mask |= RS6000_BTM_COMMON;
+
   /* Add the ternary operators.  */
   d = bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
     {
       tree type;
-      int mask = d->mask;
+      unsigned mask = d->mask;
 
-      if ((mask != 0 && (mask & target_flags) == 0)
-         || (mask == 0 && !TARGET_PAIRED_FLOAT))
-       continue;
+      if ((mask & builtin_mask) != mask)
+       {
+         if (TARGET_DEBUG_BUILTIN)
+           fprintf (stderr, "rs6000_builtin, skip ternary %s\n", d->name);
+         continue;
+       }
 
-      if ((d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
-          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
-         || (d->code >= VSX_BUILTIN_OVERLOADED_FIRST
-             && d->code <= VSX_BUILTIN_OVERLOADED_LAST))
+      if (rs6000_overloaded_builtin_p (d->code))
        {
          if (! (type = opaque_ftype_opaque_opaque_opaque))
            type = opaque_ftype_opaque_opaque_opaque
@@ -13213,7 +12563,7 @@ rs6000_common_init_builtins (void)
                                        d->code, d->name);
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 
   /* Add the binary operators.  */
@@ -13222,16 +12572,16 @@ rs6000_common_init_builtins (void)
     {
       enum machine_mode mode0, mode1, mode2;
       tree type;
-      int mask = d->mask;
+      unsigned mask = d->mask;
 
-      if ((mask != 0 && (mask & target_flags) == 0)
-         || (mask == 0 && !TARGET_PAIRED_FLOAT))
-       continue;
+      if ((mask & builtin_mask) != mask)
+       {
+         if (TARGET_DEBUG_BUILTIN)
+           fprintf (stderr, "rs6000_builtin, skip binary %s\n", d->name);
+         continue;
+       }
 
-      if ((d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
-          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
-         || (d->code >= VSX_BUILTIN_OVERLOADED_FIRST
-             && d->code <= VSX_BUILTIN_OVERLOADED_LAST))
+      if (rs6000_overloaded_builtin_p (d->code))
        {
          if (! (type = opaque_ftype_opaque_opaque))
            type = opaque_ftype_opaque_opaque
@@ -13276,25 +12626,25 @@ rs6000_common_init_builtins (void)
                                          d->code, d->name);
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 
   /* Add the simple unary operators.  */
-  d = (struct builtin_description *) bdesc_1arg;
+  d = bdesc_1arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
     {
       enum machine_mode mode0, mode1;
       tree type;
-      int mask = d->mask;
+      unsigned mask = d->mask;
 
-      if ((mask != 0 && (mask & target_flags) == 0)
-         || (mask == 0 && !TARGET_PAIRED_FLOAT))
-       continue;
+      if ((mask & builtin_mask) != mask)
+       {
+         if (TARGET_DEBUG_BUILTIN)
+           fprintf (stderr, "rs6000_builtin, skip unary %s\n", d->name);
+         continue;
+       }
 
-      if ((d->code >= ALTIVEC_BUILTIN_OVERLOADED_FIRST
-          && d->code <= ALTIVEC_BUILTIN_OVERLOADED_LAST)
-         || (d->code >= VSX_BUILTIN_OVERLOADED_FIRST
-             && d->code <= VSX_BUILTIN_OVERLOADED_LAST))
+      if (rs6000_overloaded_builtin_p (d->code))
        {
          if (! (type = opaque_ftype_opaque))
            type = opaque_ftype_opaque
@@ -13325,23 +12675,13 @@ rs6000_common_init_builtins (void)
                                          d->code, d->name);
        }
 
-      def_builtin (d->mask, d->name, type, d->code);
+      def_builtin (d->name, type, d->code);
     }
 }
 
 static void
 rs6000_init_libfuncs (void)
 {
-  if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
-      && !TARGET_POWER2 && !TARGET_POWERPC)
-    {
-      /* AIX library routines for float->int conversion.  */
-      set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
-      set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
-      set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
-      set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
-    }
-
   if (!TARGET_IEEEQUAD)
       /* AIX/Darwin/64-bit Linux quad floating point routines.  */
     if (!TARGET_XL_COMPAT)
@@ -13390,7 +12730,7 @@ rs6000_init_libfuncs (void)
       set_optab_libfunc (neg_optab, TFmode, "_q_neg");
       set_optab_libfunc (smul_optab, TFmode, "_q_mul");
       set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
-      if (TARGET_PPC_GPOPT || TARGET_POWER2)
+      if (TARGET_PPC_GPOPT)
        set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
 
       set_optab_libfunc (eq_optab, TFmode, "_q_feq");
@@ -13711,7 +13051,7 @@ rs6000_output_load_multiple (rtx operands[3])
   rtx xop[10];
 
   if (XVECLEN (operands[0], 0) == 1)
-    return "{l|lwz} %2,0(%1)";
+    return "lwz %2,0(%1)";
 
   for (i = 0; i < words; i++)
     if (refers_to_regno_p (REGNO (operands[2]) + i,
@@ -13722,7 +13062,7 @@ rs6000_output_load_multiple (rtx operands[3])
            xop[0] = GEN_INT (4 * (words-1));
            xop[1] = operands[1];
            xop[2] = operands[2];
-           output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
+           output_asm_insn ("lswi %2,%1,%0\n\tlwz %1,%0(%1)", xop);
            return "";
          }
        else if (i == 0)
@@ -13730,7 +13070,7 @@ rs6000_output_load_multiple (rtx operands[3])
            xop[0] = GEN_INT (4 * (words-1));
            xop[1] = operands[1];
            xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
-           output_asm_insn ("{cal %1,4(%1)|addi %1,%1,4}\n\t{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,-4(%1)", xop);
+           output_asm_insn ("addi %1,%1,4\n\tlswi %2,%1,%0\n\tlwz %1,-4(%1)", xop);
            return "";
          }
        else
@@ -13741,16 +13081,16 @@ rs6000_output_load_multiple (rtx operands[3])
                  xop[0] = GEN_INT (j * 4);
                  xop[1] = operands[1];
                  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
-                 output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
+                 output_asm_insn ("lwz %2,%0(%1)", xop);
                }
            xop[0] = GEN_INT (i * 4);
            xop[1] = operands[1];
-           output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
+           output_asm_insn ("lwz %1,%0(%1)", xop);
            return "";
          }
       }
 
-  return "{lsi|lswi} %2,%1,%N0";
+  return "lswi %2,%1,%N0";
 }
 
 \f
@@ -14231,7 +13571,8 @@ rs6000_secondary_reload (bool in_p,
          if (rclass == GENERAL_REGS || rclass == BASE_REGS)
            {
              if (!legitimate_indirect_address_p (addr, false)
-                 && !rs6000_legitimate_offset_address_p (TImode, addr, false))
+                 && !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                         false, true))
                {
                  sri->icode = icode;
                  /* account for splitting the loads, and converting the
@@ -14304,18 +13645,12 @@ rs6000_secondary_reload (bool in_p,
           && MEM_P (x)
           && GET_MODE_SIZE (GET_MODE (x)) >= UNITS_PER_WORD)
     {
-      rtx addr = XEXP (x, 0);
-
-      if (GET_CODE (addr) == PRE_MODIFY)
-       addr = XEXP (addr, 1);
-      else if (GET_CODE (addr) == LO_SUM
-              && GET_CODE (XEXP (addr, 0)) == REG
-              && GET_CODE (XEXP (addr, 1)) == CONST)
-       addr = XEXP (XEXP (addr, 1), 0);
+      rtx off = address_offset (XEXP (x, 0));
+      unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
 
-      if (GET_CODE (addr) == PLUS
-         && GET_CODE (XEXP (addr, 1)) == CONST_INT
-         && (INTVAL (XEXP (addr, 1)) & 3) != 0)
+      if (off != NULL_RTX
+         && (INTVAL (off) & 3) != 0
+         && (unsigned HOST_WIDE_INT) INTVAL (off) + 0x8000 < 0x10000 - extra)
        {
          if (in_p)
            sri->icode = CODE_FOR_reload_di_load;
@@ -14327,10 +13662,38 @@ rs6000_secondary_reload (bool in_p,
       else
        default_p = true;
     }
-  else
-    default_p = true;
+  else if (!TARGET_POWERPC64
+          && rs6000_reload_register_type (rclass) == GPR_REGISTER_TYPE
+          && MEM_P (x)
+          && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+    {
+      rtx off = address_offset (XEXP (x, 0));
+      unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
 
-  if (default_p)
+      /* We need a secondary reload only when our legitimate_address_p
+        says the address is good (as otherwise the entire address
+        will be reloaded).  So for mode sizes of 8 and 16 this will
+        be when the offset is in the ranges [0x7ffc,0x7fff] and
+        [0x7ff4,0x7ff7] respectively.  Note that the address we see
+        here may have been manipulated by legitimize_reload_address.  */
+      if (off != NULL_RTX
+         && ((unsigned HOST_WIDE_INT) INTVAL (off) - (0x8000 - extra)
+             < UNITS_PER_WORD))
+       {
+         if (in_p)
+           sri->icode = CODE_FOR_reload_si_load;
+         else
+           sri->icode = CODE_FOR_reload_si_store;
+         sri->extra_cost = 2;
+         ret = NO_REGS;
+       }
+      else
+       default_p = true;
+    }
+  else
+    default_p = true;
+
+  if (default_p)
     ret = default_secondary_reload (in_p, x, rclass, mode, sri);
 
   gcc_assert (ret != ALL_REGS);
@@ -14415,8 +13778,9 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
        }
 
       if (GET_CODE (addr) == PLUS
-         && (!rs6000_legitimate_offset_address_p (TImode, addr, false)
-             || and_op2 != NULL_RTX))
+         && (and_op2 != NULL_RTX
+             || !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                     false, true)))
        {
          addr_op1 = XEXP (addr, 0);
          addr_op2 = XEXP (addr, 1);
@@ -14448,7 +13812,8 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
          scratch_or_premodify = scratch;
        }
       else if (!legitimate_indirect_address_p (addr, false)
-              && !rs6000_legitimate_offset_address_p (TImode, addr, false))
+              && !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                      false, true))
        {
          if (TARGET_DEBUG_ADDR)
            {
@@ -14507,7 +13872,7 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
              && GET_MODE_SIZE (mode) == 8
              && and_op2 == NULL_RTX
              && scratch_or_premodify == scratch
-             && rs6000_legitimate_offset_address_p (mode, addr, false)))
+             && rs6000_legitimate_offset_address_p (mode, addr, false, false)))
        ;
 
       else if (GET_CODE (addr) == PLUS)
@@ -14616,10 +13981,11 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
 }
 
 /* Convert reloads involving 64-bit gprs and misaligned offset
-   addressing to use indirect addressing.  */
+   addressing, or multiple 32-bit gprs and offsets that are too large,
+   to use indirect addressing.  */
 
 void
-rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
+rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
 {
   int regno = true_regnum (reg);
   enum reg_class rclass;
@@ -14628,7 +13994,7 @@ rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
 
   if (TARGET_DEBUG_ADDR)
     {
-      fprintf (stderr, "\nrs6000_secondary_reload_ppc64, type = %s\n",
+      fprintf (stderr, "\nrs6000_secondary_reload_gpr, type = %s\n",
               store_p ? "store" : "load");
       fprintf (stderr, "reg:\n");
       debug_rtx (reg);
@@ -15258,7 +14624,6 @@ void
 print_operand (FILE *file, rtx x, int code)
 {
   int i;
-  HOST_WIDE_INT val;
   unsigned HOST_WIDE_INT uval;
 
   switch (code)
@@ -15310,7 +14675,7 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'D':
       /* Like 'J' but get to the GT bit only.  */
-      gcc_assert (GET_CODE (x) == REG);
+      gcc_assert (REG_P (x));
 
       /* Bit 1 is GT bit.  */
       i = 4 * (REGNO (x) - CR0_REGNO) + 1;
@@ -15430,18 +14795,18 @@ print_operand (FILE *file, rtx x, int code)
     case 'L':
       /* Write second word of DImode or DFmode reference.  Works on register
         or non-indexed memory only.  */
-      if (GET_CODE (x) == REG)
+      if (REG_P (x))
        fputs (reg_names[REGNO (x) + 1], file);
-      else if (GET_CODE (x) == MEM)
+      else if (MEM_P (x))
        {
          /* Handle possible auto-increment.  Since it is pre-increment and
             we have already done it, we can just use an offset of word.  */
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0),
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0),
                                           UNITS_PER_WORD));
          else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0),
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0),
                                           UNITS_PER_WORD));
          else
            output_address (XEXP (adjust_address_nv (x, SImode,
@@ -15601,7 +14966,7 @@ print_operand (FILE *file, rtx x, int code)
 
     case 't':
       /* Like 'J' but get to the OVERFLOW/UNORDERED bit.  */
-      gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == CCmode);
+      gcc_assert (REG_P (x) && GET_MODE (x) == CCmode);
 
       /* Bit 3 is OV bit.  */
       i = 4 * (REGNO (x) - CR0_REGNO) + 3;
@@ -15616,7 +14981,7 @@ print_operand (FILE *file, rtx x, int code)
                                  && REGNO (x) != CTR_REGNO))
        output_operand_lossage ("invalid %%T value");
       else if (REGNO (x) == LR_REGNO)
-       fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
+       fputs ("lr", file);
       else
        fputs ("ctr", file);
       return;
@@ -15641,7 +15006,7 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'U':
       /* Print `u' if this has an auto-increment or auto-decrement.  */
-      if (GET_CODE (x) == MEM
+      if (MEM_P (x)
          && (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC
              || GET_CODE (XEXP (x, 0)) == PRE_MODIFY))
@@ -15699,34 +15064,17 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'W':
       /* MB value for a PowerPC64 rldic operand.  */
-      val = (GET_CODE (x) == CONST_INT
-            ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
-
-      if (val < 0)
-       i = -1;
-      else
-       for (i = 0; i < HOST_BITS_PER_WIDE_INT; i++)
-         if ((val <<= 1) < 0)
-           break;
+      i = clz_hwi (GET_CODE (x) == CONST_INT
+                  ? INTVAL (x) : CONST_DOUBLE_HIGH (x));
 
 #if HOST_BITS_PER_WIDE_INT == 32
-      if (GET_CODE (x) == CONST_INT && i >= 0)
+      if (GET_CODE (x) == CONST_INT && i > 0)
        i += 32;  /* zero-extend high-part was all 0's */
       else if (GET_CODE (x) == CONST_DOUBLE && i == 32)
-       {
-         val = CONST_DOUBLE_LOW (x);
-
-         gcc_assert (val);
-         if (val < 0)
-           --i;
-         else
-           for ( ; i < 64; i++)
-             if ((val <<= 1) < 0)
-               break;
-       }
+       i = clz_hwi (CONST_DOUBLE_LOW (x)) + 32;
 #endif
 
-      fprintf (file, "%d", i + 1);
+      fprintf (file, "%d", i);
       return;
 
     case 'x':
@@ -15750,7 +15098,7 @@ print_operand (FILE *file, rtx x, int code)
       return;
 
     case 'X':
-      if (GET_CODE (x) == MEM
+      if (MEM_P (x)
          && (legitimate_indexed_address_p (XEXP (x, 0), 0)
              || (GET_CODE (XEXP (x, 0)) == PRE_MODIFY
                  && legitimate_indexed_address_p (XEXP (XEXP (x, 0), 1), 0))))
@@ -15759,15 +15107,15 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'Y':
       /* Like 'L', for third word of TImode  */
-      if (GET_CODE (x) == REG)
+      if (REG_P (x))
        fputs (reg_names[REGNO (x) + 2], file);
-      else if (GET_CODE (x) == MEM)
+      else if (MEM_P (x))
        {
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0), 8));
          else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0), 8));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -15809,15 +15157,15 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'Z':
       /* Like 'L', for last word of TImode.  */
-      if (GET_CODE (x) == REG)
+      if (REG_P (x))
        fputs (reg_names[REGNO (x) + 3], file);
-      else if (GET_CODE (x) == MEM)
+      else if (MEM_P (x))
        {
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0), 12));
          else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
-           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
+           output_address (plus_constant (Pmode, XEXP (XEXP (x, 0), 0), 12));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -15831,7 +15179,7 @@ print_operand (FILE *file, rtx x, int code)
       {
        rtx tmp;
 
-       gcc_assert (GET_CODE (x) == MEM);
+       gcc_assert (MEM_P (x));
 
        tmp = XEXP (x, 0);
 
@@ -15842,7 +15190,7 @@ print_operand (FILE *file, rtx x, int code)
                || GET_MODE (x) == TImode))
          {
            /* Handle [reg].  */
-           if (GET_CODE (tmp) == REG)
+           if (REG_P (tmp))
              {
                fprintf (file, "0(%s)", reg_names[REGNO (tmp)]);
                break;
@@ -15853,7 +15201,7 @@ print_operand (FILE *file, rtx x, int code)
              {
                int x;
 
-               gcc_assert (GET_CODE (XEXP (tmp, 0)) == REG);
+               gcc_assert (REG_P (XEXP (tmp, 0)));
 
                x = INTVAL (XEXP (tmp, 1));
                fprintf (file, "%d(%s)", x, reg_names[REGNO (XEXP (tmp, 0))]);
@@ -15870,7 +15218,7 @@ print_operand (FILE *file, rtx x, int code)
        else if (VECTOR_MEM_VSX_P (GET_MODE (x))
                 && GET_CODE (tmp) == PRE_MODIFY)
          tmp = XEXP (tmp, 1);
-       if (GET_CODE (tmp) == REG)
+       if (REG_P (tmp))
          fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
        else
          {
@@ -15893,9 +15241,9 @@ print_operand (FILE *file, rtx x, int code)
       }
 
     case 0:
-      if (GET_CODE (x) == REG)
+      if (REG_P (x))
        fprintf (file, "%s", reg_names[REGNO (x)]);
-      else if (GET_CODE (x) == MEM)
+      else if (MEM_P (x))
        {
          /* We need to handle PRE_INC and PRE_DEC here, since we need to
             know the width from the mode.  */
@@ -15912,14 +15260,14 @@ print_operand (FILE *file, rtx x, int code)
        }
       else
        {
-         if (toc_relative_expr_p (x))
+         if (toc_relative_expr_p (x, false))
            /* This hack along with a corresponding hack in
               rs6000_output_addr_const_extra arranges to output addends
               where the assembler expects to find them.  eg.
-              (const (plus (unspec [symbol_ref ("x") tocrel]) 4))
+              (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 4)
               without this hack would be output as "x@toc+4".  We
               want "x+4@toc".  */
-           output_addr_const (file, tocrel_base);
+           output_addr_const (file, CONST_CAST_RTX (tocrel_base));
          else
            output_addr_const (file, x);
        }
@@ -15939,7 +15287,7 @@ print_operand (FILE *file, rtx x, int code)
 void
 print_operand_address (FILE *file, rtx x)
 {
-  if (GET_CODE (x) == REG)
+  if (REG_P (x))
     fprintf (file, "0(%s)", reg_names[ REGNO (x) ]);
   else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST
           || GET_CODE (x) == LABEL_REF)
@@ -15951,9 +15299,9 @@ print_operand_address (FILE *file, rtx x)
       else
        gcc_assert (!TARGET_TOC);
     }
-  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
+  else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
+          && REG_P (XEXP (x, 1)))
     {
-      gcc_assert (REG_P (XEXP (x, 0)));
       if (REGNO (XEXP (x, 0)) == 0)
        fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
                 reg_names[ REGNO (XEXP (x, 0)) ]);
@@ -15961,11 +15309,12 @@ print_operand_address (FILE *file, rtx x)
        fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 0)) ],
                 reg_names[ REGNO (XEXP (x, 1)) ]);
     }
-  else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+  else if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0))
+          && GET_CODE (XEXP (x, 1)) == CONST_INT)
     fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%s)",
             INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
 #if TARGET_MACHO
-  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
+  else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0))
           && CONSTANT_P (XEXP (x, 1)))
     {
       fprintf (file, "lo16(");
@@ -15973,29 +15322,29 @@ print_operand_address (FILE *file, rtx x)
       fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
     }
 #endif
-  else if (legitimate_constant_pool_address_p (x, QImode, true))
+#if TARGET_ELF
+  else if (GET_CODE (x) == LO_SUM && REG_P (XEXP (x, 0))
+          && CONSTANT_P (XEXP (x, 1)))
+    {
+      output_addr_const (file, XEXP (x, 1));
+      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+    }
+#endif
+  else if (toc_relative_expr_p (x, false))
     {
       /* This hack along with a corresponding hack in
         rs6000_output_addr_const_extra arranges to output addends
         where the assembler expects to find them.  eg.
         (lo_sum (reg 9)
-        .       (const (plus (unspec [symbol_ref ("x") tocrel]) 8)))
+        .       (plus (unspec [(symbol_ref ("x")) (reg 2)] tocrel) 8))
         without this hack would be output as "x@toc+8@l(9)".  We
         want "x+8@toc@l(9)".  */
-      output_addr_const (file, tocrel_base);
+      output_addr_const (file, CONST_CAST_RTX (tocrel_base));
       if (GET_CODE (x) == LO_SUM)
-       fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+       fprintf (file, "@l(%s)", reg_names[REGNO (XEXP (x, 0))]);
       else
-       fprintf (file, "(%s)", reg_names[REGNO (XEXP (x, 0))]);
-    }
-#if TARGET_ELF
-  else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
-          && CONSTANT_P (XEXP (x, 1)))
-    {
-      output_addr_const (file, XEXP (x, 1));
-      fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
+       fprintf (file, "(%s)", reg_names[REGNO (XVECEXP (tocrel_base, 0, 1))]);
     }
-#endif
   else
     gcc_unreachable ();
 }
@@ -16009,13 +15358,15 @@ rs6000_output_addr_const_extra (FILE *file, rtx x)
     switch (XINT (x, 1))
       {
       case UNSPEC_TOCREL:
-       gcc_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF);
+       gcc_checking_assert (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF
+                            && REG_P (XVECEXP (x, 0, 1))
+                            && REGNO (XVECEXP (x, 0, 1)) == TOC_REGISTER);
        output_addr_const (file, XVECEXP (x, 0, 0));
        if (x == tocrel_base && tocrel_offset != const0_rtx)
          {
            if (INTVAL (tocrel_offset) >= 0)
              fprintf (file, "+");
-           output_addr_const (file, tocrel_offset);
+           output_addr_const (file, CONST_CAST_RTX (tocrel_offset));
          }
        if (!TARGET_AIX || (TARGET_ELF && TARGET_MINIMAL_TOC))
          {
@@ -16051,12 +15402,13 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
     {
       static int recurse = 0;
 
-      /* For -mrelocatable, we mark all addresses that need to be fixed up
-        in the .fixup section.  */
+      /* For -mrelocatable, we mark all addresses that need to be fixed up in
+        the .fixup section.  Since the TOC section is already relocated, we
+        don't need to mark it here.  We used to skip the text section, but it
+        should never be valid for relocated addresses to be placed in the text
+        section.  */
       if (TARGET_RELOCATABLE
          && in_section != toc_section
-         && in_section != text_section
-         && !unlikely_text_section_p (in_section)
          && !recurse
          && GET_CODE (x) != CONST_INT
          && GET_CODE (x) != CONST_DOUBLE
@@ -16098,7 +15450,7 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
-#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
+#if defined (HAVE_GAS_HIDDEN) && !TARGET_MACHO
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
 
@@ -16161,18 +15513,25 @@ rs6000_generate_compare (rtx cmp, enum machine_mode mode)
           || code == GEU || code == LEU)
     comp_mode = CCUNSmode;
   else if ((code == EQ || code == NE)
-          && GET_CODE (op0) == SUBREG
-          && GET_CODE (op1) == SUBREG
-          && SUBREG_PROMOTED_UNSIGNED_P (op0)
-          && SUBREG_PROMOTED_UNSIGNED_P (op1))
+          && unsigned_reg_p (op0)
+          && (unsigned_reg_p (op1)
+              || (CONST_INT_P (op1) && INTVAL (op1) != 0)))
     /* These are unsigned values, perhaps there will be a later
-       ordering compare that can be shared with this one.
-       Unfortunately we cannot detect the signedness of the operands
-       for non-subregs.  */
+       ordering compare that can be shared with this one.  */
     comp_mode = CCUNSmode;
   else
     comp_mode = CCmode;
 
+  /* If we have an unsigned compare, make sure we don't have a signed value as
+     an immediate.  */
+  if (comp_mode == CCUNSmode && GET_CODE (op1) == CONST_INT
+      && INTVAL (op1) < 0)
+    {
+      op0 = copy_rtx_if_shared (op0);
+      op1 = force_reg (GET_MODE (op0), op1);
+      cmp = gen_rtx_fmt_ee (code, GET_MODE (cmp), op0, op1);
+    }
+
   /* First, the compare.  */
   compare_result = gen_reg_rtx (comp_mode);
 
@@ -16587,8 +15946,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
       gcc_unreachable ();
     }
 
-  /* Maybe we have a guess as to how likely the branch is.
-     The old mnemonics don't have a way to specify this information.  */
+  /* Maybe we have a guess as to how likely the branch is.  */
   pred = "";
   note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
   if (note != NULL_RTX)
@@ -16615,9 +15973,9 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
     }
 
   if (label == NULL)
-    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
+    s += sprintf (s, "b%slr%s ", ccode, pred);
   else
-    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
+    s += sprintf (s, "b%s%s ", ccode, pred);
 
   /* We need to escape any '%' characters in the reg_names string.
      Assume they'd only be the first character....  */
@@ -16676,6 +16034,10 @@ rs6000_emit_vector_compare_inner (enum rtx_code code, rtx op0, rtx op1)
     case EQ:
     case GT:
     case GTU:
+    case ORDERED:
+    case UNORDERED:
+    case UNEQ:
+    case LTGT:
       mask = gen_reg_rtx (mode);
       emit_insn (gen_rtx_SET (VOIDmode,
                              mask,
@@ -16828,6 +16190,7 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false,
                              rtx cond, rtx cc_op0, rtx cc_op1)
 {
   enum machine_mode dest_mode = GET_MODE (dest);
+  enum machine_mode mask_mode = GET_MODE (cc_op0);
   enum rtx_code rcode = GET_CODE (cond);
   enum machine_mode cc_mode = CCmode;
   rtx mask;
@@ -16838,6 +16201,9 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false,
   if (VECTOR_UNIT_NONE_P (dest_mode))
     return 0;
 
+  gcc_assert (GET_MODE_SIZE (dest_mode) == GET_MODE_SIZE (mask_mode)
+             && GET_MODE_NUNITS (dest_mode) == GET_MODE_NUNITS (mask_mode));
+
   switch (rcode)
     {
       /* Swap operands if we can, and fall back to doing the operation as
@@ -16868,7 +16234,7 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false,
     }
 
   /* Get the vector mask for the given relational operations.  */
-  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode);
+  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, mask_mode);
 
   if (!mask)
     return 0;
@@ -16880,7 +16246,8 @@ rs6000_emit_vector_cond_expr (rtx dest, rtx op_true, rtx op_false,
       op_false = tmp;
     }
 
-  cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, CONST0_RTX (dest_mode));
+  cond2 = gen_rtx_fmt_ee (NE, cc_mode, gen_lowpart (dest_mode, mask),
+                         CONST0_RTX (dest_mode));
   emit_insn (gen_rtx_SET (VOIDmode,
                          dest,
                          gen_rtx_IF_THEN_ELSE (dest_mode,
@@ -16917,6 +16284,11 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
   if (GET_MODE (false_cond) != result_mode)
     return 0;
 
+  /* Don't allow using floating point comparisons for integer results for
+     now.  */
+  if (FLOAT_MODE_P (compare_mode) && !FLOAT_MODE_P (result_mode))
+    return 0;
+
   /* First, work out if the hardware can do this at all, or
      if it's too slow....  */
   if (!FLOAT_MODE_P (compare_mode))
@@ -17180,199 +16552,6 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
     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_lwsync ());
-
-    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);
-         used_m = change_address (used_m, SImode, 0);
-       }
-      else
-       {
-         rtx addrSI, aligned_addr;
-         int shift_mask = mode == QImode ? 0x18 : 0x10;
-
-         addrSI = gen_lowpart_common (SImode,
-                                      force_reg (Pmode, XEXP (used_m, 0)));
-         addrSI = force_reg (SImode, addrSI);
-         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.  */
-      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 NOT: /* NAND */
-         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 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 ();
-       }
-
-      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)
-      && 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 if (code == NOT)
-    the_op = gen_rtx_fmt_ee (IOR, used_mode,
-                            gen_rtx_NOT (used_mode, m),
-                            gen_rtx_NOT (used_mode, op));
-  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.  */
 
@@ -17394,10 +16573,18 @@ 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;
+
+  switch (mode)
+    {
+    case SImode:
+      fn = gen_load_lockedsi;
+      break;
+    case DImode:
+      fn = gen_load_lockeddi;
+      break;
+    default:
+      gcc_unreachable ();
+    }
   emit_insn (fn (reg, mem));
 }
 
@@ -17408,228 +16595,430 @@ 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;
+
+  switch (mode)
+    {
+    case SImode:
+      fn = gen_store_conditionalsi;
+      break;
+    case DImode:
+      fn = gen_store_conditionaldi;
+      break;
+    default:
+      gcc_unreachable ();
+    }
 
   /* Emit sync before stwcx. to address PPC405 Erratum.  */
   if (PPC405_ERRATUM77)
-    emit_insn (gen_memory_barrier ());
+    emit_insn (gen_hwsync ());
 
   emit_insn (fn (res, mem, val));
 }
 
-/* Expand 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.  */
+/* Expand barriers before and after a load_locked/store_cond sequence.  */
 
-void
-rs6000_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
-                       rtx before, rtx after, rtx scratch)
+static rtx
+rs6000_pre_atomic_barrier (rtx mem, enum memmodel model)
 {
-  enum machine_mode mode = GET_MODE (mem);
-  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
+  rtx addr = XEXP (mem, 0);
+  int strict_p = (reload_in_progress || reload_completed);
 
-  emit_insn (gen_lwsync ());
+  if (!legitimate_indirect_address_p (addr, strict_p)
+      && !legitimate_indexed_address_p (addr, strict_p))
+    {
+      addr = force_reg (Pmode, addr);
+      mem = replace_equiv_address_nv (mem, addr);
+    }
 
-  label = gen_label_rtx ();
-  emit_label (label);
-  label = gen_rtx_LABEL_REF (VOIDmode, label);
+  switch (model)
+    {
+    case MEMMODEL_RELAXED:
+    case MEMMODEL_CONSUME:
+    case MEMMODEL_ACQUIRE:
+      break;
+    case MEMMODEL_RELEASE:
+    case MEMMODEL_ACQ_REL:
+      emit_insn (gen_lwsync ());
+      break;
+    case MEMMODEL_SEQ_CST:
+      emit_insn (gen_hwsync ());
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  return mem;
+}
 
-  if (before == NULL_RTX)
-    before = scratch;
-  emit_load_locked (mode, before, mem);
+static void
+rs6000_post_atomic_barrier (enum memmodel model)
+{
+  switch (model)
+    {
+    case MEMMODEL_RELAXED:
+    case MEMMODEL_CONSUME:
+    case MEMMODEL_RELEASE:
+      break;
+    case MEMMODEL_ACQUIRE:
+    case MEMMODEL_ACQ_REL:
+    case MEMMODEL_SEQ_CST:
+      emit_insn (gen_isync ());
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
 
-  if (code == NOT)
-    x = gen_rtx_IOR (mode,
-                    gen_rtx_NOT (mode, before),
-                    gen_rtx_NOT (mode, val));
-  else if (code == AND)
-    x = gen_rtx_UNSPEC (mode, gen_rtvec (2, before, val), UNSPEC_AND);
-  else
-    x = gen_rtx_fmt_ee (code, mode, before, val);
+/* A subroutine of the various atomic expanders.  For sub-word operations,
+   we must adjust things to operate on SImode.  Given the original MEM,
+   return a new aligned memory.  Also build and return the quantities by
+   which to shift and mask.  */
 
-  if (after != NULL_RTX)
-    emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
-  emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+static rtx
+rs6000_adjust_atomic_subword (rtx orig_mem, rtx *pshift, rtx *pmask)
+{
+  rtx addr, align, shift, mask, mem;
+  HOST_WIDE_INT shift_mask;
+  enum machine_mode mode = GET_MODE (orig_mem);
 
-  emit_store_conditional (mode, cond, mem, scratch);
+  /* For smaller modes, we have to implement this via SImode.  */
+  shift_mask = (mode == QImode ? 0x18 : 0x10);
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label);
+  addr = XEXP (orig_mem, 0);
+  addr = force_reg (GET_MODE (addr), addr);
 
-  emit_insn (gen_isync ());
-}
+  /* Aligned memory containing subword.  Generate a new memory.  We
+     do not want any of the existing MEM_ATTR data, as we're now
+     accessing memory outside the original object.  */
+  align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-4),
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+  mem = gen_rtx_MEM (SImode, align);
+  MEM_VOLATILE_P (mem) = MEM_VOLATILE_P (orig_mem);
+  if (MEM_ALIAS_SET (orig_mem) == ALIAS_SET_MEMORY_BARRIER)
+    set_mem_alias_set (mem, ALIAS_SET_MEMORY_BARRIER);
 
-/* 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.  */
+  /* Shift amount for subword relative to aligned word.  */
+  shift = gen_reg_rtx (SImode);
+  addr = gen_lowpart (SImode, addr);
+  emit_insn (gen_rlwinm (shift, addr, GEN_INT (3), GEN_INT (shift_mask)));
+  shift = expand_simple_binop (SImode, XOR, shift, GEN_INT (shift_mask),
+                              shift, 1, OPTAB_LIB_WIDEN);
+  *pshift = shift;
 
-void
-rs6000_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
-                              rtx scratch)
-{
-  enum machine_mode mode = GET_MODE (mem);
-  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
+  /* Mask for insertion.  */
+  mask = expand_simple_binop (SImode, ASHIFT, GEN_INT (GET_MODE_MASK (mode)),
+                             shift, NULL_RTX, 1, OPTAB_LIB_WIDEN);
+  *pmask = mask;
 
-  emit_insn (gen_lwsync ());
+  return mem;
+}
 
-  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
-  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
-  emit_label (XEXP (label1, 0));
+/* A subroutine of the various atomic expanders.  For sub-word operands,
+   combine OLDVAL and NEWVAL via MASK.  Returns a new pseduo.  */
 
-  emit_load_locked (mode, retval, mem);
+static rtx
+rs6000_mask_atomic_subword (rtx oldval, rtx newval, rtx mask)
+{
+  rtx x;
 
-  x = gen_rtx_COMPARE (CCmode, retval, oldval);
-  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+  x = gen_reg_rtx (SImode);
+  emit_insn (gen_rtx_SET (VOIDmode, x,
+                         gen_rtx_AND (SImode,
+                                      gen_rtx_NOT (SImode, mask),
+                                      oldval)));
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label2);
+  x = expand_simple_binop (SImode, IOR, newval, x, x, 1, OPTAB_LIB_WIDEN);
 
-  emit_move_insn (scratch, newval);
-  emit_store_conditional (mode, cond, mem, scratch);
+  return x;
+}
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label1);
+/* A subroutine of the various atomic expanders.  For sub-word operands,
+   extract WIDE to NARROW via SHIFT.  */
 
-  emit_insn (gen_isync ());
-  emit_label (XEXP (label2, 0));
+static void
+rs6000_finish_atomic_subword (rtx narrow, rtx wide, rtx shift)
+{
+  wide = expand_simple_binop (SImode, LSHIFTRT, wide, shift,
+                             wide, 1, OPTAB_LIB_WIDEN);
+  emit_move_insn (narrow, gen_lowpart (GET_MODE (narrow), wide));
 }
 
-/* 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.  */
+/* Expand an atomic compare and swap operation.  */
 
 void
-rs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
+rs6000_expand_atomic_compare_and_swap (rtx operands[])
 {
-  enum machine_mode mode = GET_MODE (mem);
-  rtx label, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
+  rtx boolval, retval, mem, oldval, newval, cond;
+  rtx label1, label2, x, mask, shift;
+  enum machine_mode mode;
+  enum memmodel mod_s, mod_f;
+  bool is_weak;
+
+  boolval = operands[0];
+  retval = operands[1];
+  mem = operands[2];
+  oldval = operands[3];
+  newval = operands[4];
+  is_weak = (INTVAL (operands[5]) != 0);
+  mod_s = (enum memmodel) INTVAL (operands[6]);
+  mod_f = (enum memmodel) INTVAL (operands[7]);
+  mode = GET_MODE (mem);
+
+  mask = shift = NULL_RTX;
+  if (mode == QImode || mode == HImode)
+    {
+      mem = rs6000_adjust_atomic_subword (mem, &shift, &mask);
 
-  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
-  emit_label (XEXP (label, 0));
+      /* Shift and mask OLDVAL into position with the word.  */
+      oldval = convert_modes (SImode, mode, oldval, 1);
+      oldval = expand_simple_binop (SImode, ASHIFT, oldval, shift,
+                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+      /* Shift and mask NEWVAL into position within the word.  */
+      newval = convert_modes (SImode, mode, newval, 1);
+      newval = expand_simple_binop (SImode, ASHIFT, newval, shift,
+                                   NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+      /* Prepare to adjust the return value.  */
+      retval = gen_reg_rtx (SImode);
+      mode = SImode;
+    }
+  else if (reg_overlap_mentioned_p (retval, oldval))
+    oldval = copy_to_reg (oldval);
+
+  mem = rs6000_pre_atomic_barrier (mem, mod_s);
+
+  label1 = NULL_RTX;
+  if (!is_weak)
+    {
+      label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+      emit_label (XEXP (label1, 0));
+    }
+  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
 
   emit_load_locked (mode, retval, mem);
-  emit_move_insn (scratch, val);
-  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = retval;
+  if (mask)
+    {
+      x = expand_simple_binop (SImode, AND, retval, mask,
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+    }
+
+  cond = gen_reg_rtx (CCmode);
+  x = gen_rtx_COMPARE (CCmode, x, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
 
   x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label);
+  emit_unlikely_jump (x, label2);
 
-  emit_insn (gen_isync ());
-}
+  x = newval;
+  if (mask)
+    x = rs6000_mask_atomic_subword (retval, newval, mask);
 
-void
-rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
-{
-  enum machine_mode mode = GET_MODE (mem);
-  rtx addrSI, align, wdst, shift, mask;
-  HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10;
-  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
+  emit_store_conditional (mode, cond, mem, x);
 
-  /* Shift amount for subword relative to aligned word.  */
-  addrSI = force_reg (GET_MODE (XEXP (mem, 0)), XEXP (mem, 0));
-  addrSI = force_reg (SImode, gen_lowpart_common (SImode, addrSI));
-  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)));
-
-  /* Shift and mask old value into position within word.  */
-  oldval = convert_modes (SImode, mode, oldval, 1);
-  oldval = expand_binop (SImode, and_optab,
-                        oldval, GEN_INT (imask), NULL_RTX,
-                        1, OPTAB_LIB_WIDEN);
-  emit_insn (gen_ashlsi3 (oldval, oldval, shift));
-
-  /* Shift and mask new value into position within word.  */
-  newval = convert_modes (SImode, mode, newval, 1);
-  newval = expand_binop (SImode, and_optab,
-                        newval, GEN_INT (imask), NULL_RTX,
-                        1, OPTAB_LIB_WIDEN);
-  emit_insn (gen_ashlsi3 (newval, newval, shift));
+  if (!is_weak)
+    {
+      x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+      emit_unlikely_jump (x, label1);
+    }
 
-  /* Mask for insertion.  */
-  mask = gen_reg_rtx (SImode);
-  emit_move_insn (mask, GEN_INT (imask));
-  emit_insn (gen_ashlsi3 (mask, mask, shift));
+  if (mod_f != MEMMODEL_RELAXED)
+    emit_label (XEXP (label2, 0));
 
-  /* Address of aligned word containing subword.  */
-  align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4),
-                       NULL_RTX, 1, OPTAB_LIB_WIDEN);
-  mem = change_address (mem, SImode, align);
-  set_mem_align (mem, 32);
-  MEM_VOLATILE_P (mem) = 1;
+  rs6000_post_atomic_barrier (mod_s);
 
-  wdst = gen_reg_rtx (SImode);
-  emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
-                                                   oldval, newval, mem));
+  if (mod_f == MEMMODEL_RELAXED)
+    emit_label (XEXP (label2, 0));
 
-  /* Shift the result back.  */
-  emit_insn (gen_lshrsi3 (wdst, wdst, shift));
+  if (shift)
+    rs6000_finish_atomic_subword (operands[1], retval, shift);
 
-  emit_move_insn (dst, gen_lowpart (mode, wdst));
+  /* In all cases, CR0 contains EQ on success, and NE on failure.  */
+  x = gen_rtx_EQ (SImode, cond, const0_rtx);
+  emit_insn (gen_rtx_SET (VOIDmode, boolval, x));
 }
 
+/* Expand an atomic exchange operation.  */
+
 void
-rs6000_split_compare_and_swapqhi (rtx dest, rtx mask,
-                                 rtx oldval, rtx newval, rtx mem,
-                                 rtx scratch)
+rs6000_expand_atomic_exchange (rtx operands[])
 {
-  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
+  rtx retval, mem, val, cond;
+  enum machine_mode mode;
+  enum memmodel model;
+  rtx label, x, mask, shift;
 
-  emit_insn (gen_lwsync ());
-  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
-  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
-  emit_label (XEXP (label1, 0));
+  retval = operands[0];
+  mem = operands[1];
+  val = operands[2];
+  model = (enum memmodel) INTVAL (operands[3]);
+  mode = GET_MODE (mem);
 
-  emit_load_locked (SImode, scratch, mem);
+  mask = shift = NULL_RTX;
+  if (mode == QImode || mode == HImode)
+    {
+      mem = rs6000_adjust_atomic_subword (mem, &shift, &mask);
 
-  /* Mask subword within loaded value for comparison with oldval.
-     Use UNSPEC_AND to avoid clobber.*/
-  emit_insn (gen_rtx_SET (SImode, dest,
-                         gen_rtx_UNSPEC (SImode,
-                                         gen_rtvec (2, scratch, mask),
-                                         UNSPEC_AND)));
+      /* Shift and mask VAL into position with the word.  */
+      val = convert_modes (SImode, mode, val, 1);
+      val = expand_simple_binop (SImode, ASHIFT, val, shift,
+                                NULL_RTX, 1, OPTAB_LIB_WIDEN);
 
-  x = gen_rtx_COMPARE (CCmode, dest, oldval);
-  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+      /* Prepare to adjust the return value.  */
+      retval = gen_reg_rtx (SImode);
+      mode = SImode;
+    }
 
-  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label2);
+  mem = rs6000_pre_atomic_barrier (mem, model);
 
-  /* Clear subword within loaded value for insertion of new value.  */
-  emit_insn (gen_rtx_SET (SImode, scratch,
-                         gen_rtx_AND (SImode,
-                                      gen_rtx_NOT (SImode, mask), scratch)));
-  emit_insn (gen_iorsi3 (scratch, scratch, newval));
-  emit_store_conditional (SImode, cond, mem, scratch);
+  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  emit_label (XEXP (label, 0));
+
+  emit_load_locked (mode, retval, mem);
+
+  x = val;
+  if (mask)
+    x = rs6000_mask_atomic_subword (retval, val, mask);
+
+  cond = gen_reg_rtx (CCmode);
+  emit_store_conditional (mode, cond, mem, x);
 
   x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
-  emit_unlikely_jump (x, label1);
+  emit_unlikely_jump (x, label);
 
-  emit_insn (gen_isync ());
-  emit_label (XEXP (label2, 0));
-}
+  rs6000_post_atomic_barrier (model);
 
+  if (shift)
+    rs6000_finish_atomic_subword (operands[0], retval, shift);
+}
 
-  /* 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
-   register.  */
+/* Expand 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.  MODEL_RTX
+   is a CONST_INT containing the memory model to use.  */
 
 void
-rs6000_split_multireg_move (rtx dst, rtx src)
+rs6000_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
+                        rtx orig_before, rtx orig_after, rtx model_rtx)
 {
-  /* The register number of the first register being moved.  */
-  int reg;
-  /* The mode that is to be moved.  */
-  enum machine_mode mode;
-  /* The mode that the move is being done in, and its size.  */
-  enum machine_mode reg_mode;
+  enum memmodel model = (enum memmodel) INTVAL (model_rtx);
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label, x, cond, mask, shift;
+  rtx before = orig_before, after = orig_after;
+
+  mask = shift = NULL_RTX;
+  if (mode == QImode || mode == HImode)
+    {
+      mem = rs6000_adjust_atomic_subword (mem, &shift, &mask);
+
+      /* Shift and mask VAL into position with the word.  */
+      val = convert_modes (SImode, mode, val, 1);
+      val = expand_simple_binop (SImode, ASHIFT, val, shift,
+                                NULL_RTX, 1, OPTAB_LIB_WIDEN);
+
+      switch (code)
+       {
+       case IOR:
+       case XOR:
+         /* We've already zero-extended VAL.  That is sufficient to
+            make certain that it does not affect other bits.  */
+         mask = NULL;
+         break;
+
+       case AND:
+         /* If we make certain that all of the other bits in VAL are
+            set, that will be sufficient to not affect other bits.  */
+         x = gen_rtx_NOT (SImode, mask);
+         x = gen_rtx_IOR (SImode, x, val);
+         emit_insn (gen_rtx_SET (VOIDmode, val, x));
+         mask = NULL;
+         break;
+
+       case NOT:
+       case PLUS:
+       case MINUS:
+         /* These will all affect bits outside the field and need
+            adjustment via MASK within the loop.  */
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+
+      /* Prepare to adjust the return value.  */
+      before = gen_reg_rtx (SImode);
+      if (after)
+       after = gen_reg_rtx (SImode);
+      mode = SImode;
+    }
+
+  mem = rs6000_pre_atomic_barrier (mem, model);
+
+  label = gen_label_rtx ();
+  emit_label (label);
+  label = gen_rtx_LABEL_REF (VOIDmode, label);
+
+  if (before == NULL_RTX)
+    before = gen_reg_rtx (mode);
+
+  emit_load_locked (mode, before, mem);
+
+  if (code == NOT)
+    {
+      x = expand_simple_binop (mode, AND, before, val,
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+      after = expand_simple_unop (mode, NOT, x, after, 1);
+    }
+  else
+    {
+      after = expand_simple_binop (mode, code, before, val,
+                                  after, 1, OPTAB_LIB_WIDEN);
+    }
+
+  x = after;
+  if (mask)
+    {
+      x = expand_simple_binop (SImode, AND, after, mask,
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+      x = rs6000_mask_atomic_subword (before, x, mask);
+    }
+
+  cond = gen_reg_rtx (CCmode);
+  emit_store_conditional (mode, cond, mem, x);
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label);
+
+  rs6000_post_atomic_barrier (model);
+
+  if (shift)
+    {
+      if (orig_before)
+       rs6000_finish_atomic_subword (orig_before, before, shift);
+      if (orig_after)
+       rs6000_finish_atomic_subword (orig_after, after, shift);
+    }
+  else if (orig_after && after != orig_after)
+    emit_move_insn (orig_after, after);
+}
+
+/* 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
+   register.  */
+
+void
+rs6000_split_multireg_move (rtx dst, rtx src)
+{
+  /* The register number of the first register being moved.  */
+  int reg;
+  /* The mode that is to be moved.  */
+  enum machine_mode mode;
+  /* The mode that the move is being done in, and its size.  */
+  enum machine_mode reg_mode;
   int reg_mode_size;
   /* The number of registers that will be moved.  */
   int nregs;
@@ -17684,7 +17073,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              emit_insn (gen_add3_insn (breg, breg, delta_rtx));
              src = replace_equiv_address (src, breg);
            }
-         else if (! rs6000_offsettable_memref_p (src))
+         else if (! rs6000_offsettable_memref_p (src, reg_mode))
            {
              if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY)
                {
@@ -17750,7 +17139,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                emit_insn (gen_add3_insn (breg, breg, delta_rtx));
              dst = replace_equiv_address (dst, breg);
            }
-         else if (!rs6000_offsettable_memref_p (dst)
+         else if (!rs6000_offsettable_memref_p (dst, reg_mode)
                   && GET_CODE (XEXP (dst, 0)) != LO_SUM)
            {
              if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY)
@@ -17788,7 +17177,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                }
            }
          else if (GET_CODE (XEXP (dst, 0)) != LO_SUM)
-           gcc_assert (rs6000_offsettable_memref_p (dst));
+           gcc_assert (rs6000_offsettable_memref_p (dst, reg_mode));
        }
 
       for (i = 0; i < nregs; i++)
@@ -17818,6 +17207,12 @@ rs6000_split_multireg_move (rtx dst, rtx src)
 /* This page contains routines that are used to determine what the
    function prologue and epilogue code will do and write them out.  */
 
+static inline bool
+save_reg_p (int r)
+{
+  return !call_used_regs[r] && df_regs_ever_live_p (r);
+}
+
 /* Return the first fixed-point register that is required to be
    saved. 32 if none.  */
 
@@ -17828,14 +17223,16 @@ first_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 13; first_reg <= 31; first_reg++)
-    if (df_regs_ever_live_p (first_reg)
-       && (! call_used_regs[first_reg]
-           || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
-                   || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
+    if (save_reg_p (first_reg))
       break;
 
+  if (first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM
+      && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
+         || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
+         || (TARGET_TOC && TARGET_MINIMAL_TOC))
+      && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))
+    first_reg = RS6000_PIC_OFFSET_TABLE_REGNUM;
+
 #if TARGET_MACHO
   if (flag_pic
       && crtl->uses_pic_offset_table
@@ -17855,7 +17252,7 @@ first_fp_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
-    if (df_regs_ever_live_p (first_reg))
+    if (save_reg_p (first_reg))
       break;
 
   return first_reg;
@@ -17881,7 +17278,7 @@ first_altivec_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (df_regs_ever_live_p (i))
+    if (save_reg_p (i))
       break;
 
   return i;
@@ -17941,7 +17338,7 @@ compute_save_world_info (rs6000_stack_t *info_ptr)
   info_ptr->world_save_p
     = (WORLD_SAVE_P (info_ptr)
        && DEFAULT_ABI == ABI_DARWIN
-       && ! (cfun->calls_setjmp && flag_exceptions)
+       && !cfun->has_nonlocal_label
        && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
        && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
        && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
@@ -17995,6 +17392,21 @@ is_altivec_return_reg (rtx reg, void *xyes)
 }
 
 \f
+/* Look for user-defined global regs in the range FIRST to LAST-1.
+   We should not restore these, and so cannot use lmw or out-of-line
+   restore functions if there are any.  We also can't save them
+   (well, emit frame notes for them), because frame unwinding during
+   exception handling will restore saved registers.  */
+
+static bool
+global_regs_p (unsigned first, unsigned last)
+{
+  while (first < last)
+    if (global_regs[first++])
+      return true;
+  return false;
+}
+
 /* Determine the strategy for savings/restoring registers.  */
 
 enum {
@@ -18005,7 +17417,9 @@ enum {
   REST_INLINE_GPRS = 0x10,
   SAVE_NOINLINE_GPRS_SAVES_LR = 0x20,
   SAVE_NOINLINE_FPRS_SAVES_LR = 0x40,
-  REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80
+  REST_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x80,
+  SAVE_INLINE_VRS = 0x100,
+  REST_INLINE_VRS = 0x200
 };
 
 static int
@@ -18013,39 +17427,102 @@ rs6000_savres_strategy (rs6000_stack_t *info,
                        bool using_static_chain_p)
 {
   int strategy = 0;
+  bool lr_save_p;
 
   if (TARGET_MULTIPLE
       && !TARGET_POWERPC64
       && !(TARGET_SPE_ABI && info->spe_64bit_regs_used)
       && info->first_gp_reg_save < 31
-      && no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true))
+      && !global_regs_p (info->first_gp_reg_save, 32))
     strategy |= SAVRES_MULTIPLE;
 
   if (crtl->calls_eh_return
-      || cfun->machine->ra_need_lr
-      || info->total_size > 32767)
+      || cfun->machine->ra_need_lr)
     strategy |= (SAVE_INLINE_FPRS | REST_INLINE_FPRS
-                | SAVE_INLINE_GPRS | REST_INLINE_GPRS);
+                | SAVE_INLINE_GPRS | REST_INLINE_GPRS
+                | SAVE_INLINE_VRS | REST_INLINE_VRS);
 
   if (info->first_fp_reg_save == 64
-      || FP_SAVE_INLINE (info->first_fp_reg_save)
       /* The out-of-line FP routines use double-precision stores;
         we can't use those routines if we don't have such stores.  */
       || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT)
-      || !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false))
+      || global_regs_p (info->first_fp_reg_save, 64))
     strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
 
   if (info->first_gp_reg_save == 32
-      || GP_SAVE_INLINE (info->first_gp_reg_save)
-      || !((strategy & SAVRES_MULTIPLE)
-          || no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true)))
+      || (!(strategy & SAVRES_MULTIPLE)
+         && global_regs_p (info->first_gp_reg_save, 32)))
     strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
 
+  if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO + 1
+      || global_regs_p (info->first_altivec_reg_save, LAST_ALTIVEC_REGNO + 1))
+    strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+
+  /* Define cutoff for using out-of-line functions to save registers.  */
+  if (DEFAULT_ABI == ABI_V4 || TARGET_ELF)
+    {
+      if (!optimize_size)
+       {
+         strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+         strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
+         strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+       }
+      else
+       {
+         /* Prefer out-of-line restore if it will exit.  */
+         if (info->first_fp_reg_save > 61)
+           strategy |= SAVE_INLINE_FPRS;
+         if (info->first_gp_reg_save > 29)
+           {
+             if (info->first_fp_reg_save == 64)
+               strategy |= SAVE_INLINE_GPRS;
+             else
+               strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
+           }
+         if (info->first_altivec_reg_save == LAST_ALTIVEC_REGNO)
+           strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+       }
+    }
+  else if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      if (info->first_fp_reg_save > 60)
+       strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+      if (info->first_gp_reg_save > 29)
+       strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
+      strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+    }
+  else
+    {
+      gcc_checking_assert (DEFAULT_ABI == ABI_AIX);
+      if (info->first_fp_reg_save > 61)
+       strategy |= SAVE_INLINE_FPRS | REST_INLINE_FPRS;
+      strategy |= SAVE_INLINE_GPRS | REST_INLINE_GPRS;
+      strategy |= SAVE_INLINE_VRS | REST_INLINE_VRS;
+    }
+
   /* Don't bother to try to save things out-of-line if r11 is occupied
      by the static chain.  It would require too much fiddling and the
-     static chain is rarely used anyway.  */
-  if (using_static_chain_p)
-    strategy |= SAVE_INLINE_FPRS | SAVE_INLINE_GPRS;
+     static chain is rarely used anyway.  FPRs are saved w.r.t the stack
+     pointer on Darwin, and AIX uses r1 or r12.  */
+  if (using_static_chain_p && DEFAULT_ABI != ABI_AIX)
+    strategy |= ((DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
+                | SAVE_INLINE_GPRS
+                | SAVE_INLINE_VRS | REST_INLINE_VRS);
+
+  /* We can only use the out-of-line routines to restore if we've
+     saved all the registers from first_fp_reg_save in the prologue.
+     Otherwise, we risk loading garbage.  */
+  if ((strategy & (SAVE_INLINE_FPRS | REST_INLINE_FPRS)) == SAVE_INLINE_FPRS)
+    {
+      int i;
+
+      for (i = info->first_fp_reg_save; i < 64; i++)
+       if (!save_reg_p (i))
+         {
+           strategy |= REST_INLINE_FPRS;
+           break;
+         }
+    }
 
   /* If we are going to use store multiple, then don't even bother
      with the out-of-line routines, since the store-multiple
@@ -18053,6 +17530,16 @@ rs6000_savres_strategy (rs6000_stack_t *info,
   if ((strategy & SAVRES_MULTIPLE))
     strategy |= SAVE_INLINE_GPRS;
 
+  /* info->lr_save_p isn't yet set if the only reason lr needs to be
+     saved is an out-of-line save or restore.  Set up the value for
+     the next test (excluding out-of-line gpr restore).  */
+  lr_save_p = (info->lr_save_p
+              || !(strategy & SAVE_INLINE_GPRS)
+              || !(strategy & SAVE_INLINE_FPRS)
+              || !(strategy & SAVE_INLINE_VRS)
+              || !(strategy & REST_INLINE_FPRS)
+              || !(strategy & REST_INLINE_VRS));
+
   /* The situation is more complicated with load multiple.  We'd
      prefer to use the out-of-line routines for restores, since the
      "exit" out-of-line routines can handle the restore of LR and the
@@ -18062,17 +17549,10 @@ rs6000_savres_strategy (rs6000_stack_t *info,
      have saved some fprs; In those cases it is advantageous to use
      load multiple when available.  */
   if ((strategy & SAVRES_MULTIPLE)
-      && (!info->lr_save_p
+      && (!lr_save_p
          || info->first_fp_reg_save != 64))
     strategy |= REST_INLINE_GPRS;
 
-  /* We can only use load multiple or the out-of-line routines to
-     restore if we've used store multiple or out-of-line routines
-     in the prologue, i.e. if we've saved all the registers from
-     first_gp_reg_save.  Otherwise, we risk loading garbage.  */
-  if ((strategy & (SAVE_INLINE_GPRS | SAVRES_MULTIPLE)) == SAVE_INLINE_GPRS)
-    strategy |= REST_INLINE_GPRS;
-
   /* Saving CR interferes with the exit routines used on the SPE, so
      just punt here.  */
   if (TARGET_SPE_ABI
@@ -18080,8 +17560,24 @@ rs6000_savres_strategy (rs6000_stack_t *info,
       && info->cr_save_p)
     strategy |= REST_INLINE_GPRS;
 
-#ifdef POWERPC_LINUX
-  if (TARGET_64BIT)
+  /* We can only use load multiple or the out-of-line routines to
+     restore if we've used store multiple or out-of-line routines
+     in the prologue, i.e. if we've saved all the registers from
+     first_gp_reg_save.  Otherwise, we risk loading garbage.  */
+  if ((strategy & (SAVE_INLINE_GPRS | REST_INLINE_GPRS | SAVRES_MULTIPLE))
+      == SAVE_INLINE_GPRS)
+    {
+      int i;
+
+      for (i = info->first_gp_reg_save; i < 32; i++)
+       if (!save_reg_p (i))
+         {
+           strategy |= REST_INLINE_GPRS;
+           break;
+         }
+    }
+
+  if (TARGET_ELF && TARGET_64BIT)
     {
       if (!(strategy & SAVE_INLINE_FPRS))
        strategy |= SAVE_NOINLINE_FPRS_SAVES_LR;
@@ -18089,10 +17585,12 @@ rs6000_savres_strategy (rs6000_stack_t *info,
               && info->first_fp_reg_save == 64)
        strategy |= SAVE_NOINLINE_GPRS_SAVES_LR;
     }
-#else
-  if (TARGET_AIX && !(strategy & REST_INLINE_FPRS))
+  else if (TARGET_AIX && !(strategy & REST_INLINE_FPRS))
     strategy |= REST_NOINLINE_FPRS_DOESNT_RESTORE_LR;
-#endif
+
+  if (TARGET_MACHO && !(strategy & SAVE_INLINE_FPRS))
+    strategy |= SAVE_NOINLINE_FPRS_SAVES_LR;
+
   return strategy;
 }
 
@@ -18262,7 +17760,7 @@ rs6000_stack_info (void)
                                 - info_ptr->first_altivec_reg_save);
 
   /* Does this function call anything?  */
-  info_ptr->calls_p = (! current_function_is_leaf
+  info_ptr->calls_p = (! crtl->is_leaf 
                       || cfun->machine->ra_needs_full_frame);
 
   /* Determine if we need to save the condition code registers.  */
@@ -18453,8 +17951,10 @@ rs6000_stack_info (void)
 
   if (!(info_ptr->savres_strategy & SAVE_INLINE_GPRS)
       || !(info_ptr->savres_strategy & SAVE_INLINE_FPRS)
+      || !(info_ptr->savres_strategy & SAVE_INLINE_VRS)
       || !(info_ptr->savres_strategy & REST_INLINE_GPRS)
-      || !(info_ptr->savres_strategy & REST_INLINE_FPRS))
+      || !(info_ptr->savres_strategy & REST_INLINE_FPRS)
+      || !(info_ptr->savres_strategy & REST_INLINE_VRS))
     info_ptr->lr_save_p = 1;
 
   if (info_ptr->lr_save_p)
@@ -18688,6 +18188,8 @@ debug_stack_info (rs6000_stack_t *info)
   if (info->reg_size != 4)
     fprintf (stderr, "\treg_size            = %5d\n", info->reg_size);
 
+    fprintf (stderr, "\tsave-strategy       =  %04x\n", info->savres_strategy);
+
   fprintf (stderr, "\n");
 }
 
@@ -18706,7 +18208,8 @@ rs6000_return_addr (int count, rtx frame)
          (Pmode,
           memory_address
           (Pmode,
-           plus_constant (copy_to_reg
+           plus_constant (Pmode,
+                          copy_to_reg
                           (gen_rtx_MEM (Pmode,
                                         memory_address (Pmode, frame))),
                           RETURN_ADDRESS_OFFSET)));
@@ -18919,6 +18422,8 @@ rs6000_emit_load_toc_table (int fromprolog)
          lab = gen_label_rtx ();
          emit_insn (gen_load_toc_v4_PIC_1b (tocsym, lab));
          emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
+         if (TARGET_LINK_STACK)
+           emit_insn (gen_addsi3 (dest, dest, GEN_INT (4)));
          emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
        }
       emit_insn (gen_addsi3 (dest, temp0, dest));
@@ -18974,7 +18479,8 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
       else if (info->push_p)
        sp_offset = info->total_size;
 
-      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
+      tmp = plus_constant (Pmode, frame_rtx,
+                          info->lr_save_offset + sp_offset);
       tmp = gen_frame_mem (Pmode, tmp);
       emit_move_insn (tmp, operands[0]);
     }
@@ -19033,7 +18539,7 @@ uses_TOC (void)
 rtx
 create_TOC_reference (rtx symbol, rtx largetoc_reg)
 {
-  rtx tocrel, tocreg;
+  rtx tocrel, tocreg, hi;
 
   if (TARGET_DEBUG_ADDR)
     {
@@ -19051,24 +18557,18 @@ create_TOC_reference (rtx symbol, rtx largetoc_reg)
   if (!can_create_pseudo_p ())
     df_set_regs_ever_live (TOC_REGISTER, true);
 
-  tocrel = gen_rtx_CONST (Pmode,
-                         gen_rtx_UNSPEC (Pmode, gen_rtvec (1, symbol),
-                                         UNSPEC_TOCREL));
   tocreg = gen_rtx_REG (Pmode, TOC_REGISTER);
-  if (TARGET_CMODEL != CMODEL_SMALL)
+  tocrel = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, symbol, tocreg), UNSPEC_TOCREL);
+  if (TARGET_CMODEL == CMODEL_SMALL || can_create_pseudo_p ())
+    return tocrel;
+
+  hi = gen_rtx_HIGH (Pmode, copy_rtx (tocrel));
+  if (largetoc_reg != NULL)
     {
-      rtx hi = gen_rtx_CONST (Pmode,
-                             gen_rtx_PLUS (Pmode, tocreg, 
-                                           gen_rtx_HIGH (Pmode, tocrel)));
-      if (largetoc_reg != NULL)
-       {
-         emit_move_insn (largetoc_reg, hi);
-         hi = largetoc_reg;
-       }
-      return gen_rtx_LO_SUM (Pmode, hi, copy_rtx (tocrel));
+      emit_move_insn (largetoc_reg, hi);
+      hi = largetoc_reg;
     }
-  else
-    return gen_rtx_PLUS (Pmode, tocreg, tocrel);
+  return gen_rtx_LO_SUM (Pmode, hi, tocrel);
 }
 
 /* Issue assembly directives that create a reference to the given DWARF
@@ -19077,19 +18577,36 @@ void
 rs6000_aix_asm_output_dwarf_table_ref (char * frame_table_label)
 {
   fprintf (asm_out_file, "\t.ref %s\n",
-          TARGET_STRIP_NAME_ENCODING (frame_table_label));
+          (* targetm.strip_name_encoding) (frame_table_label));
 }
 \f
 /* This ties together stack memory (MEM with an alias set of frame_alias_set)
    and the change to the stack pointer.  */
 
 static void
-rs6000_emit_stack_tie (void)
+rs6000_emit_stack_tie (rtx fp, bool hard_frame_needed)
 {
-  rtx mem = gen_frame_mem (BLKmode,
-                          gen_rtx_REG (Pmode, STACK_POINTER_REGNUM));
+  rtvec p;
+  int i;
+  rtx regs[3];
+
+  i = 0;
+  regs[i++] = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+  if (hard_frame_needed)
+    regs[i++] = gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM);
+  if (!(REGNO (fp) == STACK_POINTER_REGNUM
+       || (hard_frame_needed
+           && REGNO (fp) == HARD_FRAME_POINTER_REGNUM)))
+    regs[i++] = fp;
+
+  p = rtvec_alloc (i);
+  while (--i >= 0)
+    {
+      rtx mem = gen_frame_mem (BLKmode, regs[i]);
+      RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, const0_rtx);
+    }
 
-  emit_insn (gen_stack_tie (mem));
+  emit_insn (gen_stack_tie (gen_rtx_PARALLEL (VOIDmode, p)));
 }
 
 /* Emit the correct code for allocating stack space, as insns.
@@ -19097,7 +18614,7 @@ rs6000_emit_stack_tie (void)
    The generated code may use hard register 0 as a temporary.  */
 
 static void
-rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg)
+rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg, int copy_off)
 {
   rtx insn;
   rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
@@ -19141,7 +18658,12 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg)
     }
 
   if (copy_reg)
-    emit_move_insn (copy_reg, stack_reg);
+    {
+      if (copy_off != 0)
+       emit_insn (gen_add3_insn (copy_reg, stack_reg, GEN_INT (copy_off)));
+      else
+       emit_move_insn (copy_reg, stack_reg);
+    }
 
   if (size > 32767)
     {
@@ -19200,9 +18722,11 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
         it exceeds SIZE.  If only one probe is needed, this will not
         generate any code.  Then probe at FIRST + SIZE.  */
       for (i = PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
-       emit_stack_probe (plus_constant (stack_pointer_rtx, -(first + i)));
+       emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+                                        -(first + i)));
 
-      emit_stack_probe (plus_constant (stack_pointer_rtx, -(first + size)));
+      emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+                                      -(first + size)));
     }
 
   /* Otherwise, do the same as above, but in a loop.  Note that we must be
@@ -19228,7 +18752,8 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
 
       /* TEST_ADDR = SP + FIRST.  */
       emit_insn (gen_rtx_SET (VOIDmode, r12,
-                             plus_constant (stack_pointer_rtx, -first)));
+                             plus_constant (Pmode, stack_pointer_rtx,
+                                            -first)));
 
       /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE.  */
       if (rounded_size > 32768)
@@ -19239,7 +18764,7 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
        }
       else
        emit_insn (gen_rtx_SET (VOIDmode, r0,
-                               plus_constant (r12, -rounded_size)));
+                               plus_constant (Pmode, r12, -rounded_size)));
 
 
       /* Step 3: the loop
@@ -19263,7 +18788,7 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
         that SIZE is equal to ROUNDED_SIZE.  */
 
       if (size != rounded_size)
-       emit_stack_probe (plus_constant (r12, rounded_size - size));
+       emit_stack_probe (plus_constant (Pmode, r12, rounded_size - size));
     }
 }
 
@@ -19286,9 +18811,9 @@ output_probe_stack_range (rtx reg1, rtx reg2)
   xops[0] = reg1;
   xops[1] = reg2;
   if (TARGET_64BIT)
-    output_asm_insn ("{cmp|cmpd} 0,%0,%1", xops);
+    output_asm_insn ("cmpd 0,%0,%1", xops);
   else
-    output_asm_insn ("{cmp|cmpw} 0,%0,%1", xops);
+    output_asm_insn ("cmpw 0,%0,%1", xops);
 
   fputs ("\tbeq 0,", asm_out_file);
   assemble_name_raw (asm_out_file, end_lab);
@@ -19296,10 +18821,11 @@ output_probe_stack_range (rtx reg1, rtx reg2)
 
   /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL.  */
   xops[1] = GEN_INT (-PROBE_INTERVAL);
-  output_asm_insn ("{cal %0,%1(%0)|addi %0,%0,%1}", xops);
+  output_asm_insn ("addi %0,%0,%1", xops);
 
   /* Probe at TEST_ADDR and branch.  */
-  output_asm_insn ("{st|stw} 0,0(%0)", xops);
+  xops[1] = gen_rtx_REG (Pmode, 0);
+  output_asm_insn ("stw %1,0(%0)", xops);
   fprintf (asm_out_file, "\tb ");
   assemble_name_raw (asm_out_file, loop_lab);
   fputc ('\n', asm_out_file);
@@ -19313,7 +18839,10 @@ output_probe_stack_range (rtx reg1, rtx reg2)
    with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
    is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
    deduce these equivalences by itself so it wasn't necessary to hold
-   its hand so much.  */
+   its hand so much.  Don't be tempted to always supply d2_f_d_e with
+   the actual cfa register, ie. r31 when we are using a hard frame
+   pointer.  That fails when saving regs off r1, and sched moves the
+   r31 setup past the reg saves.  */
 
 static rtx
 rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
@@ -19321,6 +18850,25 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
 {
   rtx real, temp;
 
+  if (REGNO (reg) == STACK_POINTER_REGNUM && reg2 == NULL_RTX)
+    {
+      /* No need for any replacement.  Just set RTX_FRAME_RELATED_P.  */
+      int i;
+
+      gcc_checking_assert (val == 0);
+      real = PATTERN (insn);
+      if (GET_CODE (real) == PARALLEL)
+       for (i = 0; i < XVECLEN (real, 0); i++)
+         if (GET_CODE (XVECEXP (real, 0, i)) == SET)
+           {
+             rtx set = XVECEXP (real, 0, i);
+
+             RTX_FRAME_RELATED_P (set) = 1;
+           }
+      RTX_FRAME_RELATED_P (insn) = 1;
+      return insn;
+    }
+
   /* copy_rtx will not make unique copies of registers, so we need to
      ensure we don't have unwanted sharing here.  */
   if (reg == reg2)
@@ -19334,10 +18882,13 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
   if (reg2 != NULL_RTX)
     real = replace_rtx (real, reg2, rreg);
 
-  real = replace_rtx (real, reg,
-                     gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
-                                                       STACK_POINTER_REGNUM),
-                                   GEN_INT (val)));
+  if (REGNO (reg) == STACK_POINTER_REGNUM)
+    gcc_checking_assert (val == 0);
+  else
+    real = replace_rtx (real, reg,
+                       gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode,
+                                                         STACK_POINTER_REGNUM),
+                                     GEN_INT (val)));
 
   /* We expect that 'real' is either a SET or a PARALLEL containing
      SETs (and possibly other stuff).  In a PARALLEL, all the SETs
@@ -19451,48 +19002,49 @@ generate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
   return insn;
 }
 
+static rtx
+gen_frame_set (rtx reg, rtx frame_reg, int offset, bool store)
+{
+  rtx addr, mem;
+
+  addr = gen_rtx_PLUS (Pmode, frame_reg, GEN_INT (offset));
+  mem = gen_frame_mem (GET_MODE (reg), addr);
+  return gen_rtx_SET (VOIDmode, store ? mem : reg, store ? reg : mem);
+}
+
+static rtx
+gen_frame_load (rtx reg, rtx frame_reg, int offset)
+{
+  return gen_frame_set (reg, frame_reg, offset, false);
+}
+
+static rtx
+gen_frame_store (rtx reg, rtx frame_reg, int offset)
+{
+  return gen_frame_set (reg, frame_reg, offset, true);
+}
+
 /* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
    Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
 
 static rtx
-emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
-                unsigned int regno, int offset, HOST_WIDE_INT total_size)
+emit_frame_save (rtx frame_reg, enum machine_mode mode,
+                unsigned int regno, int offset, HOST_WIDE_INT frame_reg_to_sp)
 {
-  rtx reg, offset_rtx, insn, mem, addr, int_rtx;
-  rtx replacea, replaceb;
-
-  int_rtx = GEN_INT (offset);
+  rtx reg, insn;
 
   /* Some cases that need register indexed addressing.  */
-  if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
-      || (TARGET_VSX && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
-      || (TARGET_E500_DOUBLE && mode == DFmode)
-      || (TARGET_SPE_ABI
-         && SPE_VECTOR_MODE (mode)
-         && !SPE_CONST_OFFSET_OK (offset)))
-    {
-      /* Whomever calls us must make sure r11 is available in the
-        flow path of instructions in the prologue.  */
-      offset_rtx = gen_rtx_REG (Pmode, 11);
-      emit_move_insn (offset_rtx, int_rtx);
-
-      replacea = offset_rtx;
-      replaceb = int_rtx;
-    }
-  else
-    {
-      offset_rtx = int_rtx;
-      replacea = NULL_RTX;
-      replaceb = NULL_RTX;
-    }
+  gcc_checking_assert (!((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+                        || (TARGET_VSX && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
+                        || (TARGET_E500_DOUBLE && mode == DFmode)
+                        || (TARGET_SPE_ABI
+                            && SPE_VECTOR_MODE (mode)
+                            && !SPE_CONST_OFFSET_OK (offset))));
 
   reg = gen_rtx_REG (mode, regno);
-  addr = gen_rtx_PLUS (Pmode, frame_reg, offset_rtx);
-  mem = gen_frame_mem (mode, addr);
-
-  insn = emit_move_insn (mem, reg);
-
-  return rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
+  insn = emit_insn (gen_frame_store (reg, frame_reg, offset));
+  return rs6000_frame_related (insn, frame_reg, frame_reg_to_sp,
+                              NULL_RTX, NULL_RTX);
 }
 
 /* Emit an offset memory reference suitable for a frame store, while
@@ -19505,7 +19057,7 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
 
   int_rtx = GEN_INT (offset);
 
-  if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
+  if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode) && !SPE_CONST_OFFSET_OK (offset))
       || (TARGET_E500_DOUBLE && mode == DFmode))
     {
       offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
@@ -19517,30 +19069,25 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
   return gen_frame_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, bool gpr)
-{
-  int i;
-  int last = gpr ? 32 : 64;
-  for (i = first; i < last; i++)
-    if (global_regs[i])
-      return false;
-  return true;
-}
-
 #ifndef TARGET_FIX_AND_CONTINUE
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
 
-/* It's really GPR 13 and FPR 14, but we need the smaller of the two.  */
+/* It's really GPR 13 or 14, FPR 14 and VR 20.  We need the smallest.  */
 #define FIRST_SAVRES_REGISTER FIRST_SAVED_GP_REGNO
 #define LAST_SAVRES_REGISTER 31
 #define N_SAVRES_REGISTERS (LAST_SAVRES_REGISTER - FIRST_SAVRES_REGISTER + 1)
 
-static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][8];
+enum {
+  SAVRES_LR = 0x1,
+  SAVRES_SAVE = 0x2,
+  SAVRES_REG = 0x0c,
+  SAVRES_GPR = 0,
+  SAVRES_FPR = 4,
+  SAVRES_VR  = 8
+};
+
+static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][12];
 
 /* Temporary holding space for an out-of-line register save/restore
    routine name.  */
@@ -19550,8 +19097,7 @@ static char savres_routine_name[30];
    We are saving/restoring GPRs if GPR is true.  */
 
 static char *
-rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
-                           bool savep, bool gpr, bool lr)
+rs6000_savres_routine_name (rs6000_stack_t *info, int regno, int sel)
 {
   const char *prefix = "";
   const char *suffix = "";
@@ -19587,14 +19133,14 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
   if (TARGET_SPE)
     {
       /* No floating point saves on the SPE.  */
-      gcc_assert (gpr);
+      gcc_assert ((sel & SAVRES_REG) == SAVRES_GPR);
 
-      if (savep)
+      if ((sel & SAVRES_SAVE))
        prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_";
       else
        prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_";
 
-      if (lr)
+      if ((sel & SAVRES_LR))
        suffix = "_x";
     }
   else if (DEFAULT_ABI == ABI_V4)
@@ -19602,40 +19148,71 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
       if (TARGET_64BIT)
        goto aix_names;
 
-      if (gpr)
-       prefix = savep ? "_savegpr_" : "_restgpr_";
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+       prefix = (sel & SAVRES_SAVE) ? "_savegpr_" : "_restgpr_";
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+       prefix = (sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_";
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+       prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
       else
-       prefix = savep ? "_savefpr_" : "_restfpr_";
+       abort ();
 
-      if (lr)
+      if ((sel & SAVRES_LR))
        suffix = "_x";
     }
   else if (DEFAULT_ABI == ABI_AIX)
     {
-#ifndef POWERPC_LINUX
+#if !defined (POWERPC_LINUX) && !defined (POWERPC_FREEBSD)
       /* No out-of-line save/restore routines for GPRs on AIX.  */
-      gcc_assert (!TARGET_AIX || !gpr);
+      gcc_assert (!TARGET_AIX || (sel & SAVRES_REG) != SAVRES_GPR);
 #endif
 
     aix_names:
-      if (gpr)
-       prefix = (savep
-                 ? (lr ? "_savegpr0_" : "_savegpr1_")
-                 : (lr ? "_restgpr0_" : "_restgpr1_"));
-#ifdef POWERPC_LINUX
-      else if (lr)
-       prefix = (savep ? "_savefpr_" : "_restfpr_");
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+       prefix = ((sel & SAVRES_SAVE)
+                 ? ((sel & SAVRES_LR) ? "_savegpr0_" : "_savegpr1_")
+                 : ((sel & SAVRES_LR) ? "_restgpr0_" : "_restgpr1_"));
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+       {
+#if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
+         if ((sel & SAVRES_LR))
+           prefix = ((sel & SAVRES_SAVE) ? "_savefpr_" : "_restfpr_");
+         else
 #endif
-      else
-       {
-         prefix = savep ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX;
-         suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
+           {
+             prefix = (sel & SAVRES_SAVE) ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX;
+             suffix = (sel & SAVRES_SAVE) ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
+           }
        }
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+       prefix = (sel & SAVRES_SAVE) ? "_savevr_" : "_restvr_";
+      else
+       abort ();
+    }
+
+   if (DEFAULT_ABI == ABI_DARWIN)
+    {
+      /* The Darwin approach is (slightly) different, in order to be
+        compatible with code generated by the system toolchain.  There is a
+        single symbol for the start of save sequence, and the code here
+        embeds an offset into that code on the basis of the first register
+        to be saved.  */
+      prefix = (sel & SAVRES_SAVE) ? "save" : "rest" ;
+      if ((sel & SAVRES_REG) == SAVRES_GPR)
+       sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31", prefix,
+                ((sel & SAVRES_LR) ? "x" : ""), (regno == 13 ? "" : "+"),
+                (regno - 13) * 4, prefix, regno);
+      else if ((sel & SAVRES_REG) == SAVRES_FPR)
+       sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31", prefix,
+                (regno == 14 ? "" : "+"), (regno - 14) * 4, prefix, regno);
+      else if ((sel & SAVRES_REG) == SAVRES_VR)
+       sprintf (savres_routine_name, "*%sVEC%s%.0d ; %s v%d-v31", prefix,
+                (regno == 20 ? "" : "+"), (regno - 20) * 8, prefix, regno);
+      else
+       abort ();
     }
-  else if (DEFAULT_ABI == ABI_DARWIN)
-    sorry ("out-of-line save/restore routines not supported on Darwin");
-
-  sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
+  else
+    sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
 
   return savres_routine_name;
 }
@@ -19644,22 +19221,28 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
    We are saving/restoring GPRs if GPR is true.  */
 
 static rtx
-rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep,
-                          bool gpr, bool lr)
+rs6000_savres_routine_sym (rs6000_stack_t *info, int sel)
 {
-  int regno = gpr ? info->first_gp_reg_save : (info->first_fp_reg_save - 32);
+  int regno = ((sel & SAVRES_REG) == SAVRES_GPR
+              ? info->first_gp_reg_save
+              : (sel & SAVRES_REG) == SAVRES_FPR
+              ? info->first_fp_reg_save - 32
+              : (sel & SAVRES_REG) == SAVRES_VR
+              ? info->first_altivec_reg_save - FIRST_ALTIVEC_REGNO
+              : -1);
   rtx sym;
-  int select = ((savep ? 1 : 0) << 2
-               | ((TARGET_SPE_ABI
-                   /* On the SPE, we never have any FPRs, but we do have
-                      32/64-bit versions of the routines.  */
-                   ? (info->spe_64bit_regs_used ? 1 : 0)
-                   : (gpr ? 1 : 0)) << 1)
-               | (lr ? 1: 0));
+  int select = sel;
+
+  /* On the SPE, we never have any FPRs, but we do have 32/64-bit
+     versions of the gpr routines.  */
+  if (TARGET_SPE_ABI && (sel & SAVRES_REG) == SAVRES_GPR
+      && info->spe_64bit_regs_used)
+    select ^= SAVRES_FPR ^ SAVRES_GPR;
 
   /* Don't generate bogus routine names.  */
   gcc_assert (FIRST_SAVRES_REGISTER <= regno
-             && regno <= LAST_SAVRES_REGISTER);
+             && regno <= LAST_SAVRES_REGISTER
+             && select >= 0 && select <= 12);
 
   sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select];
 
@@ -19667,7 +19250,7 @@ rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep,
     {
       char *name;
 
-      name = rs6000_savres_routine_name (info, regno, savep, gpr, lr);
+      name = rs6000_savres_routine_name (info, regno, sel);
 
       sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]
        = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
@@ -19678,113 +19261,129 @@ rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep,
 }
 
 /* Emit a sequence of insns, including a stack tie if needed, for
-   resetting the stack pointer.  If SAVRES is true, then don't reset the
-   stack pointer, but move the base of the frame into r11 for use by
-   out-of-line register restore routines.  */
+   resetting the stack pointer.  If UPDT_REGNO is not 1, then don't
+   reset the stack pointer, but move the base of the frame into
+   reg UPDT_REGNO for use by out-of-line register restore routines.  */
 
 static rtx
 rs6000_emit_stack_reset (rs6000_stack_t *info,
-                        rtx sp_reg_rtx, rtx frame_reg_rtx,
-                        int sp_offset, bool savres)
+                        rtx frame_reg_rtx, HOST_WIDE_INT frame_off,
+                        unsigned updt_regno)
 {
+  rtx updt_reg_rtx;
+
   /* This blockage is needed so that sched doesn't decide to move
      the sp change before the register restores.  */
-  if (frame_reg_rtx != sp_reg_rtx
+  if (DEFAULT_ABI == ABI_V4
       || (TARGET_SPE_ABI
          && info->spe_64bit_regs_used != 0
          && info->first_gp_reg_save != 32))
-    rs6000_emit_stack_tie ();
-  
-  if (frame_reg_rtx != sp_reg_rtx)
-    {
-      if (sp_offset != 0)
-       {
-         rtx dest_reg = savres ? gen_rtx_REG (Pmode, 11) : sp_reg_rtx;
-         return emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
-                                          GEN_INT (sp_offset)));
-       }
-      else if (!savres)
-       return emit_move_insn (sp_reg_rtx, frame_reg_rtx);
-    }
-  else if (sp_offset != 0)
-    {
-      /* If we are restoring registers out-of-line, we will be using the
-        "exit" variants of the restore routines, which will reset the
-        stack for us.  But we do need to point r11 into the right place
-        for those routines.  */
-      rtx dest_reg = (savres
-                     ? gen_rtx_REG (Pmode, 11)
-                     : sp_reg_rtx);
+    rs6000_emit_stack_tie (frame_reg_rtx, frame_pointer_needed);
+
+  /* If we are restoring registers out-of-line, we will be using the
+     "exit" variants of the restore routines, which will reset the
+     stack for us.  But we do need to point updt_reg into the
+     right place for those routines.  */
+  updt_reg_rtx = gen_rtx_REG (Pmode, updt_regno);
+
+  if (frame_off != 0)
+    return emit_insn (gen_add3_insn (updt_reg_rtx,
+                                    frame_reg_rtx, GEN_INT (frame_off)));
+  else if (REGNO (frame_reg_rtx) != updt_regno)
+    return emit_move_insn (updt_reg_rtx, frame_reg_rtx);
 
-      rtx insn = emit_insn (gen_add3_insn (dest_reg, sp_reg_rtx,
-                                          GEN_INT (sp_offset)));
-      if (!savres)
-       return insn;
-    }
   return NULL_RTX;
 }
 
+/* Return the register number used as a pointer by out-of-line
+   save/restore functions.  */
+
+static inline unsigned
+ptr_regno_for_savres (int sel)
+{
+  if (DEFAULT_ABI == ABI_AIX)
+    return (sel & SAVRES_REG) == SAVRES_FPR || (sel & SAVRES_LR) ? 1 : 12;
+  return DEFAULT_ABI == ABI_DARWIN && (sel & SAVRES_REG) == SAVRES_FPR ? 1 : 11;
+}
+
 /* Construct a parallel rtx describing the effect of a call to an
-   out-of-line register save/restore routine.  */
+   out-of-line register save/restore routine, and emit the insn
+   or jump_insn as appropriate.  */
 
 static rtx
-rs6000_make_savres_rtx (rs6000_stack_t *info,
-                       rtx frame_reg_rtx, int save_area_offset,
-                       enum machine_mode reg_mode,
-                       bool savep, bool gpr, bool lr)
+rs6000_emit_savres_rtx (rs6000_stack_t *info,
+                       rtx frame_reg_rtx, int save_area_offset, int lr_offset,
+                       enum machine_mode reg_mode, int sel)
 {
   int i;
-  int offset, start_reg, end_reg, n_regs;
+  int offset, start_reg, end_reg, n_regs, use_reg;
   int reg_size = GET_MODE_SIZE (reg_mode);
   rtx sym;
   rtvec p;
+  rtx par, insn;
 
   offset = 0;
-  start_reg = (gpr
+  start_reg = ((sel & SAVRES_REG) == SAVRES_GPR
               ? info->first_gp_reg_save
-              : info->first_fp_reg_save);
-  end_reg = gpr ? 32 : 64;
+              : (sel & SAVRES_REG) == SAVRES_FPR
+              ? info->first_fp_reg_save
+              : (sel & SAVRES_REG) == SAVRES_VR
+              ? info->first_altivec_reg_save
+              : -1);
+  end_reg = ((sel & SAVRES_REG) == SAVRES_GPR
+            ? 32
+            : (sel & SAVRES_REG) == SAVRES_FPR
+            ? 64
+            : (sel & SAVRES_REG) == SAVRES_VR
+            ? LAST_ALTIVEC_REGNO + 1
+            : -1);
   n_regs = end_reg - start_reg;
-  p = rtvec_alloc ((lr ? 4 : 3) + n_regs);
+  p = rtvec_alloc (3 + ((sel & SAVRES_LR) ? 1 : 0)
+                  + ((sel & SAVRES_REG) == SAVRES_VR ? 1 : 0)
+                  + n_regs);
 
-  if (!savep && lr)
+  if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
     RTVEC_ELT (p, offset++) = ret_rtx;
 
   RTVEC_ELT (p, offset++)
-    = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65));
+    = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, LR_REGNO));
 
-  sym = rs6000_savres_routine_sym (info, savep, gpr, lr);
+  sym = rs6000_savres_routine_sym (info, sel);
   RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
-  RTVEC_ELT (p, offset++)
-    = gen_rtx_USE (VOIDmode,
-                  gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11
-                                      : gpr && !lr ? 12
-                                      : 1));
 
-  for (i = 0; i < end_reg - start_reg; i++)
+  use_reg = ptr_regno_for_savres (sel);
+  if ((sel & SAVRES_REG) == SAVRES_VR)
     {
-      rtx addr, reg, mem;
-      reg = gen_rtx_REG (reg_mode, start_reg + i);
-      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                          GEN_INT (save_area_offset + reg_size*i));
-      mem = gen_frame_mem (reg_mode, addr);
-
-      RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode,
-                                              savep ? mem : reg,
-                                              savep ? reg : mem);
+      /* Vector regs are saved/restored using [reg+reg] addressing.  */
+      RTVEC_ELT (p, offset++)
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, use_reg));
+      RTVEC_ELT (p, offset++)
+       = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
     }
+  else
+    RTVEC_ELT (p, offset++)
+      = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, use_reg));
 
-  if (savep && lr)
+  for (i = 0; i < end_reg - start_reg; i++)
+    RTVEC_ELT (p, i + offset)
+      = gen_frame_set (gen_rtx_REG (reg_mode, start_reg + i),
+                      frame_reg_rtx, save_area_offset + reg_size * i,
+                      (sel & SAVRES_SAVE) != 0);
+
+  if ((sel & SAVRES_SAVE) && (sel & SAVRES_LR))
+    RTVEC_ELT (p, i + offset)
+      = gen_frame_store (gen_rtx_REG (Pmode, 0), frame_reg_rtx, lr_offset);
+
+  par = gen_rtx_PARALLEL (VOIDmode, p);
+
+  if (!(sel & SAVRES_SAVE) && (sel & SAVRES_LR))
     {
-      rtx addr, reg, mem;
-      reg = gen_rtx_REG (Pmode, 0);
-      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                          GEN_INT (info->lr_save_offset));
-      mem = gen_frame_mem (Pmode, addr);
-      RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg);
+      insn = emit_jump_insn (par);
+      JUMP_LABEL (insn) = ret_rtx;
     }
-
-  return gen_rtx_PARALLEL (VOIDmode, p);
+  else
+    insn = emit_insn (par);
+  return insn;
 }
 
 /* Determine whether the gp REG is really used.  */
@@ -19817,18 +19416,40 @@ rs6000_emit_prologue (void)
   enum machine_mode reg_mode = Pmode;
   int reg_size = TARGET_32BIT ? 4 : 8;
   rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
-  rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
   rtx frame_reg_rtx = sp_reg_rtx;
+  unsigned int cr_save_regno;
   rtx cr_save_rtx = NULL_RTX;
   rtx insn;
   int strategy;
-  int saving_FPRs_inline;
-  int saving_GPRs_inline;
-  int using_store_multiple;
   int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
-                              && df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
+                             && df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
                              && call_used_regs[STATIC_CHAIN_REGNUM]);
-  HOST_WIDE_INT sp_offset = 0;
+  /* Offset to top of frame for frame_reg and sp respectively.  */
+  HOST_WIDE_INT frame_off = 0;
+  HOST_WIDE_INT sp_off = 0;
+
+#ifdef ENABLE_CHECKING
+  /* Track and check usage of r0, r11, r12.  */
+  int reg_inuse = using_static_chain_p ? 1 << 11 : 0;
+#define START_USE(R) do \
+  {                                            \
+    gcc_assert ((reg_inuse & (1 << (R))) == 0);        \
+    reg_inuse |= 1 << (R);                     \
+  } while (0)
+#define END_USE(R) do \
+  {                                            \
+    gcc_assert ((reg_inuse & (1 << (R))) != 0);        \
+    reg_inuse &= ~(1 << (R));                  \
+  } while (0)
+#define NOT_INUSE(R) do \
+  {                                            \
+    gcc_assert ((reg_inuse & (1 << (R))) == 0);        \
+  } while (0)
+#else
+#define START_USE(R) do {} while (0)
+#define END_USE(R) do {} while (0)
+#define NOT_INUSE(R) do {} while (0)
+#endif
 
   if (flag_stack_usage_info)
     current_function_static_stack_size = info->total_size;
@@ -19856,52 +19477,6 @@ rs6000_emit_prologue (void)
       reg_size = 8;
     }
 
-  strategy = info->savres_strategy;
-  using_store_multiple = strategy & SAVRES_MULTIPLE;
-  saving_FPRs_inline = strategy & SAVE_INLINE_FPRS;
-  saving_GPRs_inline = strategy & SAVE_INLINE_GPRS;
-
-  /* For V.4, update stack before we do any saving and set back pointer.  */
-  if (! WORLD_SAVE_P (info)
-      && info->push_p
-      && (DEFAULT_ABI == ABI_V4
-         || crtl->calls_eh_return))
-    {
-      bool need_r11 = (TARGET_SPE
-                      ? (!saving_GPRs_inline
-                         && info->spe_64bit_regs_used == 0)
-                      : (!saving_FPRs_inline || !saving_GPRs_inline));
-      rtx copy_reg = need_r11 ? gen_rtx_REG (Pmode, 11) : NULL;
-
-      if (info->total_size < 32767)
-       sp_offset = info->total_size;
-      else if (need_r11)
-       frame_reg_rtx = copy_reg;
-      else if (info->cr_save_p
-              || info->lr_save_p
-              || info->first_fp_reg_save < 64
-              || info->first_gp_reg_save < 32
-              || info->altivec_size != 0
-              || info->vrsave_mask != 0
-              || crtl->calls_eh_return)
-       {
-         copy_reg = frame_ptr_rtx;
-         frame_reg_rtx = copy_reg;
-       }
-      else
-       {
-         /* The prologue won't be saving any regs so there is no need
-            to set up a frame register to access any frame save area.
-            We also won't be using sp_offset anywhere below, but set
-            the correct value anyway to protect against future
-            changes to this function.  */
-         sp_offset = info->total_size;
-       }
-      rs6000_emit_allocate_stack (info->total_size, copy_reg);
-      if (frame_reg_rtx != sp_reg_rtx)
-       rs6000_emit_stack_tie ();
-    }
-
   /* Handle world saves specially here.  */
   if (WORLD_SAVE_P (info))
     {
@@ -19929,7 +19504,7 @@ rs6000_emit_prologue (void)
                  && info->push_p
                  && info->lr_save_p
                  && (!crtl->calls_eh_return
-                      || info->ehrd_offset == -432)
+                     || info->ehrd_offset == -432)
                  && info->vrsave_save_offset == -224
                  && info->altivec_save_offset == -416);
 
@@ -19955,59 +19530,33 @@ rs6000_emit_prologue (void)
       /* We do floats first so that the instruction pattern matches
         properly.  */
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-       {
-         rtx reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                                  ? DFmode : SFmode), 
-                                info->first_fp_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->fp_save_offset
-                                           + sp_offset + 8 * i));
-         rtx mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                                    ? DFmode : SFmode), addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-       }
+       RTVEC_ELT (p, j++)
+         = gen_frame_store (gen_rtx_REG (TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
+                                         ? DFmode : SFmode,
+                                         info->first_fp_reg_save + i),
+                            frame_reg_rtx,
+                            info->fp_save_offset + frame_off + 8 * i);
       for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
-       {
-         rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->altivec_save_offset
-                                           + sp_offset + 16 * i));
-         rtx mem = gen_frame_mem (V4SImode, addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-       }
+       RTVEC_ELT (p, j++)
+         = gen_frame_store (gen_rtx_REG (V4SImode,
+                                         info->first_altivec_reg_save + i),
+                            frame_reg_rtx,
+                            info->altivec_save_offset + frame_off + 16 * i);
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       {
-         rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->gp_save_offset
-                                           + sp_offset + reg_size * i));
-         rtx mem = gen_frame_mem (reg_mode, addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-       }
-
-      {
-       /* CR register traditionally saved as CR2.  */
-       rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
-       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                GEN_INT (info->cr_save_offset
-                                         + sp_offset));
-       rtx mem = gen_frame_mem (reg_mode, addr);
+       RTVEC_ELT (p, j++)
+         = gen_frame_store (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                            frame_reg_rtx,
+                            info->gp_save_offset + frame_off + reg_size * i);
 
-       RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-      }
+      /* CR register traditionally saved as CR2.  */
+      RTVEC_ELT (p, j++)
+       = gen_frame_store (gen_rtx_REG (SImode, CR2_REGNO),
+                          frame_reg_rtx, info->cr_save_offset + frame_off);
       /* Explain about use of R0.  */
       if (info->lr_save_p)
-       {
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->lr_save_offset
-                                           + sp_offset));
-         rtx mem = gen_frame_mem (reg_mode, addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0);
-       }
+       RTVEC_ELT (p, j++)
+         = gen_frame_store (reg0,
+                            frame_reg_rtx, info->lr_save_offset + frame_off);
       /* Explain what happens to the stack pointer.  */
       {
        rtx newval = gen_rtx_PLUS (Pmode, sp_reg_rtx, treg);
@@ -20015,9 +19564,69 @@ rs6000_emit_prologue (void)
       }
 
       insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+      rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
                            treg, GEN_INT (-info->total_size));
-      sp_offset = info->total_size;
+      sp_off = frame_off = info->total_size;
+    }
+
+  strategy = info->savres_strategy;
+
+  /* For V.4, update stack before we do any saving and set back pointer.  */
+  if (! WORLD_SAVE_P (info)
+      && info->push_p
+      && (DEFAULT_ABI == ABI_V4
+         || crtl->calls_eh_return))
+    {
+      bool need_r11 = (TARGET_SPE
+                      ? (!(strategy & SAVE_INLINE_GPRS)
+                         && info->spe_64bit_regs_used == 0)
+                      : (!(strategy & SAVE_INLINE_FPRS)
+                         || !(strategy & SAVE_INLINE_GPRS)
+                         || !(strategy & SAVE_INLINE_VRS)));
+      int ptr_regno = -1;
+      rtx ptr_reg = NULL_RTX;
+      int ptr_off = 0;
+
+      if (info->total_size < 32767)
+       frame_off = info->total_size;
+      else if (need_r11)
+       ptr_regno = 11;
+      else if (info->cr_save_p
+              || info->lr_save_p
+              || info->first_fp_reg_save < 64
+              || info->first_gp_reg_save < 32
+              || info->altivec_size != 0
+              || info->vrsave_mask != 0
+              || crtl->calls_eh_return)
+       ptr_regno = 12;
+      else
+       {
+         /* The prologue won't be saving any regs so there is no need
+            to set up a frame register to access any frame save area.
+            We also won't be using frame_off anywhere below, but set
+            the correct value anyway to protect against future
+            changes to this function.  */
+         frame_off = info->total_size;
+       }
+      if (ptr_regno != -1)
+       {
+         /* Set up the frame offset to that needed by the first
+            out-of-line save function.  */
+         START_USE (ptr_regno);
+         ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
+         frame_reg_rtx = ptr_reg;
+         if (!(strategy & SAVE_INLINE_FPRS) && info->fp_size != 0)
+           gcc_checking_assert (info->fp_save_offset + info->fp_size == 0);
+         else if (!(strategy & SAVE_INLINE_GPRS) && info->first_gp_reg_save < 32)
+           ptr_off = info->gp_save_offset + info->gp_size;
+         else if (!(strategy & SAVE_INLINE_VRS) && info->altivec_size != 0)
+           ptr_off = info->altivec_save_offset + info->altivec_size;
+         frame_off = -ptr_off;
+       }
+      rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
+      sp_off = info->total_size;
+      if (frame_reg_rtx != sp_reg_rtx)
+       rs6000_emit_stack_tie (frame_reg_rtx, false);
     }
 
   /* If we use the link register, get it into r0.  */
@@ -20025,34 +19634,42 @@ rs6000_emit_prologue (void)
     {
       rtx addr, reg, mem;
 
-      insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
-                            gen_rtx_REG (Pmode, LR_REGNO));
+      reg = gen_rtx_REG (Pmode, 0);
+      START_USE (0);
+      insn = emit_move_insn (reg, gen_rtx_REG (Pmode, LR_REGNO));
       RTX_FRAME_RELATED_P (insn) = 1;
 
       if (!(strategy & (SAVE_NOINLINE_GPRS_SAVES_LR
                        | SAVE_NOINLINE_FPRS_SAVES_LR)))
        {
          addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->lr_save_offset + sp_offset));
-         reg = gen_rtx_REG (Pmode, 0);
+                              GEN_INT (info->lr_save_offset + frame_off));
          mem = gen_rtx_MEM (Pmode, addr);
          /* This should not be of rs6000_sr_alias_set, because of
             __builtin_return_address.  */
 
          insn = emit_move_insn (mem, reg);
-         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+         rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
                                NULL_RTX, NULL_RTX);
+         END_USE (0);
        }
     }
 
-  /* If we need to save CR, put it into r12 or r11.  */
-  if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
+  /* If we need to save CR, put it into r12 or r11.  Choose r12 except when
+     r12 will be needed by out-of-line gpr restore.  */
+  cr_save_regno = (DEFAULT_ABI == ABI_AIX
+                  && !(strategy & (SAVE_INLINE_GPRS
+                                   | SAVE_NOINLINE_GPRS_SAVES_LR))
+                  ? 11 : 12);
+  if (!WORLD_SAVE_P (info)
+      && info->cr_save_p
+      && REGNO (frame_reg_rtx) != cr_save_regno
+      && !(using_static_chain_p && cr_save_regno == 11))
     {
       rtx set;
 
-      cr_save_rtx
-       = gen_rtx_REG (SImode, DEFAULT_ABI == ABI_AIX && !saving_GPRs_inline
-                      ? 11 : 12);
+      cr_save_rtx = gen_rtx_REG (SImode, cr_save_regno);
+      START_USE (cr_save_regno);
       insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
       RTX_FRAME_RELATED_P (insn) = 1;
       /* Now, there's no way that dwarf2out_frame_debug_expr is going
@@ -20068,33 +19685,42 @@ rs6000_emit_prologue (void)
 
   /* Do any required saving of fpr's.  If only one or two to save, do
      it ourselves.  Otherwise, call function.  */
-  if (!WORLD_SAVE_P (info) && saving_FPRs_inline)
+  if (!WORLD_SAVE_P (info) && (strategy & SAVE_INLINE_FPRS))
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-       if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
-            && ! call_used_regs[info->first_fp_reg_save+i]))
-         emit_frame_save (frame_reg_rtx, frame_ptr_rtx, 
-                          (TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                           ? DFmode : SFmode,
+       if (save_reg_p (info->first_fp_reg_save + i))
+         emit_frame_save (frame_reg_rtx,
+                          (TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
+                           ? DFmode : SFmode),
                           info->first_fp_reg_save + i,
-                          info->fp_save_offset + sp_offset + 8 * i,
-                          info->total_size);
+                          info->fp_save_offset + frame_off + 8 * i,
+                          sp_off - frame_off);
     }
   else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
     {
-      rtx par;
-
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->fp_save_offset + sp_offset,
-                                   DFmode,
-                                   /*savep=*/true, /*gpr=*/false,
-                                   /*lr=*/(strategy
-                                           & SAVE_NOINLINE_FPRS_SAVES_LR)
-                                          != 0);
-      insn = emit_insn (par);
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+      bool lr = (strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
+      int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
+      unsigned ptr_regno = ptr_regno_for_savres (sel);
+      rtx ptr_reg = frame_reg_rtx;
+
+      if (REGNO (frame_reg_rtx) == ptr_regno)
+       gcc_checking_assert (frame_off == 0);
+      else
+       {
+         ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
+         NOT_INUSE (ptr_regno);
+         emit_insn (gen_add3_insn (ptr_reg,
+                                   frame_reg_rtx, GEN_INT (frame_off)));
+       }
+      insn = rs6000_emit_savres_rtx (info, ptr_reg,
+                                    info->fp_save_offset,
+                                    info->lr_save_offset,
+                                    DFmode, sel);
+      rs6000_frame_related (insn, ptr_reg, sp_off,
                            NULL_RTX, NULL_RTX);
+      if (lr)
+       END_USE (0);
     }
 
   /* Save GPRs.  This is done as a PARALLEL if we are using
@@ -20106,142 +19732,138 @@ rs6000_emit_prologue (void)
     {
       int i;
       rtx spe_save_area_ptr;
+      HOST_WIDE_INT save_off;
+      int ool_adjust = 0;
+
       /* Determine whether we can address all of the registers that need
-        to be saved with an offset from the stack pointer that fits in
+        to be saved with an offset from frame_reg_rtx that fits in
         the small const field for SPE memory instructions.  */
-      int spe_regs_addressable_via_sp
-       = (SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
-                              + (32 - info->first_gp_reg_save - 1) * reg_size)
-          && saving_GPRs_inline);
-      int spe_offset;
-      if (spe_regs_addressable_via_sp)
+      int spe_regs_addressable
+       = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off
+                               + reg_size * (32 - info->first_gp_reg_save - 1))
+          && (strategy & SAVE_INLINE_GPRS));
+
+      if (spe_regs_addressable)
        {
          spe_save_area_ptr = frame_reg_rtx;
-         spe_offset = info->spe_gp_save_offset + sp_offset;
+         save_off = frame_off;
        }
       else
        {
          /* Make r11 point to the start of the SPE save area.  We need
             to be careful here if r11 is holding the static chain.  If
-            it is, then temporarily save it in r0.  We would use r0 as
-            our base register here, but using r0 as a base register in
-            loads and stores means something different from what we
-            would like.  */
-         int ool_adjust = (saving_GPRs_inline
-                           ? 0
-                           : (info->first_gp_reg_save
-                              - (FIRST_SAVRES_REGISTER+1))*8);
-         HOST_WIDE_INT offset = (info->spe_gp_save_offset
-                                 + sp_offset - ool_adjust);
+            it is, then temporarily save it in r0.  */
+         HOST_WIDE_INT offset;
+
+         if (!(strategy & SAVE_INLINE_GPRS))
+           ool_adjust = 8 * (info->first_gp_reg_save
+                             - (FIRST_SAVRES_REGISTER + 1));
+         offset = info->spe_gp_save_offset + frame_off - ool_adjust;
+         spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+         save_off = frame_off - offset;
 
          if (using_static_chain_p)
            {
              rtx r0 = gen_rtx_REG (Pmode, 0);
+
+             START_USE (0);
              gcc_assert (info->first_gp_reg_save > 11);
-             emit_move_insn (r0, gen_rtx_REG (Pmode, 11));
+
+             emit_move_insn (r0, spe_save_area_ptr);
            }
-         spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
-         insn = emit_insn (gen_addsi3 (spe_save_area_ptr,
-                                       frame_reg_rtx,
-                                       GEN_INT (offset)));
-         /* We need to make sure the move to r11 gets noted for
-            properly outputting unwind information.  */
-         if (!saving_GPRs_inline)
-           rs6000_frame_related (insn, frame_reg_rtx, offset,
-                                 NULL_RTX, NULL_RTX);
-         spe_offset = 0;
+         else if (REGNO (frame_reg_rtx) != 11)
+           START_USE (11);
+
+         emit_insn (gen_addsi3 (spe_save_area_ptr,
+                                frame_reg_rtx, GEN_INT (offset)));
+         if (!using_static_chain_p && REGNO (frame_reg_rtx) == 11)
+           frame_off = -info->spe_gp_save_offset + ool_adjust;
        }
-      if (saving_GPRs_inline)
+
+      if ((strategy & SAVE_INLINE_GPRS))
        {
          for (i = 0; i < 32 - info->first_gp_reg_save; i++)
            if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
-             {
-               rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-               rtx offset, addr, mem;
-
-               /* We're doing all this to ensure that the offset fits into
-                  the immediate offset of 'evstdd'.  */
-               gcc_assert (SPE_CONST_OFFSET_OK (reg_size * i + spe_offset));
-               offset = GEN_INT (reg_size * i + spe_offset);
-               addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
-               mem = gen_rtx_MEM (V2SImode, addr);
-  
-               insn = emit_move_insn (mem, reg);
-          
-               rs6000_frame_related (insn, spe_save_area_ptr,
-                                     info->spe_gp_save_offset
-                                     + sp_offset + reg_size * i,
-                                     offset, const0_rtx);
-             }
+             emit_frame_save (spe_save_area_ptr, reg_mode,
+                              info->first_gp_reg_save + i,
+                              (info->spe_gp_save_offset + save_off
+                               + reg_size * i),
+                              sp_off - save_off);
        }
       else
        {
-         rtx par;
+         insn = rs6000_emit_savres_rtx (info, spe_save_area_ptr,
+                                        info->spe_gp_save_offset + save_off,
+                                        0, reg_mode,
+                                        SAVRES_SAVE | SAVRES_GPR);
 
-         par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
-                                       0, reg_mode,
-                                       /*savep=*/true, /*gpr=*/true,
-                                       /*lr=*/false);
-         insn = emit_insn (par);
-         rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+         rs6000_frame_related (insn, spe_save_area_ptr, sp_off - save_off,
                                NULL_RTX, NULL_RTX);
        }
-                                       
+
       /* Move the static chain pointer back.  */
-      if (using_static_chain_p && !spe_regs_addressable_via_sp)
-       emit_move_insn (gen_rtx_REG (Pmode, 11), gen_rtx_REG (Pmode, 0));
+      if (!spe_regs_addressable)
+       {
+         if (using_static_chain_p)
+           {
+             emit_move_insn (spe_save_area_ptr, gen_rtx_REG (Pmode, 0));
+             END_USE (0);
+           }
+         else if (REGNO (frame_reg_rtx) != 11)
+           END_USE (11);
+       }
     }
-  else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline)
+  else if (!WORLD_SAVE_P (info) && !(strategy & SAVE_INLINE_GPRS))
     {
-      rtx par;
+      bool lr = (strategy & SAVE_NOINLINE_GPRS_SAVES_LR) != 0;
+      int sel = SAVRES_SAVE | SAVRES_GPR | (lr ? SAVRES_LR : 0);
+      unsigned ptr_regno = ptr_regno_for_savres (sel);
+      rtx ptr_reg = frame_reg_rtx;
+      bool ptr_set_up = REGNO (ptr_reg) == ptr_regno;
+      int end_save = info->gp_save_offset + info->gp_size;
+      int ptr_off;
+
+      if (!ptr_set_up)
+       ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
 
       /* Need to adjust r11 (r12) if we saved any FPRs.  */
-      if (info->first_fp_reg_save != 64)
-        {
-         rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX
-                                     ? 12 : 11);
-         rtx offset = GEN_INT (sp_offset
-                                + (-8 * (64-info->first_fp_reg_save)));
-         emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
-        }
+      if (end_save + frame_off != 0)
+       {
+         rtx offset = GEN_INT (end_save + frame_off);
 
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->gp_save_offset + sp_offset,
-                                   reg_mode,
-                                   /*savep=*/true, /*gpr=*/true,
-                                   /*lr=*/(strategy
-                                           & SAVE_NOINLINE_GPRS_SAVES_LR)
-                                          != 0);
-      insn = emit_insn (par);
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+         if (ptr_set_up)
+           frame_off = -end_save;
+         else
+           NOT_INUSE (ptr_regno);
+         emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+       }
+      else if (!ptr_set_up)
+       {
+         NOT_INUSE (ptr_regno);
+         emit_move_insn (ptr_reg, frame_reg_rtx);
+       }
+      ptr_off = -end_save;
+      insn = rs6000_emit_savres_rtx (info, ptr_reg,
+                                    info->gp_save_offset + ptr_off,
+                                    info->lr_save_offset + ptr_off,
+                                    reg_mode, sel);
+      rs6000_frame_related (insn, ptr_reg, sp_off - ptr_off,
                            NULL_RTX, NULL_RTX);
+      if (lr)
+       END_USE (0);
     }
-  else if (!WORLD_SAVE_P (info) && using_store_multiple)
+  else if (!WORLD_SAVE_P (info) && (strategy & SAVRES_MULTIPLE))
     {
       rtvec p;
       int i;
       p = rtvec_alloc (32 - info->first_gp_reg_save);
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       {
-         rtx addr, reg, mem;
-         reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-         addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->gp_save_offset
-                                       + sp_offset
-                                       + reg_size * i));
-         mem = gen_frame_mem (reg_mode, addr);
-
-         RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, mem, reg);
-       }
+       RTVEC_ELT (p, i)
+         = gen_frame_store (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                            frame_reg_rtx,
+                            info->gp_save_offset + frame_off + reg_size * i);
       insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+      rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
                            NULL_RTX, NULL_RTX);
     }
   else if (!WORLD_SAVE_P (info))
@@ -20249,39 +19871,43 @@ rs6000_emit_prologue (void)
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
        if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
-          {
-            rtx addr, reg, mem;
-            reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-
-            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                 GEN_INT (info->gp_save_offset
-                                          + sp_offset
-                                          + reg_size * i));
-            mem = gen_frame_mem (reg_mode, addr);
-
-            insn = emit_move_insn (mem, reg);
-            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                  NULL_RTX, NULL_RTX);
-          }
+         emit_frame_save (frame_reg_rtx, reg_mode,
+                          info->first_gp_reg_save + i,
+                          info->gp_save_offset + frame_off + reg_size * i,
+                          sp_off - frame_off);
     }
 
-  /* ??? There's no need to emit actual instructions here, but it's the
-     easiest way to get the frame unwind information emitted.  */
   if (crtl->calls_eh_return)
     {
-      unsigned int i, regno;
+      unsigned int i;
+      rtvec p;
 
       for (i = 0; ; ++i)
        {
-         regno = EH_RETURN_DATA_REGNO (i);
+         unsigned int regno = EH_RETURN_DATA_REGNO (i);
+         if (regno == INVALID_REGNUM)
+           break;
+       }
+
+      p = rtvec_alloc (i);
+
+      for (i = 0; ; ++i)
+       {
+         unsigned int regno = EH_RETURN_DATA_REGNO (i);
          if (regno == INVALID_REGNUM)
            break;
 
-         emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
-                          info->ehrd_offset + sp_offset
-                          + reg_size * (int) i,
-                          info->total_size);
+         insn
+           = gen_frame_store (gen_rtx_REG (reg_mode, regno),
+                              sp_reg_rtx,
+                              info->ehrd_offset + sp_off + reg_size * (int) i);
+         RTVEC_ELT (p, i) = insn;
+         RTX_FRAME_RELATED_P (insn) = 1;
        }
+
+      insn = emit_insn (gen_blockage ());
+      RTX_FRAME_RELATED_P (insn) = 1;
+      add_reg_note (insn, REG_FRAME_RELATED_EXPR, gen_rtx_PARALLEL (VOIDmode, p));
     }
 
   /* In AIX ABI we need to make sure r2 is really saved.  */
@@ -20291,13 +19917,15 @@ rs6000_emit_prologue (void)
       rtx save_insn, join_insn, note;
       long toc_restore_insn;
 
-      gcc_assert (frame_reg_rtx == frame_ptr_rtx
-                 || frame_reg_rtx == sp_reg_rtx);
       tmp_reg = gen_rtx_REG (Pmode, 11);
       tmp_reg_si = gen_rtx_REG (SImode, 11);
       if (using_static_chain_p)
-       emit_move_insn (gen_rtx_REG (Pmode, 0), tmp_reg);
-      gcc_assert (saving_GPRs_inline && saving_FPRs_inline);
+       {
+         START_USE (0);
+         emit_move_insn (gen_rtx_REG (Pmode, 0), tmp_reg);
+       }
+      else
+       START_USE (11);
       emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, LR_REGNO));
       /* Peek at instruction to which this function returns.  If it's
         restoring r2, then we know we've already saved r2.  We can't
@@ -20323,9 +19951,9 @@ rs6000_emit_prologue (void)
       JUMP_LABEL (jump) = toc_save_done;
       LABEL_NUSES (toc_save_done) += 1;
 
-      save_insn = emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode,
-                                  TOC_REGNUM, sp_offset + 5 * reg_size,
-                                  info->total_size);
+      save_insn = emit_frame_save (frame_reg_rtx, reg_mode,
+                                  TOC_REGNUM, frame_off + 5 * reg_size,
+                                  sp_off - frame_off);
 
       emit_label (toc_save_done);
 
@@ -20338,8 +19966,11 @@ rs6000_emit_prologue (void)
         code that minimizes the number of DW_CFA_advance opcodes better
         freedom in placing the annotations.  */
       note = find_reg_note (save_insn, REG_FRAME_RELATED_EXPR, NULL);
-      gcc_assert (note);
-      remove_note (save_insn, note);
+      if (note)
+       remove_note (save_insn, note);
+      else
+       note = alloc_reg_note (REG_FRAME_RELATED_EXPR,
+                              copy_rtx (PATTERN (save_insn)), NULL_RTX);
       RTX_FRAME_RELATED_P (save_insn) = 0;
 
       join_insn = emit_insn (gen_blockage ());
@@ -20347,24 +19978,29 @@ rs6000_emit_prologue (void)
       RTX_FRAME_RELATED_P (join_insn) = 1;
 
       if (using_static_chain_p)
-       emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
+       {
+         emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
+         END_USE (0);
+       }
+      else
+       END_USE (11);
     }
 
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->cr_save_offset + sp_offset));
+                              GEN_INT (info->cr_save_offset + frame_off));
       rtx mem = gen_frame_mem (SImode, addr);
       /* See the large comment above about why CR2_REGNO is used.  */
       rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
 
-      /* If r12 was used to hold the original sp, copy cr into r0 now
-        that it's free.  */
-      if (REGNO (frame_reg_rtx) == 12)
+      /* If we didn't copy cr before, do so now using r0.  */
+      if (cr_save_rtx == NULL_RTX)
        {
          rtx set;
 
+         START_USE (0);
          cr_save_rtx = gen_rtx_REG (SImode, 0);
          insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
          RTX_FRAME_RELATED_P (insn) = 1;
@@ -20372,8 +20008,9 @@ rs6000_emit_prologue (void)
          add_reg_note (insn, REG_FRAME_RELATED_EXPR, set);
        }
       insn = emit_move_insn (mem, cr_save_rtx);
+      END_USE (REGNO (cr_save_rtx));
 
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+      rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
                            NULL_RTX, NULL_RTX);
     }
 
@@ -20382,21 +20019,38 @@ rs6000_emit_prologue (void)
   if (!WORLD_SAVE_P (info) && info->push_p
       && !(DEFAULT_ABI == ABI_V4 || crtl->calls_eh_return))
     {
-      rtx copy_reg = NULL;
-
-      if (info->total_size < 32767)
-       sp_offset = info->total_size;
-      else if (info->altivec_size != 0
-              || info->vrsave_mask != 0)
-       {
-         copy_reg = frame_ptr_rtx;
-         frame_reg_rtx = copy_reg;
-       }
-      else
-       sp_offset = info->total_size;
-      rs6000_emit_allocate_stack (info->total_size, copy_reg);
+      rtx ptr_reg = NULL;
+      int ptr_off = 0;
+
+      /* If saving altivec regs we need to be able to address all save
+        locations using a 16-bit offset.  */
+      if ((strategy & SAVE_INLINE_VRS) == 0
+         || (info->altivec_size != 0
+             && (info->altivec_save_offset + info->altivec_size - 16
+                 + info->total_size - frame_off) > 32767)
+         || (info->vrsave_mask != 0
+             && (info->vrsave_save_offset
+                 + info->total_size - frame_off) > 32767))
+       {
+         int sel = SAVRES_SAVE | SAVRES_VR;
+         unsigned ptr_regno = ptr_regno_for_savres (sel);
+
+         if (using_static_chain_p
+             && ptr_regno == STATIC_CHAIN_REGNUM)
+           ptr_regno = 12;
+         if (REGNO (frame_reg_rtx) != ptr_regno)
+           START_USE (ptr_regno);
+         ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
+         frame_reg_rtx = ptr_reg;
+         ptr_off = info->altivec_save_offset + info->altivec_size;
+         frame_off = -ptr_off;
+       }
+      else if (REGNO (frame_reg_rtx) == 1)
+       frame_off = info->total_size;
+      rs6000_emit_allocate_stack (info->total_size, ptr_reg, ptr_off);
+      sp_off = info->total_size;
       if (frame_reg_rtx != sp_reg_rtx)
-       rs6000_emit_stack_tie ();
+       rs6000_emit_stack_tie (frame_reg_rtx, false);
     }
 
   /* Set frame pointer, if needed.  */
@@ -20408,36 +20062,72 @@ rs6000_emit_prologue (void)
     }
 
   /* Save AltiVec registers if needed.  Save here because the red zone does
-     not include AltiVec registers.  */
-  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+     not always include AltiVec registers.  */
+  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
+      && info->altivec_size != 0 && (strategy & SAVE_INLINE_VRS) == 0)
+    {
+      int end_save = info->altivec_save_offset + info->altivec_size;
+      int ptr_off;
+      /* Oddly, the vector save/restore functions point r0 at the end
+        of the save area, then use r11 or r12 to load offsets for
+        [reg+reg] addressing.  */
+      rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+      int scratch_regno = ptr_regno_for_savres (SAVRES_SAVE | SAVRES_VR);
+      rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
+
+      gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
+      NOT_INUSE (0);
+      if (end_save + frame_off != 0)
+       {
+         rtx offset = GEN_INT (end_save + frame_off);
+
+         emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+       }
+      else
+       emit_move_insn (ptr_reg, frame_reg_rtx);
+
+      ptr_off = -end_save;
+      insn = rs6000_emit_savres_rtx (info, scratch_reg,
+                                    info->altivec_save_offset + ptr_off,
+                                    0, V4SImode, SAVRES_SAVE | SAVRES_VR);
+      rs6000_frame_related (insn, scratch_reg, sp_off - ptr_off,
+                           NULL_RTX, NULL_RTX);
+      if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
+       {
+         /* The oddity mentioned above clobbered our frame reg.  */
+         emit_move_insn (frame_reg_rtx, ptr_reg);
+         frame_off = ptr_off;
+       }
+    }
+  else if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI
+          && info->altivec_size != 0)
     {
       int i;
 
-      /* There should be a non inline version of this, for when we
-         are saving lots of vector registers.  */
       for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-          {
-            rtx areg, savereg, mem;
-            int offset;
+       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+         {
+           rtx areg, savereg, mem;
+           int offset;
 
-            offset = info->altivec_save_offset + sp_offset
-              + 16 * (i - info->first_altivec_reg_save);
+           offset = (info->altivec_save_offset + frame_off
+                     + 16 * (i - info->first_altivec_reg_save));
 
-            savereg = gen_rtx_REG (V4SImode, i);
+           savereg = gen_rtx_REG (V4SImode, i);
 
-            areg = gen_rtx_REG (Pmode, 0);
-            emit_move_insn (areg, GEN_INT (offset));
+           NOT_INUSE (0);
+           areg = gen_rtx_REG (Pmode, 0);
+           emit_move_insn (areg, GEN_INT (offset));
 
-            /* AltiVec addressing mode is [reg+reg].  */
-            mem = gen_frame_mem (V4SImode,
-                                 gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+           /* AltiVec addressing mode is [reg+reg].  */
+           mem = gen_frame_mem (V4SImode,
+                                gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
 
-            insn = emit_move_insn (mem, savereg);
+           insn = emit_move_insn (mem, savereg);
 
-            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                  areg, GEN_INT (offset));
-          }
+           rs6000_frame_related (insn, frame_reg_rtx, sp_off - frame_off,
+                                 areg, GEN_INT (offset));
+         }
     }
 
   /* VRSAVE is a bit vector representing which AltiVec registers
@@ -20447,31 +20137,39 @@ rs6000_emit_prologue (void)
      used in this function, and do the corresponding magic in the
      epilogue.  */
 
-  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+  if (!WORLD_SAVE_P (info)
+      && TARGET_ALTIVEC
+      && TARGET_ALTIVEC_VRSAVE
       && info->vrsave_mask != 0)
     {
-      rtx reg, mem, vrsave;
+      rtx reg, vrsave;
       int offset;
+      int save_regno;
+
+      /* Get VRSAVE onto a GPR.  Note that ABI_V4 and ABI_DARWIN might
+        be using r12 as frame_reg_rtx and r11 as the static chain
+        pointer for nested functions.  */
+      save_regno = 12;
+      if (DEFAULT_ABI == ABI_AIX && !using_static_chain_p)
+       save_regno = 11;
+      else if (REGNO (frame_reg_rtx) == 12)
+       {
+         save_regno = 11;
+         if (using_static_chain_p)
+           save_regno = 0;
+       }
 
-      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
-         as frame_reg_rtx and r11 as the static chain pointer for
-         nested functions.  */
-      reg = gen_rtx_REG (SImode, 0);
+      NOT_INUSE (save_regno);
+      reg = gen_rtx_REG (SImode, save_regno);
       vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
       if (TARGET_MACHO)
-        emit_insn (gen_get_vrsave_internal (reg));
+       emit_insn (gen_get_vrsave_internal (reg));
       else
-        emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
+       emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
 
-      if (!WORLD_SAVE_P (info))
-        {
-          /* Save VRSAVE.  */
-          offset = info->vrsave_save_offset + sp_offset;
-          mem = gen_frame_mem (SImode,
-                               gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                             GEN_INT (offset)));
-          insn = emit_move_insn (mem, reg);
-        }
+      /* Save VRSAVE.  */
+      offset = info->vrsave_save_offset + frame_off;
+      insn = emit_insn (gen_frame_store (reg, frame_reg_rtx, offset));
 
       /* Include the registers in the mask.  */
       emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
@@ -20498,13 +20196,14 @@ rs6000_emit_prologue (void)
       if (save_LR_around_toc_setup)
        {
          rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+         rtx tmp = gen_rtx_REG (Pmode, 12);
 
-         insn = emit_move_insn (frame_ptr_rtx, lr);
+         insn = emit_move_insn (tmp, lr);
          RTX_FRAME_RELATED_P (insn) = 1;
 
          rs6000_emit_load_toc_table (TRUE);
 
-         insn = emit_move_insn (lr, frame_ptr_rtx);
+         insn = emit_move_insn (lr, tmp);
          add_reg_note (insn, REG_CFA_RESTORE, lr);
          RTX_FRAME_RELATED_P (insn) = 1;
        }
@@ -20548,12 +20247,11 @@ rs6000_emit_prologue (void)
      both in terms of the size of DWARF info and the time taken in the
      unwinder to interpret it.  R2 changes, apart from the
      calls_eh_return case earlier in this function, are handled by
-     linux-unwind.h frob_update_context.  */ 
+     linux-unwind.h frob_update_context.  */
   if (rs6000_save_toc_in_prologue_p ())
     {
-      rtx addr = gen_rtx_PLUS (Pmode, sp_reg_rtx, GEN_INT (5 * reg_size));
-      rtx mem = gen_frame_mem (reg_mode, addr);
-      emit_move_insn (mem, gen_rtx_REG (reg_mode, TOC_REGNUM));
+      rtx reg = gen_rtx_REG (reg_mode, TOC_REGNUM);
+      emit_insn (gen_frame_store (reg, sp_reg_rtx, 5 * reg_size));
     }
 }
 
@@ -20570,37 +20268,30 @@ rs6000_output_function_prologue (FILE *file,
 
   /* Write .extern for any function we will call to save and restore
      fp values.  */
-  if (info->first_fp_reg_save < 64)
+  if (info->first_fp_reg_save < 64
+      && !TARGET_MACHO
+      && !TARGET_ELF)
     {
       char *name;
       int regno = info->first_fp_reg_save - 32;
 
       if ((info->savres_strategy & SAVE_INLINE_FPRS) == 0)
        {
-         name = rs6000_savres_routine_name (info, regno, /*savep=*/true,
-                                            /*gpr=*/false, /*lr=*/false);
+         bool lr = (info->savres_strategy & SAVE_NOINLINE_FPRS_SAVES_LR) != 0;
+         int sel = SAVRES_SAVE | SAVRES_FPR | (lr ? SAVRES_LR : 0);
+         name = rs6000_savres_routine_name (info, regno, sel);
          fprintf (file, "\t.extern %s\n", name);
        }
       if ((info->savres_strategy & REST_INLINE_FPRS) == 0)
        {
-         name = rs6000_savres_routine_name (info, regno, /*savep=*/false,
-                                            /*gpr=*/false, /*lr=*/true);
+         bool lr = (info->savres_strategy
+                    & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
+         int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+         name = rs6000_savres_routine_name (info, regno, sel);
          fprintf (file, "\t.extern %s\n", name);
        }
     }
 
-  /* Write .extern for AIX common mode routines, if needed.  */
-  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
-    {
-      fputs ("\t.extern __mulh\n", file);
-      fputs ("\t.extern __mull\n", file);
-      fputs ("\t.extern __divss\n", file);
-      fputs ("\t.extern __divus\n", file);
-      fputs ("\t.extern __quoss\n", file);
-      fputs ("\t.extern __quous\n", file);
-      common_mode_defined = 1;
-    }
-
   rs6000_pic_labelno++;
 }
 
@@ -20608,10 +20299,37 @@ rs6000_output_function_prologue (FILE *file,
    we restore after the pop when possible.  */
 #define ALWAYS_RESTORE_ALTIVEC_BEFORE_POP 0
 
+/* Restoring cr is a two step process: loading a reg from the frame
+   save, then moving the reg to cr.  For ABI_V4 we must let the
+   unwinder know that the stack location is no longer valid at or
+   before the stack deallocation, but we can't emit a cfa_restore for
+   cr at the stack deallocation like we do for other registers.
+   The trouble is that it is possible for the move to cr to be
+   scheduled after the stack deallocation.  So say exactly where cr
+   is located on each of the two insns.  */
+
+static rtx
+load_cr_save (int regno, rtx frame_reg_rtx, int offset, bool exit_func)
+{
+  rtx mem = gen_frame_mem_offset (SImode, frame_reg_rtx, offset);
+  rtx reg = gen_rtx_REG (SImode, regno);
+  rtx insn = emit_move_insn (reg, mem);
+
+  if (!exit_func && DEFAULT_ABI == ABI_V4)
+    {
+      rtx cr = gen_rtx_REG (SImode, CR2_REGNO);
+      rtx set = gen_rtx_SET (VOIDmode, reg, cr);
+
+      add_reg_note (insn, REG_CFA_REGISTER, set);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+  return reg;
+}
+
 /* Reload CR from REG.  */
 
 static void
-rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple)
+restore_saved_cr (rtx reg, int using_mfcr_multiple, bool exit_func)
 {
   int count = 0;
   int i;
@@ -20619,7 +20337,7 @@ rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple)
   if (using_mfcr_multiple)
     {
       for (i = 0; i < 8; i++)
-       if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
+       if (save_reg_p (CR0_REGNO + i))
          count++;
       gcc_assert (count);
     }
@@ -20633,27 +20351,75 @@ rs6000_restore_saved_cr (rtx reg, int using_mfcr_multiple)
 
       ndx = 0;
       for (i = 0; i < 8; i++)
-       if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
+       if (save_reg_p (CR0_REGNO + i))
          {
            rtvec r = rtvec_alloc (2);
            RTVEC_ELT (r, 0) = reg;
            RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
            RTVEC_ELT (p, ndx) =
-             gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i),
+             gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO + i),
                           gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
            ndx++;
          }
       emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
       gcc_assert (ndx == count);
     }
-  else
-    for (i = 0; i < 8; i++)
-      if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
-       {
-         emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
-                                                      CR0_REGNO+i),
-                                         reg));
-       }
+  else
+    for (i = 0; i < 8; i++)
+      if (save_reg_p (CR0_REGNO + i))
+       emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode, CR0_REGNO + i),
+                                       reg));
+
+  if (!exit_func && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
+    {
+      rtx insn = get_last_insn ();
+      rtx cr = gen_rtx_REG (SImode, CR2_REGNO);
+
+      add_reg_note (insn, REG_CFA_RESTORE, cr);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+}
+
+/* Like cr, the move to lr instruction can be scheduled after the
+   stack deallocation, but unlike cr, its stack frame save is still
+   valid.  So we only need to emit the cfa_restore on the correct
+   instruction.  */
+
+static void
+load_lr_save (int regno, rtx frame_reg_rtx, int offset)
+{
+  rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, offset);
+  rtx reg = gen_rtx_REG (Pmode, regno);
+
+  emit_move_insn (reg, mem);
+}
+
+static void
+restore_saved_lr (int regno, bool exit_func)
+{
+  rtx reg = gen_rtx_REG (Pmode, regno);
+  rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
+  rtx insn = emit_move_insn (lr, reg);
+
+  if (!exit_func && flag_shrink_wrap)
+    {
+      add_reg_note (insn, REG_CFA_RESTORE, lr);
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
+}
+
+static rtx
+add_crlr_cfa_restore (const rs6000_stack_t *info, rtx cfa_restores)
+{
+  if (info->cr_save_p)
+    cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                  gen_rtx_REG (SImode, CR2_REGNO),
+                                  cfa_restores);
+  if (info->lr_save_p)
+    cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                  gen_rtx_REG (Pmode, LR_REGNO),
+                                  cfa_restores);
+  return cfa_restores;
 }
 
 /* Return true if OFFSET from stack pointer can be clobbered by signals.
@@ -20668,6 +20434,20 @@ offset_below_red_zone_p (HOST_WIDE_INT offset)
                   : TARGET_32BIT ? -220 : -288);
 }
 
+/* Append CFA_RESTORES to any existing REG_NOTES on the last insn.  */
+
+static void
+emit_cfa_restores (rtx cfa_restores)
+{
+  rtx insn = get_last_insn ();
+  rtx *loc = &REG_NOTES (insn);
+
+  while (*loc)
+    loc = &XEXP (*loc, 1);
+  *loc = cfa_restores;
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
 /* Emit function epilogue as insns.  */
 
 void
@@ -20681,7 +20461,7 @@ rs6000_emit_epilogue (int sibcall)
   int use_backchain_to_restore_sp;
   int restore_lr;
   int strategy;
-  int sp_offset = 0;
+  HOST_WIDE_INT frame_off = 0;
   rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
   rtx frame_reg_rtx = sp_reg_rtx;
   rtx cfa_restores = NULL_RTX;
@@ -20690,6 +20470,8 @@ rs6000_emit_epilogue (int sibcall)
   enum machine_mode reg_mode = Pmode;
   int reg_size = TARGET_32BIT ? 4 : 8;
   int i;
+  bool exit_func;
+  unsigned ptr_regno;
 
   info = rs6000_stack_info ();
 
@@ -20712,10 +20494,7 @@ rs6000_emit_epilogue (int sibcall)
      here will not trigger at the moment;  We don't actually need a
      frame pointer for alloca, but the generic parts of the compiler
      give us one anyway.  */
-  use_backchain_to_restore_sp = (info->total_size > 32767
-                                || info->total_size
-                                    + (info->lr_save_p ? info->lr_save_offset : 0)
-                                      > 32767
+  use_backchain_to_restore_sp = (info->total_size > 32767 - info->lr_save_offset
                                 || (cfun->calls_alloca
                                     && !frame_pointer_needed));
   restore_lr = (info->lr_save_p
@@ -20762,46 +20541,45 @@ rs6000_emit_epilogue (int sibcall)
 
       {
        /* CR register traditionally saved as CR2.  */
-       rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
-       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                GEN_INT (info->cr_save_offset));
-       rtx mem = gen_frame_mem (reg_mode, addr);
-
-       RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+       rtx reg = gen_rtx_REG (SImode, CR2_REGNO);
+       RTVEC_ELT (p, j++)
+         = gen_frame_load (reg, frame_reg_rtx, info->cr_save_offset);
+       if (flag_shrink_wrap)
+         {
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                          gen_rtx_REG (Pmode, LR_REGNO),
+                                          cfa_restores);
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+         }
       }
 
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
        {
          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->gp_save_offset
-                                           + reg_size * i));
-         rtx mem = gen_frame_mem (reg_mode, addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         RTVEC_ELT (p, j++)
+           = gen_frame_load (reg,
+                             frame_reg_rtx, info->gp_save_offset + reg_size * i);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
        {
          rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->altivec_save_offset
-                                           + 16 * i));
-         rtx mem = gen_frame_mem (V4SImode, addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         RTVEC_ELT (p, j++)
+           = gen_frame_load (reg,
+                             frame_reg_rtx, info->altivec_save_offset + 16 * i);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       for (i = 0; info->first_fp_reg_save + i <= 63; i++)
        {
-         rtx reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                                  ? DFmode : SFmode), 
-                                info->first_fp_reg_save + i);
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->fp_save_offset
-                                           + 8 * i));
-         rtx mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                                    ? DFmode : SFmode), addr);
-
-         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         rtx reg = gen_rtx_REG ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
+                                 ? DFmode : SFmode),
+                                info->first_fp_reg_save + i);
+         RTVEC_ELT (p, j++)
+           = gen_frame_load (reg, frame_reg_rtx, info->fp_save_offset + 8 * i);
+         if (flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
       RTVEC_ELT (p, j++)
        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
@@ -20813,14 +20591,20 @@ rs6000_emit_epilogue (int sibcall)
        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
       RTVEC_ELT (p, j++)
        = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
-      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      insn = emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
 
+      if (flag_shrink_wrap)
+       {
+         REG_NOTES (insn) = cfa_restores;
+         add_reg_note (insn, REG_CFA_DEF_CFA, sp_reg_rtx);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
       return;
     }
 
-  /* frame_reg_rtx + sp_offset points to the top of this stack frame.  */
+  /* frame_reg_rtx + frame_off points to the top of this stack frame.  */
   if (info->push_p)
-    sp_offset = info->total_size;
+    frame_off = info->total_size;
 
   /* Restore AltiVec registers if we must do so before adjusting the
      stack.  */
@@ -20831,39 +20615,80 @@ rs6000_emit_epilogue (int sibcall)
              && offset_below_red_zone_p (info->altivec_save_offset))))
     {
       int i;
+      int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
 
+      gcc_checking_assert (scratch_regno == 11 || scratch_regno == 12);
       if (use_backchain_to_restore_sp)
        {
-         frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+         int frame_regno = 11;
+
+         if ((strategy & REST_INLINE_VRS) == 0)
+           {
+             /* Of r11 and r12, select the one not clobbered by an
+                out-of-line restore function for the frame register.  */
+             frame_regno = 11 + 12 - scratch_regno;
+           }
+         frame_reg_rtx = gen_rtx_REG (Pmode, frame_regno);
          emit_move_insn (frame_reg_rtx,
                          gen_rtx_MEM (Pmode, sp_reg_rtx));
-         sp_offset = 0;
+         frame_off = 0;
        }
       else if (frame_pointer_needed)
        frame_reg_rtx = hard_frame_pointer_rtx;
 
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-         {
-           rtx addr, areg, mem, reg;
+      if ((strategy & REST_INLINE_VRS) == 0)
+       {
+         int end_save = info->altivec_save_offset + info->altivec_size;
+         int ptr_off;
+         rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+         rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
 
-           areg = gen_rtx_REG (Pmode, 0);
-           emit_move_insn
-             (areg, GEN_INT (info->altivec_save_offset
-                             + sp_offset
-                             + 16 * (i - info->first_altivec_reg_save)));
+         if (end_save + frame_off != 0)
+           {
+             rtx offset = GEN_INT (end_save + frame_off);
 
-           /* AltiVec addressing mode is [reg+reg].  */
-           addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-           mem = gen_frame_mem (V4SImode, addr);
-
-           reg = gen_rtx_REG (V4SImode, i);
-           emit_move_insn (reg, mem);
-           if (offset_below_red_zone_p (info->altivec_save_offset
-                                        + (i - info->first_altivec_reg_save)
-                                          * 16))
-             cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                            cfa_restores);
+             emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+           }
+         else
+           emit_move_insn (ptr_reg, frame_reg_rtx);
+
+         ptr_off = -end_save;
+         insn = rs6000_emit_savres_rtx (info, scratch_reg,
+                                        info->altivec_save_offset + ptr_off,
+                                        0, V4SImode, SAVRES_VR);
+       }
+      else
+       {
+         for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+           if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+             {
+               rtx addr, areg, mem, reg;
+
+               areg = gen_rtx_REG (Pmode, 0);
+               emit_move_insn
+                 (areg, GEN_INT (info->altivec_save_offset
+                                 + frame_off
+                                 + 16 * (i - info->first_altivec_reg_save)));
+
+               /* AltiVec addressing mode is [reg+reg].  */
+               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+               mem = gen_frame_mem (V4SImode, addr);
+
+               reg = gen_rtx_REG (V4SImode, i);
+               emit_move_insn (reg, mem);
+             }
+       }
+
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+       if (((strategy & REST_INLINE_VRS) == 0
+            || (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
+           && (flag_shrink_wrap
+               || (offset_below_red_zone_p
+                   (info->altivec_save_offset
+                    + 16 * (i - info->first_altivec_reg_save)))))
+         {
+           rtx reg = gen_rtx_REG (V4SImode, i);
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
          }
     }
 
@@ -20875,7 +20700,7 @@ rs6000_emit_epilogue (int sibcall)
          || (DEFAULT_ABI != ABI_V4
              && offset_below_red_zone_p (info->vrsave_save_offset))))
     {
-      rtx addr, mem, reg;
+      rtx reg;
 
       if (frame_reg_rtx == sp_reg_rtx)
        {
@@ -20884,17 +20709,15 @@ rs6000_emit_epilogue (int sibcall)
              frame_reg_rtx = gen_rtx_REG (Pmode, 11);
              emit_move_insn (frame_reg_rtx,
                              gen_rtx_MEM (Pmode, sp_reg_rtx));
-             sp_offset = 0;
+             frame_off = 0;
            }
          else if (frame_pointer_needed)
            frame_reg_rtx = hard_frame_pointer_rtx;
        }
 
-      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                          GEN_INT (info->vrsave_save_offset + sp_offset));
-      mem = gen_frame_mem (SImode, addr);
       reg = gen_rtx_REG (SImode, 12);
-      emit_move_insn (reg, mem);
+      emit_insn (gen_frame_load (reg, frame_reg_rtx,
+                                info->vrsave_save_offset + frame_off));
 
       emit_insn (generate_set_vrsave (reg, info, 1));
     }
@@ -20913,7 +20736,7 @@ rs6000_emit_epilogue (int sibcall)
 
          insn = emit_move_insn (frame_reg_rtx,
                                 gen_rtx_MEM (Pmode, sp_reg_rtx));
-         sp_offset = 0;
+         frame_off = 0;
        }
       else if (ALWAYS_RESTORE_ALTIVEC_BEFORE_POP
               && DEFAULT_ABI == ABI_V4)
@@ -20935,17 +20758,11 @@ rs6000_emit_epilogue (int sibcall)
       /* Prevent reordering memory accesses against stack pointer restore.  */
       else if (cfun->calls_alloca
               || offset_below_red_zone_p (-info->total_size))
-       {
-         rtx mem1 = gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx);
-         rtx mem2 = gen_rtx_MEM (BLKmode, sp_reg_rtx);
-         MEM_NOTRAP_P (mem1) = 1;
-         MEM_NOTRAP_P (mem2) = 1;
-         emit_insn (gen_frame_tie (mem1, mem2));
-       }
+       rs6000_emit_stack_tie (frame_reg_rtx, true);
 
       insn = emit_insn (gen_add3_insn (frame_reg_rtx, hard_frame_pointer_rtx,
                                       GEN_INT (info->total_size)));
-      sp_offset = 0;
+      frame_off = 0;
     }
   else if (info->push_p
           && DEFAULT_ABI != ABI_V4
@@ -20954,14 +20771,10 @@ rs6000_emit_epilogue (int sibcall)
       /* Prevent reordering memory accesses against stack pointer restore.  */
       if (cfun->calls_alloca
          || offset_below_red_zone_p (-info->total_size))
-       {
-         rtx mem = gen_rtx_MEM (BLKmode, sp_reg_rtx);
-         MEM_NOTRAP_P (mem) = 1;
-         emit_insn (gen_stack_tie (mem));
-       }
+       rs6000_emit_stack_tie (frame_reg_rtx, false);
       insn = emit_insn (gen_add3_insn (sp_reg_rtx, sp_reg_rtx,
                                       GEN_INT (info->total_size)));
-      sp_offset = 0;
+      frame_off = 0;
     }
   if (insn && frame_reg_rtx == sp_reg_rtx)
     {
@@ -20983,26 +20796,94 @@ rs6000_emit_epilogue (int sibcall)
     {
       int i;
 
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-         {
-           rtx addr, areg, mem, reg;
+      if ((strategy & REST_INLINE_VRS) == 0)
+       {
+         int end_save = info->altivec_save_offset + info->altivec_size;
+         int ptr_off;
+         rtx ptr_reg = gen_rtx_REG (Pmode, 0);
+         int scratch_regno = ptr_regno_for_savres (SAVRES_VR);
+         rtx scratch_reg = gen_rtx_REG (Pmode, scratch_regno);
 
-           areg = gen_rtx_REG (Pmode, 0);
-           emit_move_insn
-             (areg, GEN_INT (info->altivec_save_offset
-                             + sp_offset
-                             + 16 * (i - info->first_altivec_reg_save)));
+         if (end_save + frame_off != 0)
+           {
+             rtx offset = GEN_INT (end_save + frame_off);
 
-           /* AltiVec addressing mode is [reg+reg].  */
-           addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
-           mem = gen_frame_mem (V4SImode, addr);
-
-           reg = gen_rtx_REG (V4SImode, i);
-           emit_move_insn (reg, mem);
-           if (DEFAULT_ABI == ABI_V4)
-             cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                            cfa_restores);
+             emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx, offset));
+           }
+         else
+           emit_move_insn (ptr_reg, frame_reg_rtx);
+
+         ptr_off = -end_save;
+         insn = rs6000_emit_savres_rtx (info, scratch_reg,
+                                        info->altivec_save_offset + ptr_off,
+                                        0, V4SImode, SAVRES_VR);
+         if (REGNO (frame_reg_rtx) == REGNO (scratch_reg))
+           {
+             /* Frame reg was clobbered by out-of-line save.  Restore it
+                from ptr_reg, and if we are calling out-of-line gpr or
+                fpr restore set up the correct pointer and offset.  */
+             unsigned newptr_regno = 1;
+             if (!restoring_GPRs_inline)
+               {
+                 bool lr = info->gp_save_offset + info->gp_size == 0;
+                 int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
+                 newptr_regno = ptr_regno_for_savres (sel);
+                 end_save = info->gp_save_offset + info->gp_size;
+               }
+             else if (!restoring_FPRs_inline)
+               {
+                 bool lr = !(strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR);
+                 int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+                 newptr_regno = ptr_regno_for_savres (sel);
+                 end_save = info->gp_save_offset + info->gp_size;
+               }
+
+             if (newptr_regno != 1 && REGNO (frame_reg_rtx) != newptr_regno)
+               frame_reg_rtx = gen_rtx_REG (Pmode, newptr_regno);
+               
+             if (end_save + ptr_off != 0)
+               {
+                 rtx offset = GEN_INT (end_save + ptr_off);
+
+                 frame_off = -end_save;
+                 emit_insn (gen_add3_insn (frame_reg_rtx, ptr_reg, offset));
+               }
+             else
+               {
+                 frame_off = ptr_off;
+                 emit_move_insn (frame_reg_rtx, ptr_reg);
+               }
+           }
+       }
+      else
+       {
+         for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+           if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+             {
+               rtx addr, areg, mem, reg;
+
+               areg = gen_rtx_REG (Pmode, 0);
+               emit_move_insn
+                 (areg, GEN_INT (info->altivec_save_offset
+                                 + frame_off
+                                 + 16 * (i - info->first_altivec_reg_save)));
+
+               /* AltiVec addressing mode is [reg+reg].  */
+               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, areg);
+               mem = gen_frame_mem (V4SImode, addr);
+
+               reg = gen_rtx_REG (V4SImode, i);
+               emit_move_insn (reg, mem);
+             }
+       }
+
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+       if (((strategy & REST_INLINE_VRS) == 0
+            || (info->vrsave_mask & ALTIVEC_REG_BIT (i)) != 0)
+           && (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap))
+         {
+           rtx reg = gen_rtx_REG (V4SImode, i);
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
          }
     }
 
@@ -21014,47 +20895,56 @@ rs6000_emit_epilogue (int sibcall)
       && (DEFAULT_ABI == ABI_V4
          || !offset_below_red_zone_p (info->vrsave_save_offset)))
     {
-      rtx addr, mem, reg;
+      rtx reg;
 
-      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                          GEN_INT (info->vrsave_save_offset + sp_offset));
-      mem = gen_frame_mem (SImode, addr);
       reg = gen_rtx_REG (SImode, 12);
-      emit_move_insn (reg, mem);
+      emit_insn (gen_frame_load (reg, frame_reg_rtx,
+                                info->vrsave_save_offset + frame_off));
 
       emit_insn (generate_set_vrsave (reg, info, 1));
     }
 
+  /* If we exit by an out-of-line restore function on ABI_V4 then that
+     function will deallocate the stack, so we don't need to worry
+     about the unwinder restoring cr from an invalid stack frame
+     location.  */
+  exit_func = (!restoring_FPRs_inline
+              || (!restoring_GPRs_inline
+                  && info->first_fp_reg_save == 64));
+
   /* Get the old lr if we saved it.  If we are restoring registers
      out-of-line, then the out-of-line routines can do this for us.  */
   if (restore_lr && restoring_GPRs_inline)
-    {
-      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
-                                     info->lr_save_offset + sp_offset);
-
-      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
-    }
+    load_lr_save (0, frame_reg_rtx, info->lr_save_offset + frame_off);
 
   /* Get the old cr if we saved it.  */
   if (info->cr_save_p)
     {
-      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->cr_save_offset + sp_offset));
-      rtx mem = gen_frame_mem (SImode, addr);
+      unsigned cr_save_regno = 12;
 
-      cr_save_reg = gen_rtx_REG (SImode,
-                                DEFAULT_ABI == ABI_AIX
-                                && !restoring_GPRs_inline
-                                && info->first_fp_reg_save < 64
-                                ? 11 : 12);
-      emit_move_insn (cr_save_reg, mem);
+      if (!restoring_GPRs_inline)
+       {
+         /* Ensure we don't use the register used by the out-of-line
+            gpr register restore below.  */
+         bool lr = info->gp_save_offset + info->gp_size == 0;
+         int sel = SAVRES_GPR | (lr ? SAVRES_LR : 0);
+         int gpr_ptr_regno = ptr_regno_for_savres (sel);
+
+         if (gpr_ptr_regno == 12)
+           cr_save_regno = 11;
+         gcc_checking_assert (REGNO (frame_reg_rtx) != cr_save_regno);
+       }
+      else if (REGNO (frame_reg_rtx) == 12)
+       cr_save_regno = 11;
+
+      cr_save_reg = load_cr_save (cr_save_regno, frame_reg_rtx,
+                                 info->cr_save_offset + frame_off,
+                                 exit_func);
     }
 
-  /* Set LR here to try to overlap restores below.  LR is always saved
-     above incoming stack, so it never needs REG_CFA_RESTORE.  */
+  /* Set LR here to try to overlap restores below.  */
   if (restore_lr && restoring_GPRs_inline)
-    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
-                   gen_rtx_REG (Pmode, 0));
+    restore_saved_lr (0, exit_func);
 
   /* Load exception handler data registers, if needed.  */
   if (crtl->calls_eh_return)
@@ -21063,11 +20953,9 @@ rs6000_emit_epilogue (int sibcall)
 
       if (TARGET_AIX)
        {
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (sp_offset + 5 * reg_size));
-         rtx mem = gen_frame_mem (reg_mode, addr);
-
-         emit_move_insn (gen_rtx_REG (reg_mode, 2), mem);
+         rtx reg = gen_rtx_REG (reg_mode, 2);
+         emit_insn (gen_frame_load (reg, frame_reg_rtx,
+                                    frame_off + 5 * reg_size));
        }
 
       for (i = 0; ; ++i)
@@ -21078,8 +20966,9 @@ rs6000_emit_epilogue (int sibcall)
          if (regno == INVALID_REGNUM)
            break;
 
+         /* Note: possible use of r0 here to address SPE regs.  */
          mem = gen_frame_mem_offset (reg_mode, frame_reg_rtx,
-                                     info->ehrd_offset + sp_offset
+                                     info->ehrd_offset + frame_off
                                      + reg_size * (int) i);
 
          emit_move_insn (gen_rtx_REG (reg_mode, regno), mem);
@@ -21089,47 +20978,43 @@ rs6000_emit_epilogue (int sibcall)
   /* Restore GPRs.  This is done as a PARALLEL if we are using
      the load-multiple instructions.  */
   if (TARGET_SPE_ABI
-      && info->spe_64bit_regs_used != 0
+      && info->spe_64bit_regs_used
       && info->first_gp_reg_save != 32)
     {
       /* Determine whether we can address all of the registers that need
-         to be saved with an offset from the stack pointer that fits in
-         the small const field for SPE memory instructions.  */
-      int spe_regs_addressable_via_sp
-       = (SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
-                              + (32 - info->first_gp_reg_save - 1) * reg_size)
+        to be saved with an offset from frame_reg_rtx that fits in
+        the small const field for SPE memory instructions.  */
+      int spe_regs_addressable
+       = (SPE_CONST_OFFSET_OK (info->spe_gp_save_offset + frame_off
+                               + reg_size * (32 - info->first_gp_reg_save - 1))
           && restoring_GPRs_inline);
-      int spe_offset;
 
-      if (spe_regs_addressable_via_sp)
-       spe_offset = info->spe_gp_save_offset + sp_offset;
-      else
-        {
+      if (!spe_regs_addressable)
+       {
+         int ool_adjust = 0;
          rtx old_frame_reg_rtx = frame_reg_rtx;
-          /* Make r11 point to the start of the SPE save area.  We worried about
-             not clobbering it when we were saving registers in the prologue.
-             There's no need to worry here because the static chain is passed
-             anew to every function.  */
-         int ool_adjust = (restoring_GPRs_inline
-                           ? 0
-                           : (info->first_gp_reg_save
-                              - (FIRST_SAVRES_REGISTER+1))*8);
-
-         if (frame_reg_rtx == sp_reg_rtx)
-           frame_reg_rtx = gen_rtx_REG (Pmode, 11);
-          emit_insn (gen_addsi3 (frame_reg_rtx, old_frame_reg_rtx,
+         /* Make r11 point to the start of the SPE save area.  We worried about
+            not clobbering it when we were saving registers in the prologue.
+            There's no need to worry here because the static chain is passed
+            anew to every function.  */
+
+         if (!restoring_GPRs_inline)
+           ool_adjust = 8 * (info->first_gp_reg_save
+                             - (FIRST_SAVRES_REGISTER + 1));
+         frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+         emit_insn (gen_addsi3 (frame_reg_rtx, old_frame_reg_rtx,
                                 GEN_INT (info->spe_gp_save_offset
-                                         + sp_offset
+                                         + frame_off
                                          - ool_adjust)));
-         /* Keep the invariant that frame_reg_rtx + sp_offset points
+         /* Keep the invariant that frame_reg_rtx + frame_off points
             at the top of the stack frame.  */
-         sp_offset = -info->spe_gp_save_offset;
-
-          spe_offset = 0;
-        }
+         frame_off = -info->spe_gp_save_offset + ool_adjust;
+       }
 
       if (restoring_GPRs_inline)
        {
+         HOST_WIDE_INT spe_offset = info->spe_gp_save_offset + frame_off;
+
          for (i = 0; i < 32 - info->first_gp_reg_save; i++)
            if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
              {
@@ -21144,202 +21029,158 @@ rs6000_emit_epilogue (int sibcall)
                mem = gen_rtx_MEM (V2SImode, addr);
                reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
 
-               insn = emit_move_insn (reg, mem);
-               if (DEFAULT_ABI == ABI_V4)
-                 {
-                   if (frame_pointer_needed
-                       && info->first_gp_reg_save + i
-                          == HARD_FRAME_POINTER_REGNUM)
-                     {
-                       add_reg_note (insn, REG_CFA_DEF_CFA,
-                                     plus_constant (frame_reg_rtx,
-                                                    sp_offset));
-                       RTX_FRAME_RELATED_P (insn) = 1;
-                     }
-
-                   cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                                  cfa_restores);
-                 }
+               emit_move_insn (reg, mem);
              }
        }
       else
-       {
-         rtx par;
-
-         par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
-                                       0, reg_mode,
-                                       /*savep=*/false, /*gpr=*/true,
-                                       /*lr=*/true);
-         emit_jump_insn (par);
-         /* We don't want anybody else emitting things after we jumped
-            back.  */
-         return;
-       }
+       rs6000_emit_savres_rtx (info, frame_reg_rtx,
+                               info->spe_gp_save_offset + frame_off,
+                               info->lr_save_offset + frame_off,
+                               reg_mode,
+                               SAVRES_GPR | SAVRES_LR);
     }
   else if (!restoring_GPRs_inline)
     {
       /* We are jumping to an out-of-line function.  */
-      bool can_use_exit = info->first_fp_reg_save == 64;
-      rtx par;
+      rtx ptr_reg;
+      int end_save = info->gp_save_offset + info->gp_size;
+      bool can_use_exit = end_save == 0;
+      int sel = SAVRES_GPR | (can_use_exit ? SAVRES_LR : 0);
+      int ptr_off;
 
       /* Emit stack reset code if we need it.  */
+      ptr_regno = ptr_regno_for_savres (sel);
+      ptr_reg = gen_rtx_REG (Pmode, ptr_regno);
       if (can_use_exit)
-       rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
-                                sp_offset, can_use_exit);
-      else
-       {
-         emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX
-                                                       ? 12 : 11),
-                                   frame_reg_rtx,
-                                   GEN_INT (sp_offset - info->fp_size)));
-         if (REGNO (frame_reg_rtx) == 11)
-           sp_offset += info->fp_size;
-       }
-
-      par = rs6000_make_savres_rtx (info, frame_reg_rtx,
-                                   info->gp_save_offset, reg_mode,
-                                   /*savep=*/false, /*gpr=*/true,
-                                   /*lr=*/can_use_exit);
-
-      if (can_use_exit)
-       {
-         if (info->cr_save_p)
-           {
-             rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
-             if (DEFAULT_ABI == ABI_V4)
-               cfa_restores
-                 = alloc_reg_note (REG_CFA_RESTORE,
-                                   gen_rtx_REG (SImode, CR2_REGNO),
-                                   cfa_restores);
-           }
-
-         emit_jump_insn (par);
-
-         /* We don't want anybody else emitting things after we jumped
-            back.  */
-         return;
-       }
-
-      insn = emit_insn (par);
-      if (DEFAULT_ABI == ABI_V4)
-       {
-         if (frame_pointer_needed)
-           {
-             add_reg_note (insn, REG_CFA_DEF_CFA,
-                           plus_constant (frame_reg_rtx, sp_offset));
-             RTX_FRAME_RELATED_P (insn) = 1;
-           }
-
-         for (i = info->first_gp_reg_save; i < 32; i++)
-           cfa_restores
-             = alloc_reg_note (REG_CFA_RESTORE,
-                               gen_rtx_REG (reg_mode, i), cfa_restores);
-       }
+       rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
+      else if (end_save + frame_off != 0)
+       emit_insn (gen_add3_insn (ptr_reg, frame_reg_rtx,
+                                 GEN_INT (end_save + frame_off)));
+      else if (REGNO (frame_reg_rtx) != ptr_regno)
+       emit_move_insn (ptr_reg, frame_reg_rtx);
+      if (REGNO (frame_reg_rtx) == ptr_regno)
+       frame_off = -end_save;
+
+      if (can_use_exit && info->cr_save_p)
+       restore_saved_cr (cr_save_reg, using_mtcr_multiple, true);
+
+      ptr_off = -end_save;
+      rs6000_emit_savres_rtx (info, ptr_reg,
+                             info->gp_save_offset + ptr_off,
+                             info->lr_save_offset + ptr_off,
+                             reg_mode, sel);
     }
   else if (using_load_multiple)
     {
       rtvec p;
       p = rtvec_alloc (32 - info->first_gp_reg_save);
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       {
-         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                  GEN_INT (info->gp_save_offset
-                                           + sp_offset
-                                           + reg_size * i));
-         rtx mem = gen_frame_mem (reg_mode, addr);
-         rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+       RTVEC_ELT (p, i)
+         = gen_frame_load (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                           frame_reg_rtx,
+                           info->gp_save_offset + frame_off + reg_size * i);
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+    }
+  else
+    {
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+       if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+         emit_insn (gen_frame_load
+                    (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                     frame_reg_rtx,
+                     info->gp_save_offset + frame_off + reg_size * i));
+    }
 
-         RTVEC_ELT (p, i) = gen_rtx_SET (VOIDmode, reg, mem);
-         if (DEFAULT_ABI == ABI_V4)
-           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                          cfa_restores);
-       }
-      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
-      if (DEFAULT_ABI == ABI_V4 && frame_pointer_needed)
+  if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+    {
+      /* If the frame pointer was used then we can't delay emitting
+        a REG_CFA_DEF_CFA note.  This must happen on the insn that
+        restores the frame pointer, r31.  We may have already emitted
+        a REG_CFA_DEF_CFA note, but that's OK;  A duplicate is
+        discarded by dwarf2cfi.c/dwarf2out.c, and in any case would
+        be harmless if emitted.  */
+      if (frame_pointer_needed)
        {
+         insn = get_last_insn ();
          add_reg_note (insn, REG_CFA_DEF_CFA,
-                       plus_constant (frame_reg_rtx, sp_offset));
+                       plus_constant (Pmode, frame_reg_rtx, frame_off));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
-    }
-  else
-    {
-      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-        if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+
+      /* Set up cfa_restores.  We always need these when
+        shrink-wrapping.  If not shrink-wrapping then we only need
+        the cfa_restore when the stack location is no longer valid.
+        The cfa_restores must be emitted on or before the insn that
+        invalidates the stack, and of course must not be emitted
+        before the insn that actually does the restore.  The latter
+        is why it is a bad idea to emit the cfa_restores as a group
+        on the last instruction here that actually does a restore:
+        That insn may be reordered with respect to others doing
+        restores.  */
+      if (flag_shrink_wrap
+         && !restoring_GPRs_inline
+         && info->first_fp_reg_save == 64)
+       cfa_restores = add_crlr_cfa_restore (info, cfa_restores);
+
+      for (i = info->first_gp_reg_save; i < 32; i++)
+       if (!restoring_GPRs_inline
+           || using_load_multiple
+           || rs6000_reg_live_or_pic_offset_p (i))
          {
-            rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                     GEN_INT (info->gp_save_offset
-                                              + sp_offset
-                                              + reg_size * i));
-            rtx mem = gen_frame_mem (reg_mode, addr);
-           rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-
-           insn = emit_move_insn (reg, mem);
-           if (DEFAULT_ABI == ABI_V4)
-             {
-               if (frame_pointer_needed
-                   && info->first_gp_reg_save + i
-                      == HARD_FRAME_POINTER_REGNUM)
-                 {
-                   add_reg_note (insn, REG_CFA_DEF_CFA,
-                                 plus_constant (frame_reg_rtx, sp_offset));
-                   RTX_FRAME_RELATED_P (insn) = 1;
-                 }
+           rtx reg = gen_rtx_REG (reg_mode, i);
 
-               cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                              cfa_restores);
-             }
-          }
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+         }
     }
 
-  if (restore_lr && !restoring_GPRs_inline)
+  if (!restoring_GPRs_inline
+      && info->first_fp_reg_save == 64)
     {
-      rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
-                                    info->lr_save_offset + sp_offset);
+      /* We are jumping to an out-of-line function.  */
+      if (cfa_restores)
+       emit_cfa_restores (cfa_restores);
+      return;
+    }
 
-      emit_move_insn (gen_rtx_REG (Pmode, 0), mem);
-      emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
-                     gen_rtx_REG (Pmode, 0));
+  if (restore_lr && !restoring_GPRs_inline)
+    {
+      load_lr_save (0, frame_reg_rtx, info->lr_save_offset + frame_off);
+      restore_saved_lr (0, exit_func);
     }
 
   /* Restore fpr's if we need to do it without calling a function.  */
   if (restoring_FPRs_inline)
     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-      if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
-          && ! call_used_regs[info->first_fp_reg_save+i]))
+      if (save_reg_p (info->first_fp_reg_save + i))
        {
-         rtx addr, mem, reg;
-         addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->fp_save_offset
-                                       + sp_offset
-                                       + 8 * i));
-         mem = gen_frame_mem (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                                ? DFmode : SFmode), addr);
-         reg = gen_rtx_REG (((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT)
-                              ? DFmode : SFmode),
-                            info->first_fp_reg_save + i);
-
-         emit_move_insn (reg, mem);
-         if (DEFAULT_ABI == ABI_V4)
-           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                          cfa_restores);
+         rtx reg = gen_rtx_REG ((TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT
+                                 ? DFmode : SFmode),
+                                info->first_fp_reg_save + i);
+         emit_insn (gen_frame_load (reg, frame_reg_rtx,
+                                    info->fp_save_offset + frame_off + 8 * i));
+         if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
        }
 
   /* If we saved cr, restore it here.  Just those that were used.  */
   if (info->cr_save_p)
+    restore_saved_cr (cr_save_reg, using_mtcr_multiple, exit_func);
+
+  /* If this is V.4, unwind the stack pointer after all of the loads
+     have been done, or set up r11 if we are restoring fp out of line.  */
+  ptr_regno = 1;
+  if (!restoring_FPRs_inline)
     {
-      rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
-      if (DEFAULT_ABI == ABI_V4)
-       cfa_restores
-         = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (SImode, CR2_REGNO),
-                           cfa_restores);
+      bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
+      int sel = SAVRES_FPR | (lr ? SAVRES_LR : 0);
+      ptr_regno = ptr_regno_for_savres (sel);
     }
 
-  /* If this is V.4, unwind the stack pointer after all of the loads
-     have been done.  */
-  insn = rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
-                                 sp_offset, !restoring_FPRs_inline);
-  if (insn)
+  insn = rs6000_emit_stack_reset (info, frame_reg_rtx, frame_off, ptr_regno);
+  if (REGNO (frame_reg_rtx) == ptr_regno)
+    frame_off = 0;
+
+  if (insn && restoring_FPRs_inline)
     {
       if (cfa_restores)
        {
@@ -21361,15 +21202,40 @@ rs6000_emit_epilogue (int sibcall)
       rtvec p;
       bool lr = (strategy & REST_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0;
       if (! restoring_FPRs_inline)
-       p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+       {
+         p = rtvec_alloc (4 + 64 - info->first_fp_reg_save);
+         RTVEC_ELT (p, 0) = ret_rtx;
+       }
       else
-       p = rtvec_alloc (2);
+       {
+         if (cfa_restores)
+           {
+             /* We can't hang the cfa_restores off a simple return,
+                since the shrink-wrap code sometimes uses an existing
+                return.  This means there might be a path from
+                pre-prologue code to this return, and dwarf2cfi code
+                wants the eh_frame unwinder state to be the same on
+                all paths to any point.  So we need to emit the
+                cfa_restores before the return.  For -m64 we really
+                don't need epilogue cfa_restores at all, except for
+                this irritating dwarf2cfi with shrink-wrap
+                requirement;  The stack red-zone means eh_frame info
+                from the prologue telling the unwinder to restore
+                from the stack is perfectly good right to the end of
+                the function.  */
+             emit_insn (gen_blockage ());
+             emit_cfa_restores (cfa_restores);
+             cfa_restores = NULL_RTX;
+           }
+         p = rtvec_alloc (2);
+         RTVEC_ELT (p, 0) = simple_return_rtx;
+       }
 
-      RTVEC_ELT (p, 0) = ret_rtx;
       RTVEC_ELT (p, 1) = ((restoring_FPRs_inline || !lr)
-                         ? gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 65))
+                         ? gen_rtx_USE (VOIDmode,
+                                        gen_rtx_REG (Pmode, LR_REGNO))
                          : gen_rtx_CLOBBER (VOIDmode,
-                                            gen_rtx_REG (Pmode, 65)));
+                                            gen_rtx_REG (Pmode, LR_REGNO)));
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
@@ -21378,10 +21244,11 @@ rs6000_emit_epilogue (int sibcall)
          int i;
          rtx sym;
 
+         if (flag_shrink_wrap)
+           cfa_restores = add_crlr_cfa_restore (info, cfa_restores);
+
          sym = rs6000_savres_routine_sym (info,
-                                          /*savep=*/false,
-                                          /*gpr=*/false,
-                                          /*lr=*/lr);
+                                          SAVRES_FPR | (lr ? SAVRES_LR : 0));
          RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym);
          RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode,
                                          gen_rtx_REG (Pmode,
@@ -21389,20 +21256,28 @@ rs6000_emit_epilogue (int sibcall)
                                                       ? 1 : 11));
          for (i = 0; i < 64 - info->first_fp_reg_save; i++)
            {
-             rtx addr, mem;
-             addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
-                                  GEN_INT (info->fp_save_offset + 8*i));
-             mem = gen_frame_mem (DFmode, addr);
-
-             RTVEC_ELT (p, i+4) =
-               gen_rtx_SET (VOIDmode,
-                            gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
-                            mem);
+             rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+
+             RTVEC_ELT (p, i + 4)
+               = gen_frame_load (reg, sp_reg_rtx, info->fp_save_offset + 8 * i);
+             if (flag_shrink_wrap)
+               cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
+                                              cfa_restores);
            }
        }
 
       emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
+
+  if (cfa_restores)
+    {
+      if (sibcall)
+       /* Ensure the cfa_restores are hung off an insn that won't
+          be reordered above other restores.  */
+       emit_insn (gen_blockage ());
+
+      emit_cfa_restores (cfa_restores);
+    }
 }
 
 /* Write function epilogue.  */
@@ -21417,15 +21292,28 @@ rs6000_output_function_epilogue (FILE *file,
      it looks like we might want one, insert a NOP.  */
   {
     rtx insn = get_last_insn ();
+    rtx deleted_debug_label = NULL_RTX;
     while (insn
           && NOTE_P (insn)
           && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL)
-      insn = PREV_INSN (insn);
+      {
+       /* Don't insert a nop for NOTE_INSN_DELETED_DEBUG_LABEL
+          notes only, instead set their CODE_LABEL_NUMBER to -1,
+          otherwise there would be code generation differences
+          in between -g and -g0.  */
+       if (NOTE_P (insn) && NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL)
+         deleted_debug_label = insn;
+       insn = PREV_INSN (insn);
+      }
     if (insn
        && (LABEL_P (insn)
            || (NOTE_P (insn)
                && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)))
       fputs ("\tnop\n", file);
+    else if (deleted_debug_label)
+      for (insn = deleted_debug_label; insn; insn = NEXT_INSN (insn))
+       if (NOTE_KIND (insn) == NOTE_INSN_DELETED_DEBUG_LABEL)
+         CODE_LABEL_NUMBER (insn) = -1;
   }
 #endif
 
@@ -21767,7 +21655,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                        gen_rtx_USE (VOIDmode,
                                     gen_rtx_REG (SImode,
                                                  LR_REGNO)),
-                       ret_rtx)));
+                       simple_return_rtx)));
   SIBLING_CALL_P (insn) = 1;
   emit_barrier ();
 
@@ -22486,53 +22374,75 @@ output_function_profiler (FILE *file, int labelno)
       fprintf (file, "\tmflr %s\n", reg_names[0]);
       if (NO_PROFILE_COUNTERS)
        {
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %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",
+         if (TARGET_LINK_STACK)
+           {
+             char name[32];
+             get_ppc476_thunk_name (name);
+             asm_fprintf (file, "\tbl %s\n", name);
+           }
+         else
+           asm_fprintf (file, "\tbcl 20,31,1f\n1:\n");
+         asm_fprintf (file, "\tstw %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,",
+         asm_fprintf (file, "\taddis %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]);
+         asm_fprintf (file, "-1b@ha\n\tla %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,4(%s)\n",
+         asm_fprintf (file, "\tstw %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]);
+         asm_fprintf (file, "\tlwz %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@got(%s)\n", reg_names[12]);
        }
       else if (flag_pic > 1)
        {
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          /* Now, we need to get the address of the label.  */
-         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]);
-         asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
+         if (TARGET_LINK_STACK)
+           {
+             char name[32];
+             get_ppc476_thunk_name (name);
+             asm_fprintf (file, "\tbl %s\n\tb 1f\n\t.long ", name);
+             assemble_name (file, buf);
+             fputs ("-.\n1:", file);
+             asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+             asm_fprintf (file, "\taddi %s,%s,4\n",
+                          reg_names[11], reg_names[11]);
+           }
+         else
+           {
+             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]);
+           }
+         asm_fprintf (file, "\tlwz %s,0(%s)\n",
                       reg_names[0], reg_names[11]);
-         asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
+         asm_fprintf (file, "\tadd %s,%s,%s\n",
                       reg_names[0], reg_names[0], reg_names[11]);
        }
       else
        {
-         asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
+         asm_fprintf (file, "\tlis %s,", reg_names[12]);
          assemble_name (file, buf);
          fputs ("@ha\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
-         asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
+         asm_fprintf (file, "\tla %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@l(%s)\n", reg_names[12]);
        }
@@ -22674,7 +22584,7 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
                scheduling pass will not know about this latency since
                the mtctr instruction, which has the latency associated
                to it, will be generated by reload.  */
-            return TARGET_POWER ? 5 : 4;
+            return 4;
           case TYPE_BRANCH:
             /* Leave some extra cycles between a compare and its
                dependent branch, to inhibit expensive mispredicts.  */
@@ -22686,6 +22596,8 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
                  || rs6000_cpu_attr == CPU_PPC750
                  || rs6000_cpu_attr == CPU_PPC7400
                  || rs6000_cpu_attr == CPU_PPC7450
+                 || rs6000_cpu_attr == CPU_PPCE5500
+                 || rs6000_cpu_attr == CPU_PPCE6500
                  || rs6000_cpu_attr == CPU_POWER4
                  || rs6000_cpu_attr == CPU_POWER5
                 || rs6000_cpu_attr == CPU_POWER7
@@ -23055,49 +22967,78 @@ set_to_load_agen (rtx out_insn, rtx in_insn)
   return false;
 }
 
-/* The function returns true if the target storage location of
-   out_insn is adjacent to the target storage location of in_insn */
-/* Return 1 if memory locations are adjacent.  */
+/* Try to determine base/offset/size parts of the given MEM.
+   Return true if successful, false if all the values couldn't
+   be determined.
+
+   This function only looks for REG or REG+CONST address forms.
+   REG+REG address form will return false. */
 
 static bool
-adjacent_mem_locations (rtx insn1, rtx insn2)
+get_memref_parts (rtx mem, rtx *base, HOST_WIDE_INT *offset,
+                 HOST_WIDE_INT *size)
 {
+  rtx addr_rtx;
+  if MEM_SIZE_KNOWN_P (mem)
+    *size = MEM_SIZE (mem);
+  else
+    return false;
 
-  rtx a = get_store_dest (PATTERN (insn1));
-  rtx b = get_store_dest (PATTERN (insn2));
+  if (GET_CODE (XEXP (mem, 0)) == PRE_MODIFY)
+    addr_rtx = XEXP (XEXP (mem, 0), 1);
+  else
+    addr_rtx = (XEXP (mem, 0));
 
-  if ((GET_CODE (XEXP (a, 0)) == REG
-       || (GET_CODE (XEXP (a, 0)) == PLUS
-          && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
-      && (GET_CODE (XEXP (b, 0)) == REG
-         || (GET_CODE (XEXP (b, 0)) == PLUS
-             && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
+  if (GET_CODE (addr_rtx) == REG)
+    {
+      *base = addr_rtx;
+      *offset = 0;
+    }
+  else if (GET_CODE (addr_rtx) == PLUS
+          && CONST_INT_P (XEXP (addr_rtx, 1)))
     {
-      HOST_WIDE_INT val0 = 0, val1 = 0, val_diff;
-      rtx reg0, reg1;
+      *base = XEXP (addr_rtx, 0);
+      *offset = INTVAL (XEXP (addr_rtx, 1));
+    }
+  else
+    return false;
 
-      if (GET_CODE (XEXP (a, 0)) == PLUS)
-        {
-         reg0 = XEXP (XEXP (a, 0), 0);
-         val0 = INTVAL (XEXP (XEXP (a, 0), 1));
-        }
-      else
-       reg0 = XEXP (a, 0);
+  return true;
+}
 
-      if (GET_CODE (XEXP (b, 0)) == PLUS)
-        {
-         reg1 = XEXP (XEXP (b, 0), 0);
-         val1 = INTVAL (XEXP (XEXP (b, 0), 1));
-        }
-      else
-       reg1 = XEXP (b, 0);
+/* The function returns true if the target storage location of
+   mem1 is adjacent to the target storage location of mem2 */
+/* Return 1 if memory locations are adjacent.  */
 
-      val_diff = val1 - val0;
+static bool
+adjacent_mem_locations (rtx mem1, rtx mem2)
+{
+  rtx reg1, reg2;
+  HOST_WIDE_INT off1, size1, off2, size2;
 
-      return ((REGNO (reg0) == REGNO (reg1))
-             && ((MEM_SIZE_KNOWN_P (a) && val_diff == MEM_SIZE (a))
-                 || (MEM_SIZE_KNOWN_P (b) && val_diff == -MEM_SIZE (b))));
-    }
+  if (get_memref_parts (mem1, &reg1, &off1, &size1)
+      && get_memref_parts (mem2, &reg2, &off2, &size2))
+    return ((REGNO (reg1) == REGNO (reg2))
+           && ((off1 + size1 == off2)
+               || (off2 + size2 == off1)));
+
+  return false;
+}
+
+/* This function returns true if it can be determined that the two MEM
+   locations overlap by at least 1 byte based on base reg/offset/size. */
+
+static bool
+mem_locations_overlap (rtx mem1, rtx mem2)
+{
+  rtx reg1, reg2;
+  HOST_WIDE_INT off1, size1, off2, size2;
+
+  if (get_memref_parts (mem1, &reg1, &off1, &size1)
+      && get_memref_parts (mem2, &reg2, &off2, &size2))
+    return ((REGNO (reg1) == REGNO (reg2))
+           && (((off1 <= off2) && (off1 + size1 > off2))
+               || ((off2 <= off1) && (off2 + size2 > off1))));
 
   return false;
 }
@@ -23111,6 +23052,7 @@ adjacent_mem_locations (rtx insn1, rtx insn2)
 static int
 rs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
 {
+  rtx load_mem, str_mem;
   /* On machines (like the 750) which have asymmetric integer units,
      where one integer unit can do multiply and divides and the other
      can't, reduce the priority of multiply/divide so it is scheduled
@@ -23162,8 +23104,8 @@ rs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
     }
 
   if (rs6000_cpu == PROCESSOR_POWER6
-      && ((load_store_pendulum == -2 && is_load_insn (insn))
-          || (load_store_pendulum == 2 && is_store_insn (insn))))
+      && ((load_store_pendulum == -2 && is_load_insn (insn, &load_mem))
+          || (load_store_pendulum == 2 && is_store_insn (insn, &str_mem))))
     /* Attach highest priority to insn if the scheduler has just issued two
        stores and this instruction is a load, or two loads and this instruction
        is a store. Power6 wants loads and stores scheduled alternately
@@ -23215,7 +23157,6 @@ rs6000_issue_rate (void)
     return 1;
 
   switch (rs6000_cpu_attr) {
-  case CPU_RIOS1:  /* ? */
   case CPU_RS64A:
   case CPU_PPC601: /* ? */
   case CPU_PPC7450:
@@ -23225,14 +23166,16 @@ rs6000_issue_rate (void)
   case CPU_PPC750:
   case CPU_PPC7400:
   case CPU_PPC8540:
+  case CPU_PPC8548:
   case CPU_CELL:
   case CPU_PPCE300C2:
   case CPU_PPCE300C3:
   case CPU_PPCE500MC:
   case CPU_PPCE500MC64:
+  case CPU_PPCE5500:
+  case CPU_PPCE6500:
   case CPU_TITAN:
     return 2;
-  case CPU_RIOS2:
   case CPU_PPC476:
   case CPU_PPC604:
   case CPU_PPC604E:
@@ -23253,13 +23196,20 @@ rs6000_issue_rate (void)
    scheduling.  */
 
 static int
-rs6000_use_sched_lookahead (void)
-{
-  if (rs6000_cpu_attr == CPU_PPC8540)
-    return 4;
-  if (rs6000_cpu_attr == CPU_CELL)
-    return (reload_completed ? 8 : 0);
-  return 0;
+rs6000_use_sched_lookahead (void)
+{
+  switch (rs6000_cpu_attr)
+    {
+    case CPU_PPC8540:
+    case CPU_PPC8548:
+      return 4;
+
+    case CPU_CELL:
+      return (reload_completed ? 8 : 0);
+
+    default:
+      return 0;
+    }
 }
 
 /* We are choosing insn from the ready queue.  Return nonzero if INSN can be chosen.  */
@@ -23280,55 +23230,63 @@ rs6000_use_sched_lookahead_guard (rtx insn)
   return 1;
 }
 
-/* Determine is PAT refers to memory.  */
+/* Determine if PAT refers to memory. If so, set MEM_REF to the MEM rtx
+   and return true.  */
 
 static bool
-is_mem_ref (rtx pat)
+find_mem_ref (rtx pat, rtx *mem_ref)
 {
   const char * fmt;
   int i, j;
-  bool ret = false;
 
   /* stack_tie does not produce any real memory traffic.  */
-  if (GET_CODE (pat) == UNSPEC
-      && XINT (pat, 1) == UNSPEC_TIE)
+  if (tie_operand (pat, VOIDmode))
     return false;
 
   if (GET_CODE (pat) == MEM)
-    return true;
+    {
+      *mem_ref = pat;
+      return true;
+    }
 
   /* Recursively process the pattern.  */
   fmt = GET_RTX_FORMAT (GET_CODE (pat));
 
-  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
     {
       if (fmt[i] == 'e')
-       ret |= is_mem_ref (XEXP (pat, i));
+       {
+         if (find_mem_ref (XEXP (pat, i), mem_ref))
+           return true;
+       }
       else if (fmt[i] == 'E')
        for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
-         ret |= is_mem_ref (XVECEXP (pat, i, j));
+         {
+           if (find_mem_ref (XVECEXP (pat, i, j), mem_ref))
+             return true;
+         }
     }
 
-  return ret;
+  return false;
 }
 
 /* Determine if PAT is a PATTERN of a load insn.  */
 
 static bool
-is_load_insn1 (rtx pat)
+is_load_insn1 (rtx pat, rtx *load_mem)
 {
   if (!pat || pat == NULL_RTX)
     return false;
 
   if (GET_CODE (pat) == SET)
-    return is_mem_ref (SET_SRC (pat));
+    return find_mem_ref (SET_SRC (pat), load_mem);
 
   if (GET_CODE (pat) == PARALLEL)
     {
       int i;
 
       for (i = 0; i < XVECLEN (pat, 0); i++)
-       if (is_load_insn1 (XVECEXP (pat, 0, i)))
+       if (is_load_insn1 (XVECEXP (pat, 0, i), load_mem))
          return true;
     }
 
@@ -23338,7 +23296,7 @@ is_load_insn1 (rtx pat)
 /* Determine if INSN loads from memory.  */
 
 static bool
-is_load_insn (rtx insn)
+is_load_insn (rtx insn, rtx *load_mem)
 {
   if (!insn || !INSN_P (insn))
     return false;
@@ -23346,26 +23304,26 @@ is_load_insn (rtx insn)
   if (GET_CODE (insn) == CALL_INSN)
     return false;
 
-  return is_load_insn1 (PATTERN (insn));
+  return is_load_insn1 (PATTERN (insn), load_mem);
 }
 
 /* Determine if PAT is a PATTERN of a store insn.  */
 
 static bool
-is_store_insn1 (rtx pat)
+is_store_insn1 (rtx pat, rtx *str_mem)
 {
   if (!pat || pat == NULL_RTX)
     return false;
 
   if (GET_CODE (pat) == SET)
-    return is_mem_ref (SET_DEST (pat));
+    return find_mem_ref (SET_DEST (pat), str_mem);
 
   if (GET_CODE (pat) == PARALLEL)
     {
       int i;
 
       for (i = 0; i < XVECLEN (pat, 0); i++)
-       if (is_store_insn1 (XVECEXP (pat, 0, i)))
+       if (is_store_insn1 (XVECEXP (pat, 0, i), str_mem))
          return true;
     }
 
@@ -23375,38 +23333,12 @@ is_store_insn1 (rtx pat)
 /* Determine if INSN stores to memory.  */
 
 static bool
-is_store_insn (rtx insn)
+is_store_insn (rtx insn, rtx *str_mem)
 {
   if (!insn || !INSN_P (insn))
     return false;
 
-  return is_store_insn1 (PATTERN (insn));
-}
-
-/* Return the dest of a store insn.  */
-
-static rtx
-get_store_dest (rtx pat)
-{
-  gcc_assert (is_store_insn1 (pat));
-
-  if (GET_CODE (pat) == SET)
-    return SET_DEST (pat);
-  else if (GET_CODE (pat) == PARALLEL)
-    {
-      int i;
-
-      for (i = 0; i < XVECLEN (pat, 0); i++)
-       {
-         rtx inner_pat = XVECEXP (pat, 0, i);
-         if (GET_CODE (inner_pat) == SET
-             && is_mem_ref (SET_DEST (inner_pat)))
-           return inner_pat;
-       }
-    }
-  /* We shouldn't get here, because we should have either a simple
-     store insn or a store with update which are covered above.  */
-  gcc_unreachable();
+  return is_store_insn1 (PATTERN (insn), str_mem);
 }
 
 /* Returns whether the dependence between INSN and NEXT is considered
@@ -23417,6 +23349,7 @@ rs6000_is_costly_dependence (dep_t dep, int cost, int distance)
 {
   rtx insn;
   rtx next;
+  rtx load_mem, str_mem;
 
   /* If the flag is not enabled - no dependence is considered costly;
      allow all dependent insns in the same group.
@@ -23434,15 +23367,16 @@ rs6000_is_costly_dependence (dep_t dep, int cost, int distance)
   next = DEP_CON (dep);
 
   if (rs6000_sched_costly_dep == store_to_load_dep_costly
-      && is_load_insn (next)
-      && is_store_insn (insn))
+      && is_load_insn (next, &load_mem)
+      && is_store_insn (insn, &str_mem))
     /* Prevent load after store in the same group.  */
     return true;
 
   if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
-      && is_load_insn (next)
-      && is_store_insn (insn)
-      && DEP_TYPE (dep) == REG_DEP_TRUE)
+      && is_load_insn (next, &load_mem)
+      && is_store_insn (insn, &str_mem)
+      && DEP_TYPE (dep) == REG_DEP_TRUE
+      && mem_locations_overlap(str_mem, load_mem))
      /* Prevent load after store in the same group if it is a true
        dependence.  */
      return true;
@@ -23569,12 +23503,12 @@ rs6000_sched_reorder2 (FILE *dump, int sched_verbose, rtx *ready,
     {
       int pos;
       int i;
-      rtx tmp;
+      rtx tmp, load_mem, str_mem;
 
-      if (is_store_insn (last_scheduled_insn))
+      if (is_store_insn (last_scheduled_insn, &str_mem))
         /* Issuing a store, swing the load_store_pendulum to the left */
         load_store_pendulum--;
-      else if (is_load_insn (last_scheduled_insn))
+      else if (is_load_insn (last_scheduled_insn, &load_mem))
         /* Issuing a load, swing the load_store_pendulum to the right */
         load_store_pendulum++;
       else
@@ -23593,7 +23527,7 @@ rs6000_sched_reorder2 (FILE *dump, int sched_verbose, rtx *ready,
 
           while (pos >= 0)
             {
-              if (is_load_insn (ready[pos]))
+              if (is_load_insn (ready[pos], &load_mem))
                 {
                   /* Found a load.  Move it to the head of the ready list,
                      and adjust it's priority so that it is more likely to
@@ -23619,7 +23553,7 @@ rs6000_sched_reorder2 (FILE *dump, int sched_verbose, rtx *ready,
 
           while (pos >= 0)
             {
-              if (is_load_insn (ready[pos])
+              if (is_load_insn (ready[pos], &load_mem)
                   && !sel_sched_p ()
                  && INSN_PRIORITY_KNOWN (ready[pos]))
                 {
@@ -23646,15 +23580,16 @@ rs6000_sched_reorder2 (FILE *dump, int sched_verbose, rtx *ready,
 
           while (pos >= 0)
             {
-              if (is_store_insn (ready[pos]))
+              if (is_store_insn (ready[pos], &str_mem))
                 {
+                 rtx str_mem2;
                   /* Maintain the index of the first store found on the
                      list */
                   if (first_store_pos == -1)
                     first_store_pos = pos;
 
-                  if (is_store_insn (last_scheduled_insn)
-                      && adjacent_mem_locations (last_scheduled_insn,ready[pos]))
+                  if (is_store_insn (last_scheduled_insn, &str_mem2)
+                      && adjacent_mem_locations (str_mem, str_mem2))
                     {
                       /* Found an adjacent store.  Move it to the head of the
                          ready list, and adjust it's priority so that it is
@@ -23698,7 +23633,7 @@ rs6000_sched_reorder2 (FILE *dump, int sched_verbose, rtx *ready,
 
           while (pos >= 0)
             {
-              if (is_store_insn (ready[pos])
+              if (is_store_insn (ready[pos], &str_mem)
                   && !sel_sched_p ()
                  && INSN_PRIORITY_KNOWN (ready[pos]))
                 {
@@ -23982,7 +23917,7 @@ is_costly_group (rtx *group_insns, rtx next_insn)
       if (!insn)
        continue;
 
-      FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
+      FOR_EACH_DEP (insn, SD_LIST_RES_FORW, sd_it, dep)
        {
          rtx next = DEP_CON (dep);
 
@@ -24046,12 +23981,20 @@ force_new_group (int sched_verbose, FILE *dump, rtx *group_insns,
       if (can_issue_more && !is_branch_slot_insn (next_insn))
        can_issue_more--;
 
-      while (can_issue_more > 0)
+      /* Power6 and Power7 have special group ending nop. */
+      if (rs6000_cpu_attr == CPU_POWER6 || rs6000_cpu_attr == CPU_POWER7)
        {
-         nop = gen_nop ();
+         nop = gen_group_ending_nop ();
          emit_insn_before (nop, next_insn);
-         can_issue_more--;
+         can_issue_more = 0;
        }
+      else
+       while (can_issue_more > 0)
+         {
+           nop = gen_nop ();
+           emit_insn_before (nop, next_insn);
+           can_issue_more--;
+         }
 
       *group_end = true;
       return 0;
@@ -24442,7 +24385,8 @@ rs6000_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
        rtx fnmem, fn_reg, toc_reg;
 
        if (!TARGET_POINTERS_TO_NESTED_FUNCTIONS)
-         error ("-mno-r11 must not be used if you have trampolines");
+         error ("You cannot take the address of a nested function if you use "
+                "the -mno-pointers-to-nested-functions option.");
 
        fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
        fn_reg = gen_reg_rtx (Pmode);
@@ -24826,6 +24770,7 @@ rs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
    function descriptor name.  This saves a lot of overriding code to
    read the prefixes.  */
 
+static void rs6000_elf_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED;
 static void
 rs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
 {
@@ -24982,7 +24927,7 @@ macho_branch_islands (void)
 
   while (!VEC_empty (branch_island, branch_islands))
     {
-      branch_island *bi = VEC_last (branch_island, branch_islands);
+      branch_island *bi = &VEC_last (branch_island, branch_islands);
       const char *label = IDENTIFIER_POINTER (bi->label_name);
       const char *name = IDENTIFIER_POINTER (bi->function_name);
       char name_buf[512];
@@ -25002,11 +24947,24 @@ macho_branch_islands (void)
 #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
       if (flag_pic)
        {
-         strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
-         strcat (tmp_buf, label);
-         strcat (tmp_buf, "_pic\n");
-         strcat (tmp_buf, label);
-         strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+         if (TARGET_LINK_STACK)
+           {
+             char name[32];
+             get_ppc476_thunk_name (name);
+             strcat (tmp_buf, ":\n\tmflr r0\n\tbl ");
+             strcat (tmp_buf, name);
+             strcat (tmp_buf, "\n");
+             strcat (tmp_buf, label);
+             strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+           }
+         else
+           {
+             strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
+             strcat (tmp_buf, label);
+             strcat (tmp_buf, "_pic\n");
+             strcat (tmp_buf, label);
+             strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+           }
 
          strcat (tmp_buf, "\taddis r11,r11,ha16(");
          strcat (tmp_buf, name_buf);
@@ -25152,8 +25110,18 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       sprintf (local_label_0, "\"L%011d$spb\"", label);
 
       fprintf (file, "\tmflr r0\n");
-      fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
-      fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+      if (TARGET_LINK_STACK)
+       {
+         char name[32];
+         get_ppc476_thunk_name (name);
+         fprintf (file, "\tbl %s\n", name);
+         fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+       }
+      else
+       {
+         fprintf (file, "\tbcl 20,31,%s\n", local_label_0);
+         fprintf (file, "%s:\n\tmflr r11\n", local_label_0);
+       }
       fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
               lazy_ptr_name, local_label_0);
       fprintf (file, "\tmtlr r0\n");
@@ -25223,7 +25191,7 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
       if (GET_CODE (offset) == CONST_INT)
        {
          if (SMALL_INT (offset))
-           return plus_constant (base, INTVAL (offset));
+           return plus_constant (Pmode, base, INTVAL (offset));
          else if (! reload_in_progress && ! reload_completed)
            offset = force_reg (Pmode, offset);
          else
@@ -25315,6 +25283,7 @@ rs6000_elf_reloc_rw_mask (void)
    This differs from default_named_section_asm_out_constructor in
    that we have special handling for -mrelocatable.  */
 
+static void rs6000_elf_asm_out_constructor (rtx, int) ATTRIBUTE_UNUSED;
 static void
 rs6000_elf_asm_out_constructor (rtx symbol, int priority)
 {
@@ -25344,6 +25313,7 @@ rs6000_elf_asm_out_constructor (rtx symbol, int priority)
     assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1);
 }
 
+static void rs6000_elf_asm_out_destructor (rtx, int) ATTRIBUTE_UNUSED;
 static void
 rs6000_elf_asm_out_destructor (rtx symbol, int priority)
 {
@@ -25449,6 +25419,7 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
   ASM_OUTPUT_LABEL (file, name);
 }
 
+static void rs6000_elf_file_end (void) ATTRIBUTE_UNUSED;
 static void
 rs6000_elf_file_end (void)
 {
@@ -25470,7 +25441,7 @@ rs6000_elf_file_end (void)
                 aix_struct_return ? 2 : 1);
     }
 #endif
-#ifdef POWERPC_LINUX
+#if defined (POWERPC_LINUX) || defined (POWERPC_FREEBSD)
   if (TARGET_32BIT)
     file_end_indicate_exec_stack ();
 #endif
@@ -25669,7 +25640,7 @@ rs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
   unsigned int flags = default_section_type_flags (decl, name, reloc);
 
   /* Align to at least UNIT size.  */
-  if (flags & SECTION_CODE)
+  if (flags & SECTION_CODE || !decl)
     align = MIN_UNITS_PER_WORD;
   else
     /* Increase alignment of large objects if not already stricter.  */
@@ -25733,8 +25704,8 @@ rs6000_xcoff_file_end (void)
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-rs6000_rtx_costs (rtx x, int code, int outer_code, int *total,
-                 bool speed)
+rs6000_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+                 int *total, bool speed)
 {
   enum machine_mode mode = GET_MODE (x);
 
@@ -26077,17 +26048,18 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total,
 /* Debug form of r6000_rtx_costs that is selected if -mdebug=cost.  */
 
 static bool
-rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int *total,
+rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
                        bool speed)
 {
-  bool ret = rs6000_rtx_costs (x, code, outer_code, total, speed);
+  bool ret = rs6000_rtx_costs (x, code, outer_code, opno, total, speed);
 
   fprintf (stderr,
           "\nrs6000_rtx_costs, return = %s, code = %s, outer_code = %s, "
-          "total = %d, speed = %s, x:\n",
+          "opno = %d, total = %d, speed = %s, x:\n",
           ret ? "complete" : "scan inner",
           GET_RTX_NAME (code),
           GET_RTX_NAME (outer_code),
+          opno,
           *total,
           speed ? "true" : "false");
 
@@ -26099,7 +26071,8 @@ rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int *total,
 /* Debug form of ADDRESS_COST that is selected if -mdebug=cost.  */
 
 static int
-rs6000_debug_address_cost (rtx x, bool speed)
+rs6000_debug_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
+                          addr_space_t as ATTRIBUTE_UNUSED, bool speed)
 {
   int ret = TARGET_ADDRESS_COST (x, speed);
 
@@ -26231,13 +26204,13 @@ rs6000_builtin_reciprocal (unsigned int fn, bool md_fn,
        if (!RS6000_RECIP_AUTO_RSQRTE_P (V2DFmode))
          return NULL_TREE;
 
-       return rs6000_builtin_decls[VSX_BUILTIN_VEC_RSQRT_V2DF];
+       return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_2DF];
 
       case VSX_BUILTIN_XVSQRTSP:
        if (!RS6000_RECIP_AUTO_RSQRTE_P (V4SFmode))
          return NULL_TREE;
 
-       return rs6000_builtin_decls[VSX_BUILTIN_VEC_RSQRT_V4SF];
+       return rs6000_builtin_decls[VSX_BUILTIN_RSQRT_4SF];
 
       default:
        return NULL_TREE;
@@ -26634,6 +26607,327 @@ rs6000_emit_parity (rtx dst, rtx src)
     }
 }
 
+/* Expand an Altivec constant permutation.  Return true if we match
+   an efficient implementation; false to fall back to VPERM.  */
+
+bool
+altivec_expand_vec_perm_const (rtx operands[4])
+{
+  struct altivec_perm_insn {
+    enum insn_code impl;
+    unsigned char perm[16];
+  };
+  static const struct altivec_perm_insn patterns[] = {
+    { CODE_FOR_altivec_vpkuhum,
+      {  1,  3,  5,  7,  9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31 } },
+    { CODE_FOR_altivec_vpkuwum,
+      {  2,  3,  6,  7, 10, 11, 14, 15, 18, 19, 22, 23, 26, 27, 30, 31 } },
+    { CODE_FOR_altivec_vmrghb,
+      {  0, 16,  1, 17,  2, 18,  3, 19,  4, 20,  5, 21,  6, 22,  7, 23 } },
+    { CODE_FOR_altivec_vmrghh,
+      {  0,  1, 16, 17,  2,  3, 18, 19,  4,  5, 20, 21,  6,  7, 22, 23 } },
+    { CODE_FOR_altivec_vmrghw,
+      {  0,  1,  2,  3, 16, 17, 18, 19,  4,  5,  6,  7, 20, 21, 22, 23 } },
+    { CODE_FOR_altivec_vmrglb,
+      {  8, 24,  9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31 } },
+    { CODE_FOR_altivec_vmrglh,
+      {  8,  9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31 } },
+    { CODE_FOR_altivec_vmrglw,
+      {  8,  9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31 } }
+  };
+
+  unsigned int i, j, elt, which;
+  unsigned char perm[16];
+  rtx target, op0, op1, sel, x;
+  bool one_vec;
+
+  target = operands[0];
+  op0 = operands[1];
+  op1 = operands[2];
+  sel = operands[3];
+
+  /* Unpack the constant selector.  */
+  for (i = which = 0; i < 16; ++i)
+    {
+      rtx e = XVECEXP (sel, 0, i);
+      elt = INTVAL (e) & 31;
+      which |= (elt < 16 ? 1 : 2);
+      perm[i] = elt;
+    }
+
+  /* Simplify the constant selector based on operands.  */
+  switch (which)
+    {
+    default:
+      gcc_unreachable ();
+
+    case 3:
+      one_vec = false;
+      if (!rtx_equal_p (op0, op1))
+       break;
+      /* FALLTHRU */
+
+    case 2:
+      for (i = 0; i < 16; ++i)
+       perm[i] &= 15;
+      op0 = op1;
+      one_vec = true;
+      break;
+
+    case 1:
+      op1 = op0;
+      one_vec = true;
+      break;
+    }
+  /* Look for splat patterns.  */
+  if (one_vec)
+    {
+      elt = perm[0];
+
+      for (i = 0; i < 16; ++i)
+       if (perm[i] != elt)
+         break;
+      if (i == 16)
+       {
+         emit_insn (gen_altivec_vspltb (target, op0, GEN_INT (elt)));
+         return true;
+       }
+
+      if (elt % 2 == 0)
+       {
+         for (i = 0; i < 16; i += 2)
+           if (perm[i] != elt || perm[i + 1] != elt + 1)
+             break;
+         if (i == 16)
+           {
+             x = gen_reg_rtx (V8HImode);
+             emit_insn (gen_altivec_vsplth (x, gen_lowpart (V8HImode, op0),
+                                            GEN_INT (elt / 2)));
+             emit_move_insn (target, gen_lowpart (V16QImode, x));
+             return true;
+           }
+       }
+
+      if (elt % 4 == 0)
+       {
+         for (i = 0; i < 16; i += 4)
+           if (perm[i] != elt
+               || perm[i + 1] != elt + 1
+               || perm[i + 2] != elt + 2
+               || perm[i + 3] != elt + 3)
+             break;
+         if (i == 16)
+           {
+             x = gen_reg_rtx (V4SImode);
+             emit_insn (gen_altivec_vspltw (x, gen_lowpart (V4SImode, op0),
+                                            GEN_INT (elt / 4)));
+             emit_move_insn (target, gen_lowpart (V16QImode, x));
+             return true;
+           }
+       }
+    }
+
+  /* Look for merge and pack patterns.  */
+  for (j = 0; j < ARRAY_SIZE (patterns); ++j)
+    {
+      bool swapped;
+
+      elt = patterns[j].perm[0];
+      if (perm[0] == elt)
+       swapped = false;
+      else if (perm[0] == elt + 16)
+       swapped = true;
+      else
+       continue;
+      for (i = 1; i < 16; ++i)
+       {
+         elt = patterns[j].perm[i];
+         if (swapped)
+           elt = (elt >= 16 ? elt - 16 : elt + 16);
+         else if (one_vec && elt >= 16)
+           elt -= 16;
+         if (perm[i] != elt)
+           break;
+       }
+      if (i == 16)
+       {
+         enum insn_code icode = patterns[j].impl;
+         enum machine_mode omode = insn_data[icode].operand[0].mode;
+         enum machine_mode imode = insn_data[icode].operand[1].mode;
+
+         if (swapped)
+           x = op0, op0 = op1, op1 = x;
+         if (imode != V16QImode)
+           {
+             op0 = gen_lowpart (imode, op0);
+             op1 = gen_lowpart (imode, op1);
+           }
+         if (omode == V16QImode)
+           x = target;
+         else
+           x = gen_reg_rtx (omode);
+         emit_insn (GEN_FCN (icode) (x, op0, op1));
+         if (omode != V16QImode)
+           emit_move_insn (target, gen_lowpart (V16QImode, x));
+         return true;
+       }
+    }
+
+  return false;
+}
+
+/* Expand a Paired Single, VSX Permute Doubleword, or SPE constant permutation.
+   Return true if we match an efficient implementation.  */
+
+static bool
+rs6000_expand_vec_perm_const_1 (rtx target, rtx op0, rtx op1,
+                               unsigned char perm0, unsigned char perm1)
+{
+  rtx x;
+
+  /* If both selectors come from the same operand, fold to single op.  */
+  if ((perm0 & 2) == (perm1 & 2))
+    {
+      if (perm0 & 2)
+       op0 = op1;
+      else
+       op1 = op0;
+    }
+  /* If both operands are equal, fold to simpler permutation.  */
+  if (rtx_equal_p (op0, op1))
+    {
+      perm0 = perm0 & 1;
+      perm1 = (perm1 & 1) + 2;
+    }
+  /* If the first selector comes from the second operand, swap.  */
+  else if (perm0 & 2)
+    {
+      if (perm1 & 2)
+       return false;
+      perm0 -= 2;
+      perm1 += 2;
+      x = op0, op0 = op1, op1 = x;
+    }
+  /* If the second selector does not come from the second operand, fail.  */
+  else if ((perm1 & 2) == 0)
+    return false;
+
+  /* Success! */
+  if (target != NULL)
+    {
+      enum machine_mode vmode, dmode;
+      rtvec v;
+
+      vmode = GET_MODE (target);
+      gcc_assert (GET_MODE_NUNITS (vmode) == 2);
+      dmode = mode_for_vector (GET_MODE_INNER (vmode), 4);
+
+      x = gen_rtx_VEC_CONCAT (dmode, op0, op1);
+      v = gen_rtvec (2, GEN_INT (perm0), GEN_INT (perm1));
+      x = gen_rtx_VEC_SELECT (vmode, x, gen_rtx_PARALLEL (VOIDmode, v));
+      emit_insn (gen_rtx_SET (VOIDmode, target, x));
+    }
+  return true;
+}
+
+bool
+rs6000_expand_vec_perm_const (rtx operands[4])
+{
+  rtx target, op0, op1, sel;
+  unsigned char perm0, perm1;
+
+  target = operands[0];
+  op0 = operands[1];
+  op1 = operands[2];
+  sel = operands[3];
+
+  /* Unpack the constant selector.  */
+  perm0 = INTVAL (XVECEXP (sel, 0, 0)) & 3;
+  perm1 = INTVAL (XVECEXP (sel, 0, 1)) & 3;
+
+  return rs6000_expand_vec_perm_const_1 (target, op0, op1, perm0, perm1);
+}
+
+/* Test whether a constant permutation is supported.  */
+
+static bool
+rs6000_vectorize_vec_perm_const_ok (enum machine_mode vmode,
+                                   const unsigned char *sel)
+{
+  /* AltiVec (and thus VSX) can handle arbitrary permutations.  */
+  if (TARGET_ALTIVEC)
+    return true;
+
+  /* Check for ps_merge* or evmerge* insns.  */
+  if ((TARGET_PAIRED_FLOAT && vmode == V2SFmode)
+      || (TARGET_SPE && vmode == V2SImode))
+    {
+      rtx op0 = gen_raw_REG (vmode, LAST_VIRTUAL_REGISTER + 1);
+      rtx op1 = gen_raw_REG (vmode, LAST_VIRTUAL_REGISTER + 2);
+      return rs6000_expand_vec_perm_const_1 (NULL, op0, op1, sel[0], sel[1]);
+    }
+
+  return false;
+}
+
+/* A subroutine for rs6000_expand_extract_even & rs6000_expand_interleave.  */
+
+static void
+rs6000_do_expand_vec_perm (rtx target, rtx op0, rtx op1,
+                          enum machine_mode vmode, unsigned nelt, rtx perm[])
+{
+  enum machine_mode imode;
+  rtx x;
+
+  imode = vmode;
+  if (GET_MODE_CLASS (vmode) != MODE_VECTOR_INT)
+    {
+      imode = GET_MODE_INNER (vmode);
+      imode = mode_for_size (GET_MODE_BITSIZE (imode), MODE_INT, 0);
+      imode = mode_for_vector (imode, nelt);
+    }
+
+  x = gen_rtx_CONST_VECTOR (imode, gen_rtvec_v (nelt, perm));
+  x = expand_vec_perm (vmode, op0, op1, x, target);
+  if (x != target)
+    emit_move_insn (target, x);
+}
+
+/* Expand an extract even operation.  */
+
+void
+rs6000_expand_extract_even (rtx target, rtx op0, rtx op1)
+{
+  enum machine_mode vmode = GET_MODE (target);
+  unsigned i, nelt = GET_MODE_NUNITS (vmode);
+  rtx perm[16];
+
+  for (i = 0; i < nelt; i++)
+    perm[i] = GEN_INT (i * 2);
+
+  rs6000_do_expand_vec_perm (target, op0, op1, vmode, nelt, perm);
+}
+
+/* Expand a vector interleave operation.  */
+
+void
+rs6000_expand_interleave (rtx target, rtx op0, rtx op1, bool highp)
+{
+  enum machine_mode vmode = GET_MODE (target);
+  unsigned i, high, nelt = GET_MODE_NUNITS (vmode);
+  rtx perm[16];
+
+  high = (highp == BYTES_BIG_ENDIAN ? 0 : nelt / 2);
+  for (i = 0; i < nelt / 2; i++)
+    {
+      perm[i * 2] = GEN_INT (i + high);
+      perm[i * 2 + 1] = GEN_INT (i + nelt + high);
+    }
+
+  rs6000_do_expand_vec_perm (target, op0, op1, vmode, nelt, perm);
+}
+
 /* Return an RTX representing where to find the function value of a
    function returning MODE.  */
 static rtx
@@ -26672,7 +26966,7 @@ rs6000_complex_function_value (enum machine_mode mode)
    On RS/6000 an integer value is in r3 and a floating-point value is in
    fp1, unless -msoft-float.  */
 
-rtx
+static rtx
 rs6000_function_value (const_tree valtype,
                       const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
                       bool outgoing ATTRIBUTE_UNUSED)
@@ -26819,7 +27113,7 @@ rs6000_libcall_value (enum machine_mode mode)
    We need r30 if -mminimal-toc was specified, and there are constant pool
    references.  */
 
-bool
+static bool
 rs6000_can_eliminate (const int from, const int to)
 {
   return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
@@ -26933,8 +27227,6 @@ rs6000_dbx_register_number (unsigned int regno)
 {
   if (regno <= 63 || write_symbols != DWARF2_DEBUG)
     return regno;
-  if (regno == MQ_REGNO)
-    return 100;
   if (regno == LR_REGNO)
     return 108;
   if (regno == CTR_REGNO)
@@ -27103,13 +27395,25 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
 #ifdef MASK_STRICT_ALIGN
   { "strict-align",    MASK_STRICT_ALIGN,      false, false },
 #endif
-  { "power",           MASK_POWER,             false, false },
-  { "power2",          MASK_POWER2,            false, false },
-  { "powerpc",         MASK_POWERPC,           false, false },
   { "soft-float",      MASK_SOFT_FLOAT,        false, false },
   { "string",          MASK_STRING,            false, false },
 };
 
+/* Builtin mask mapping for printing the flags.  */
+static struct rs6000_opt_mask const rs6000_builtin_mask_names[] =
+{
+  { "altivec",          RS6000_BTM_ALTIVEC,    false, false },
+  { "vsx",              RS6000_BTM_VSX,        false, false },
+  { "spe",              RS6000_BTM_SPE,        false, false },
+  { "paired",           RS6000_BTM_PAIRED,     false, false },
+  { "fre",              RS6000_BTM_FRE,        false, false },
+  { "fres",             RS6000_BTM_FRES,       false, false },
+  { "frsqrte",          RS6000_BTM_FRSQRTE,    false, false },
+  { "frsqrtes",                 RS6000_BTM_FRSQRTES,   false, false },
+  { "popcntd",          RS6000_BTM_POPCNTD,    false, false },
+  { "cell",             RS6000_BTM_CELL,       false, false },
+};
+
 /* Option variables that we want to support inside attribute((target)) and
    #pragma GCC target operations.  */
 
@@ -27205,6 +27509,11 @@ rs6000_inner_target_options (tree args, bool attr_p)
                        error_p = false;
                        target_flags_explicit |= mask;
 
+                       /* VSX needs altivec, so -mvsx automagically sets
+                          altivec.  */
+                       if (mask == MASK_VSX && !invert)
+                         mask |= MASK_ALTIVEC;
+
                        if (rs6000_opt_masks[i].invert)
                          invert = !invert;
 
@@ -27222,7 +27531,7 @@ rs6000_inner_target_options (tree args, bool attr_p)
                    if (strcmp (r, rs6000_opt_vars[i].name) == 0)
                      {
                        size_t j = rs6000_opt_vars[i].global_offset;
-                       ((int *) &global_options)[j] = !invert;
+                       *((int *) ((char *)&global_options + j)) = !invert;
                        error_p = false;
                        break;
                      }
@@ -27412,8 +27721,11 @@ rs6000_valid_attribute_p (tree fndecl,
 bool
 rs6000_pragma_target_parse (tree args, tree pop_target)
 {
+  tree prev_tree = build_target_option_node ();
   tree cur_tree;
-  bool ret;
+  struct cl_target_option *prev_opt, *cur_opt;
+  unsigned prev_bumask, cur_bumask, diff_bumask;
+  int prev_flags, cur_flags, diff_flags;
 
   if (TARGET_DEBUG_TARGET)
     {
@@ -27435,7 +27747,6 @@ rs6000_pragma_target_parse (tree args, tree pop_target)
 
   if (! args)
     {
-      ret = true;
       cur_tree = ((pop_target)
                  ? pop_target
                  : target_option_default_node);
@@ -27445,17 +27756,49 @@ rs6000_pragma_target_parse (tree args, tree pop_target)
   else
     {
       rs6000_cpu_index = rs6000_tune_index = -1;
-      ret = rs6000_inner_target_options (args, false);
-      cur_tree = build_target_option_node ();
+      if (!rs6000_inner_target_options (args, false)
+         || !rs6000_option_override_internal (false)
+         || (cur_tree = build_target_option_node ()) == NULL_TREE)
+       {
+         if (TARGET_DEBUG_BUILTIN || TARGET_DEBUG_TARGET)
+           fprintf (stderr, "invalid pragma\n");
 
-      if (!cur_tree)
-       ret = false;
+         return false;
+       }
     }
 
-  if (cur_tree)
-    target_option_current_node = cur_tree;
+  target_option_current_node = cur_tree;
 
-  return ret;
+  /* If we have the preprocessor linked in (i.e. C or C++ languages), possibly
+     change the macros that are defined.  */
+  if (rs6000_target_modify_macros_ptr)
+    {
+      prev_opt    = TREE_TARGET_OPTION (prev_tree);
+      prev_bumask = prev_opt->x_rs6000_builtin_mask;
+      prev_flags  = prev_opt->x_target_flags;
+
+      cur_opt     = TREE_TARGET_OPTION (cur_tree);
+      cur_flags   = cur_opt->x_target_flags;
+      cur_bumask  = cur_opt->x_rs6000_builtin_mask;
+
+      diff_bumask = (prev_bumask ^ cur_bumask);
+      diff_flags  = (prev_flags  ^ cur_flags);
+
+      if ((diff_flags != 0) || (diff_bumask != 0))
+       {
+         /* Delete old macros.  */
+         rs6000_target_modify_macros_ptr (false,
+                                          prev_flags & diff_flags,
+                                          prev_bumask & diff_bumask);
+
+         /* Define new macros.  */
+         rs6000_target_modify_macros_ptr (true,
+                                          cur_flags & diff_flags,
+                                          cur_bumask & diff_bumask);
+       }
+    }
+
+  return true;
 }
 
 \f
@@ -27562,6 +27905,7 @@ rs6000_function_specific_print (FILE *file, int indent,
 {
   size_t i;
   int flags = ptr->x_target_flags;
+  unsigned bu_mask = ptr->x_rs6000_builtin_mask;
 
   /* Print the various mask options.  */
   for (i = 0; i < ARRAY_SIZE (rs6000_opt_masks); i++)
@@ -27581,6 +27925,15 @@ rs6000_function_specific_print (FILE *file, int indent,
        fprintf (file, "%*s-m%s\n", indent, "",
                 rs6000_opt_vars[i].name);
     }
+
+  /* Print the various builtin flags.  */
+  fprintf (file, "%*sbuiltin mask = 0x%x\n", indent, "", bu_mask);
+  for (i = 0; i < ARRAY_SIZE (rs6000_builtin_mask_names); i++)
+    if ((bu_mask & rs6000_builtin_mask_names[i].mask) != 0)
+      {
+       fprintf (file, "%*s%s builtins supported\n", indent, "",
+                rs6000_builtin_mask_names[i].name);
+      }
 }
 
 \f
@@ -27636,14 +27989,14 @@ rs6000_allocate_stack_temp (enum machine_mode mode,
                            bool offsettable_p,
                            bool reg_reg_p)
 {
-  rtx stack = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+  rtx stack = assign_stack_temp (mode, GET_MODE_SIZE (mode));
   rtx addr = XEXP (stack, 0);
   int strict_p = (reload_in_progress || reload_completed);
 
   if (!legitimate_indirect_address_p (addr, strict_p))
     {
       if (offsettable_p
-         && !rs6000_legitimate_offset_address_p (mode, addr, strict_p))
+         && !rs6000_legitimate_offset_address_p (mode, addr, strict_p, true))
        stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
 
       else if (reg_reg_p && !legitimate_indexed_address_p (addr, strict_p))
@@ -27859,4 +28212,93 @@ rs6000_save_toc_in_prologue_p (void)
   return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
 }
 
+#ifdef HAVE_GAS_HIDDEN
+# define USE_HIDDEN_LINKONCE 1
+#else
+# define USE_HIDDEN_LINKONCE 0
+#endif
+
+/* Fills in the label name that should be used for a 476 link stack thunk.  */
+
+void
+get_ppc476_thunk_name (char name[32])
+{
+  gcc_assert (TARGET_LINK_STACK);
+
+  if (USE_HIDDEN_LINKONCE)
+    sprintf (name, "__ppc476.get_thunk");
+  else
+    ASM_GENERATE_INTERNAL_LABEL (name, "LPPC476_", 0);
+}
+
+/* This function emits the simple thunk routine that is used to preserve
+   the link stack on the 476 cpu.  */
+
+static void rs6000_code_end (void) ATTRIBUTE_UNUSED;
+static void
+rs6000_code_end (void)
+{
+  char name[32];
+  tree decl;
+
+  if (!TARGET_LINK_STACK)
+    return;
+
+  get_ppc476_thunk_name (name);
+
+  decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL, get_identifier (name),
+                    build_function_type_list (void_type_node, NULL_TREE));
+  DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
+                                  NULL_TREE, void_type_node);
+  TREE_PUBLIC (decl) = 1;
+  TREE_STATIC (decl) = 1;
+
+  if (USE_HIDDEN_LINKONCE)
+    {
+      DECL_COMDAT_GROUP (decl) = DECL_ASSEMBLER_NAME (decl);
+      targetm.asm_out.unique_section (decl, 0);
+      switch_to_section (get_named_section (decl, NULL, 0));
+      DECL_WEAK (decl) = 1;
+      ASM_WEAKEN_DECL (asm_out_file, decl, name, 0);
+      targetm.asm_out.globalize_label (asm_out_file, name);
+      targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN);
+      ASM_DECLARE_FUNCTION_NAME (asm_out_file, name, decl);
+    }
+  else
+    {
+      switch_to_section (text_section);
+      ASM_OUTPUT_LABEL (asm_out_file, name);
+    }
+
+  DECL_INITIAL (decl) = make_node (BLOCK);
+  current_function_decl = decl;
+  init_function_start (decl);
+  first_function_block_is_cold = false;
+  /* Make sure unwind info is emitted for the thunk if needed.  */
+  final_start_function (emit_barrier (), asm_out_file, 1);
+
+  fputs ("\tblr\n", asm_out_file);
+
+  final_end_function ();
+  init_insn_lengths ();
+  free_after_compilation (cfun);
+  set_cfun (NULL);
+  current_function_decl = NULL;
+}
+
+/* Add r30 to hard reg set if the prologue sets it up and it is not
+   pic_offset_table_rtx.  */
+
+static void
+rs6000_set_up_by_prologue (struct hard_reg_set_container *set)
+{
+  if (!TARGET_SINGLE_PIC_BASE
+      && TARGET_TOC
+      && TARGET_MINIMAL_TOC
+      && get_pool_size () != 0)
+    add_to_hard_reg_set (&set->set, Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
 #include "gt-rs6000.h"