OSDN Git Service

* config/rs6000/rs6000.c (rs6000_code_end): Declare ATTRIBUTE_UNUSED.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index fe3d0db..2430cdf 100644 (file)
@@ -1,6 +1,6 @@
 /* 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
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
@@ -48,6 +48,7 @@
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "common/common-target.h"
 #include "langhooks.h"
 #include "reload.h"
 #include "cfglayout.h"
@@ -58,6 +59,7 @@
 #include "intl.h"
 #include "params.h"
 #include "tm-constrs.h"
+#include "opts.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
@@ -128,6 +130,9 @@ typedef struct GTY(()) machine_function
   int ra_need_lr;
   /* Cache lr_save_p after expansion of builtin_eh_return.  */
   int lr_save_state;
+  /* Whether we need to save the TOC to the reserved stack location in the
+     function prologue.  */
+  bool save_toc_in_prologue;
   /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
      varargs save area.  */
   HOST_WIDE_INT varargs_save_offset;
@@ -137,61 +142,9 @@ typedef struct GTY(()) machine_function
   rtx sdmode_stack_slot;
 } machine_function;
 
-/* Target cpu type */
-
-enum processor_type rs6000_cpu;
-struct rs6000_cpu_select rs6000_select[3] =
-{
-  /* switch            name,                   tune    arch */
-  { (const char *)0,   "--with-cpu=",          1,      1 },
-  { (const char *)0,   "-mcpu=",               1,      1 },
-  { (const char *)0,   "-mtune=",              1,      0 },
-};
-
-/* Always emit branch hint bits.  */
-static GTY(()) bool rs6000_always_hint;
-
-/* Schedule instructions for group formation.  */
-static GTY(()) bool rs6000_sched_groups;
-
-/* Align branch targets.  */
-static GTY(()) bool rs6000_align_branch_targets;
-
-/* Non-zero to allow overriding loop alignment. */
-static int can_override_loop_align = 0;
-
-/* Support for -msched-costly-dep option.  */
-const char *rs6000_sched_costly_dep_str;
-enum rs6000_dependence_cost rs6000_sched_costly_dep;
-
-/* Support for -minsert-sched-nops option.  */
-const char *rs6000_sched_insert_nops_str;
-enum rs6000_nop_insertion rs6000_sched_insert_nops;
-
 /* Support targetm.vectorize.builtin_mask_for_load.  */
 static GTY(()) tree altivec_builtin_mask_for_load;
 
-/* Size of long double.  */
-int rs6000_long_double_type_size;
-
-/* IEEE quad extended precision long double. */
-int rs6000_ieeequad;
-
-/* Nonzero to use AltiVec ABI.  */
-int rs6000_altivec_abi;
-
-/* Nonzero if we want SPE SIMD instructions.  */
-int rs6000_spe;
-
-/* Nonzero if we want SPE ABI extensions.  */
-int rs6000_spe_abi;
-
-/* Nonzero if floating point operations are done in the GPRs.  */
-int rs6000_float_gprs = 0;
-
-/* Nonzero if we want Darwin's struct-by-value-in-regs ABI.  */
-int rs6000_darwin64_abi;
-
 /* Set to nonzero once AIX common-mode calls have been defined.  */
 static GTY(()) int common_mode_defined;
 
@@ -200,37 +153,13 @@ static GTY(()) int common_mode_defined;
 static int rs6000_pic_labelno;
 
 #ifdef USING_ELFOS_H
-/* Which abi to adhere to */
-const char *rs6000_abi_name;
-
-/* Semantics of the small data area */
-enum rs6000_sdata_type rs6000_sdata = SDATA_DATA;
-
-/* Which small data model to use */
-const char *rs6000_sdata_name = (char *)0;
-
 /* Counter for labels which are to be placed in .fixup.  */
 int fixuplabelno = 0;
 #endif
 
-/* Bit size of immediate TLS offsets and string from which it is decoded.  */
-int rs6000_tls_size = 32;
-const char *rs6000_tls_size_string;
-
-/* ABI enumeration available for subtarget to use.  */
-enum rs6000_abi rs6000_current_abi;
-
 /* Whether to use variant of AIX ABI for PowerPC64 Linux.  */
 int dot_symbols;
 
-/* Debug flags */
-const char *rs6000_debug_name;
-int rs6000_debug_stack;                /* debug stack applications */
-int rs6000_debug_arg;          /* debug argument handling */
-int rs6000_debug_reg;          /* debug register classes */
-int rs6000_debug_addr;         /* debug memory addressing */
-int rs6000_debug_cost;         /* debug rtx_costs */
-
 /* Specify the machine mode that pointers have.  After generation of rtl, the
    compiler makes no further distinction between pointers and any other objects
    of this machine mode.  The type is unsigned since not all things that
@@ -240,6 +169,14 @@ unsigned rs6000_pmode;
 /* Width in bits of a pointer.  */
 unsigned rs6000_pointer_size;
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+/* Flag whether floating point values have been passed/returned.  */
+static bool rs6000_passes_float;
+/* Flag whether vector values have been passed/returned.  */
+static bool rs6000_passes_vector;
+/* Flag whether small (<= 8 byte) structures have been returned.  */
+static bool rs6000_returns_struct;
+#endif
 
 /* Value is TRUE if register/mode pair is acceptable.  */
 bool rs6000_hard_regno_mode_ok_p[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
@@ -256,18 +193,12 @@ enum reg_class rs6000_regno_regclass[FIRST_PSEUDO_REGISTER];
 /* Reload functions based on the type and the vector unit.  */
 static enum insn_code rs6000_vector_reload[NUM_MACHINE_MODES][2];
 
+static int dbg_cost_ctrl;
+
 /* Built in types.  */
 tree rs6000_builtin_types[RS6000_BTI_MAX];
 tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT];
 
-const char *rs6000_traceback_name;
-static enum {
-  traceback_default = 0,
-  traceback_none,
-  traceback_part,
-  traceback_full
-} rs6000_traceback;
-
 /* Flag to say the TOC is initialized */
 int toc_initialized;
 char toc_label_name[10];
@@ -282,27 +213,6 @@ static GTY(()) section *read_only_private_data_section;
 static GTY(()) section *sdata2_section;
 static GTY(()) section *toc_section;
 
-/* Control alignment for fields within structures.  */
-/* String from -malign-XXXXX.  */
-int rs6000_alignment_flags;
-
-/* Code model for 64-bit linux.  */
-enum rs6000_cmodel cmodel;
-
-/* True for any options that were explicitly set.  */
-static struct {
-  bool aix_struct_ret;         /* True if -maix-struct-ret was used.  */
-  bool alignment;              /* True if -malign- was used.  */
-  bool spe_abi;                        /* True if -mabi=spe/no-spe was used.  */
-  bool altivec_abi;            /* True if -mabi=altivec/no-altivec used.  */
-  bool spe;                    /* True if -mspe= was used.  */
-  bool float_gprs;             /* True if -mfloat-gprs= was used.  */
-  bool long_double;            /* True if -mlong-double- was used.  */
-  bool ieee;                   /* True if -mabi=ieee/ibmlongdouble used.  */
-  bool vrsave;                 /* True if -mvrsave was used.  */
-  bool cmodel;                 /* True if -mcmodel was used.  */
-} rs6000_explicit_options;
-
 struct builtin_description
 {
   /* mask is not const because we're going to alter it below.  This
@@ -358,9 +268,6 @@ enum rs6000_recip_mask {
   RECIP_LOW_PRECISION  = (RECIP_ALL & ~(RECIP_DF_RSQRT | RECIP_V2DF_RSQRT))
 };
 
-static unsigned int rs6000_recip_control;
-static const char *rs6000_recip_name;
-
 /* -mrecip options.  */
 static struct
 {
@@ -965,10 +872,7 @@ 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 void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
 static bool spe_func_has_64bit_regs_p (void);
-static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
-                            int, HOST_WIDE_INT);
 static rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
 static unsigned rs6000_hash_constant (rtx);
 static unsigned toc_hash_function (const void *);
@@ -981,7 +885,7 @@ 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);
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
 static void rs6000_assemble_visibility (tree, int);
 #endif
 static int rs6000_ra_ever_killed (void);
@@ -995,8 +899,6 @@ 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);
@@ -1012,9 +914,9 @@ 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);
-static void rs6000_elf_asm_out_destructor (rtx, int);
-static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
+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);
@@ -1044,8 +946,8 @@ 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 bool rs6000_rtx_costs (rtx, int, int, int, int *, bool);
+static bool rs6000_debug_rtx_costs (rtx, int, int, int, int *, bool);
 static int rs6000_debug_address_cost (rtx, bool);
 static int rs6000_adjust_cost (rtx, rtx, rtx, int);
 static int rs6000_debug_adjust_cost (rtx, rtx, rtx, int);
@@ -1084,7 +986,6 @@ 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,
@@ -1141,12 +1042,7 @@ 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 void rs6000_option_init_struct (struct gcc_options *);
-static void rs6000_option_default_params (void);
-static bool rs6000_handle_option (size_t, const char *, int);
 static int rs6000_loop_align_max_skip (rtx);
-static void rs6000_parse_tls_size_option (void);
-static void rs6000_parse_yes_no_option (const char *, const char *, int *);
 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);
@@ -1181,19 +1077,19 @@ static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
                                                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 *, enum machine_mode,
+static void rs6000_function_arg_advance (cumulative_args_t, enum machine_mode,
                                         const_tree, bool);
-static rtx rs6000_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+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 *,
+static void setup_incoming_varargs (cumulative_args_t,
                                    enum machine_mode, tree,
                                    int *, int);
-static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+static bool rs6000_pass_by_reference (cumulative_args_t, enum machine_mode,
                                      const_tree, bool);
-static int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+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);
 #if TARGET_MACHO
@@ -1272,12 +1168,15 @@ static reg_class_t rs6000_secondary_reload (bool, rtx, reg_class_t,
                                            enum machine_mode,
                                            struct secondary_reload_info *);
 
-static const reg_class_t *rs6000_ira_cover_classes (void);
-
 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);
+static void rs6000_code_end (void) ATTRIBUTE_UNUSED;
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -1302,6 +1201,15 @@ 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] =
@@ -1360,24 +1268,23 @@ static const char alt_reg_names[][8] =
 
 static const struct attribute_spec rs6000_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
-  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
-  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
-  { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
-  { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
+  { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute,
+    false },
+  { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
+    false },
+  { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute,
+    false },
+  { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
+    false },
+  { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute,
+    false },
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
-  { NULL,        0, 0, false, false, false, NULL }
+  { NULL,        0, 0, false, false, false, NULL, false }
 };
-
-/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
-static const struct default_options rs6000_option_optimization_table[] =
-  {
-    { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
-    { OPT_LEVELS_NONE, 0, NULL, 0 }
-  };
 \f
 #ifndef MASK_STRICT_ALIGN
 #define MASK_STRICT_ALIGN 0
@@ -1430,7 +1337,7 @@ static const struct default_options rs6000_option_optimization_table[] =
 #undef TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER rs6000_assemble_integer
 
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
 #undef TARGET_ASM_ASSEMBLE_VISIBILITY
 #define TARGET_ASM_ASSEMBLE_VISIBILITY rs6000_assemble_visibility
 #endif
@@ -1439,7 +1346,7 @@ static const struct default_options rs6000_option_optimization_table[] =
 #define TARGET_HAVE_TLS HAVE_AS_TLS
 
 #undef TARGET_CANNOT_FORCE_CONST_MEM
-#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p
+#define TARGET_CANNOT_FORCE_CONST_MEM rs6000_cannot_force_const_mem
 
 #undef TARGET_DELEGITIMIZE_ADDRESS
 #define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address
@@ -1498,8 +1405,6 @@ static const struct default_options rs6000_option_optimization_table[] =
 #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
@@ -1613,34 +1518,20 @@ static const struct default_options rs6000_option_optimization_table[] =
 #undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
 #define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
 
-#undef TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION rs6000_handle_option
-
 #undef TARGET_ASM_LOOP_ALIGN_MAX_SKIP
 #define TARGET_ASM_LOOP_ALIGN_MAX_SKIP rs6000_loop_align_max_skip
 
 #undef TARGET_OPTION_OVERRIDE
 #define TARGET_OPTION_OVERRIDE rs6000_option_override
 
-#undef TARGET_OPTION_INIT_STRUCT
-#define TARGET_OPTION_INIT_STRUCT rs6000_option_init_struct
-
-#undef TARGET_OPTION_DEFAULT_PARAMS
-#define TARGET_OPTION_DEFAULT_PARAMS rs6000_option_default_params
-
-#undef TARGET_OPTION_OPTIMIZATION_TABLE
-#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table
-
 #undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION
 #define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \
   rs6000_builtin_vectorized_function
 
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS \
-  (TARGET_DEFAULT)
-
+#ifndef TARGET_MACHO
 #undef TARGET_STACK_PROTECT_FAIL
 #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
+#endif
 
 /* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
    The PowerPC architecture requires only weak consistency among
@@ -1684,9 +1575,6 @@ static const struct default_options rs6000_option_optimization_table[] =
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD rs6000_secondary_reload
 
-#undef TARGET_IRA_COVER_CLASSES
-#define TARGET_IRA_COVER_CLASSES rs6000_ira_cover_classes
-
 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P rs6000_legitimate_address_p
 
@@ -1696,13 +1584,114 @@ static const struct default_options rs6000_option_optimization_table[] =
 #undef TARGET_CAN_ELIMINATE
 #define TARGET_CAN_ELIMINATE rs6000_can_eliminate
 
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE rs6000_conditional_register_usage
+
 #undef TARGET_TRAMPOLINE_INIT
 #define TARGET_TRAMPOLINE_INIT rs6000_trampoline_init
 
 #undef TARGET_FUNCTION_VALUE
 #define TARGET_FUNCTION_VALUE rs6000_function_value
 
-struct gcc_target targetm = TARGET_INITIALIZER;
+#undef TARGET_OPTION_VALID_ATTRIBUTE_P
+#define TARGET_OPTION_VALID_ATTRIBUTE_P rs6000_valid_attribute_p
+
+#undef TARGET_OPTION_SAVE
+#define TARGET_OPTION_SAVE rs6000_function_specific_save
+
+#undef TARGET_OPTION_RESTORE
+#define TARGET_OPTION_RESTORE rs6000_function_specific_restore
+
+#undef TARGET_OPTION_PRINT
+#define TARGET_OPTION_PRINT rs6000_function_specific_print
+
+#undef TARGET_CAN_INLINE_P
+#define TARGET_CAN_INLINE_P rs6000_can_inline_p
+
+#undef TARGET_SET_CURRENT_FUNCTION
+#define TARGET_SET_CURRENT_FUNCTION rs6000_set_current_function
+
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P rs6000_legitimate_constant_p
+
+\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
+};
+
+/* Some OSs don't support saving the high part of 64-bit registers on context
+   switch.  Other OSs don't support saving Altivec registers.  On those OSs, we
+   don't touch the MASK_POWERPC64 or MASK_ALTIVEC settings; if the user wants
+   either, the user must explicitly specify them and we won't interfere with
+   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
+                  | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
+                  | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
+                  | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP
+                  | MASK_POPCNTD | MASK_VSX | MASK_ISEL | MASK_NO_UPDATE
+                  | MASK_RECIP_PRECISION)
+};
+
+/* Masks for instructions set at various powerpc ISAs.  */
+enum {
+  ISA_2_1_MASKS = MASK_MFCRF,
+  ISA_2_2_MASKS = (ISA_2_1_MASKS | MASK_POPCNTB),
+  ISA_2_4_MASKS = (ISA_2_2_MASKS | MASK_FPRND),
+
+  /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and don't add
+     ALTIVEC, since in general it isn't a win on power6.  In ISA 2.04, fsel,
+     fre, fsqrt, etc. were no longer documented as optional.  Group masks by
+     server and embedded. */
+  ISA_2_5_MASKS_EMBEDDED = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
+                           | MASK_PPC_GFXOPT | MASK_PPC_GPOPT),
+  ISA_2_5_MASKS_SERVER = (ISA_2_5_MASKS_EMBEDDED | MASK_DFP),
+
+  /* For ISA 2.06, don't add ISEL, since in general it isn't a win, but
+     altivec is a win so enable it.  */
+  ISA_2_6_MASKS_EMBEDDED = (ISA_2_5_MASKS_EMBEDDED | MASK_POPCNTD),
+  ISA_2_6_MASKS_SERVER = (ISA_2_5_MASKS_SERVER | MASK_POPCNTD | MASK_ALTIVEC
+                         | MASK_VSX)
+};
+
+struct rs6000_ptt
+{
+  const char *const name;              /* Canonical processor name.  */
+  const enum processor_type processor; /* Processor type enum value.  */
+  const int target_enable;             /* Target flags to enable.  */
+};
+
+static struct rs6000_ptt const processor_target_table[] =
+{
+#define RS6000_CPU(NAME, CPU, FLAGS) { NAME, CPU, FLAGS },
+#include "rs6000-cpus.def"
+#undef RS6000_CPU
+};
+
+/* Look up a processor name for -mcpu=xxx and -mtune=xxx.  Return -1 if the
+   name is invalid.  */
+
+static int
+rs6000_cpu_name_lookup (const char *name)
+{
+  size_t i;
+
+  if (name != NULL)
+    {
+      for (i = 0; i < ARRAY_SIZE (processor_target_table); i++)
+       if (! strcmp (name, processor_target_table[i].name))
+         return (int)i;
+    }
+
+  return -1;
+}
+
 \f
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
@@ -1886,16 +1875,23 @@ rs6000_debug_reg_print (int first_regno, int last_regno, const char *reg_name)
     }
 }
 
+#define DEBUG_FMT_D "%-32s= %d\n"
+#define DEBUG_FMT_S "%-32s= %s\n"
+
 /* Print various interesting information with -mdebug=reg.  */
 static void
 rs6000_debug_reg_global (void)
 {
+  static const char *const tf[2] = { "false", "true" };
   const char *nl = (const char *)0;
   int m;
   char costly_num[20];
   char nop_num[20];
   const char *costly_str;
   const char *nop_str;
+  const char *trace_str;
+  const char *abi_str;
+  const char *cmodel_str;
 
   /* Map enum rs6000_vector to string.  */
   static const char *rs6000_debug_vector_unit[] = {
@@ -1975,6 +1971,14 @@ rs6000_debug_reg_global (void)
       fputs ("\n", stderr);
     }
 
+  if (rs6000_cpu_index >= 0)
+    fprintf (stderr, DEBUG_FMT_S, "cpu",
+            processor_target_table[rs6000_cpu_index].name);
+
+  if (rs6000_tune_index >= 0)
+    fprintf (stderr, DEBUG_FMT_S, "tune",
+            processor_target_table[rs6000_tune_index].name);
+
   switch (rs6000_sched_costly_dep)
     {
     case max_dep_latency:
@@ -2003,6 +2007,8 @@ rs6000_debug_reg_global (void)
       break;
     }
 
+  fprintf (stderr, DEBUG_FMT_S, "sched_costly_dep", costly_str);
+
   switch (rs6000_sched_insert_nops)
     {
     case sched_finish_regroup_exact:
@@ -2023,21 +2029,85 @@ rs6000_debug_reg_global (void)
       break;
     }
 
-  fprintf (stderr,
-          "always_hint                     = %s\n"
-          "align_branch_targets            = %s\n"
-          "sched_restricted_insns_priority = %d\n"
-          "sched_costly_dep                = %s\n"
-          "sched_insert_nops               = %s\n\n",
-          rs6000_always_hint ? "true" : "false",
-          rs6000_align_branch_targets ? "true" : "false",
-          (int)rs6000_sched_restricted_insns_priority,
-          costly_str, nop_str);
+  fprintf (stderr, DEBUG_FMT_S, "sched_insert_nops", nop_str);
+
+  switch (rs6000_sdata)
+    {
+    default:
+    case SDATA_NONE:
+      break;
+
+    case SDATA_DATA:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "data");
+      break;
+
+    case SDATA_SYSV:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "sysv");
+      break;
+
+    case SDATA_EABI:
+      fprintf (stderr, DEBUG_FMT_S, "sdata", "eabi");
+      break;
+
+    }
+
+  switch (rs6000_traceback)
+    {
+    case traceback_default:    trace_str = "default";  break;
+    case traceback_none:       trace_str = "none";     break;
+    case traceback_part:       trace_str = "part";     break;
+    case traceback_full:       trace_str = "full";     break;
+    default:                   trace_str = "unknown";  break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "traceback", trace_str);
+
+  switch (rs6000_current_cmodel)
+    {
+    case CMODEL_SMALL: cmodel_str = "small";   break;
+    case CMODEL_MEDIUM:        cmodel_str = "medium";  break;
+    case CMODEL_LARGE: cmodel_str = "large";   break;
+    default:           cmodel_str = "unknown"; break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "cmodel", cmodel_str);
+
+  switch (rs6000_current_abi)
+    {
+    case ABI_NONE:     abi_str = "none";       break;
+    case ABI_AIX:      abi_str = "aix";        break;
+    case ABI_V4:       abi_str = "V4";         break;
+    case ABI_DARWIN:   abi_str = "darwin";     break;
+    default:           abi_str = "unknown";    break;
+    }
+
+  fprintf (stderr, DEBUG_FMT_S, "abi", abi_str);
+
+  if (rs6000_altivec_abi)
+    fprintf (stderr, DEBUG_FMT_S, "altivec_abi", "true");
+
+  if (rs6000_spe_abi)
+    fprintf (stderr, DEBUG_FMT_S, "spe_abi", "true");
+
+  if (rs6000_darwin64_abi)
+    fprintf (stderr, DEBUG_FMT_S, "darwin64_abi", "true");
+
+  if (rs6000_float_gprs)
+    fprintf (stderr, DEBUG_FMT_S, "float_gprs", "true");
+
+  fprintf (stderr, DEBUG_FMT_S, "always_hint", tf[!!rs6000_always_hint]);
+  fprintf (stderr, DEBUG_FMT_S, "align_branch",
+          tf[!!rs6000_align_branch_targets]);
+  fprintf (stderr, DEBUG_FMT_D, "tls_size", rs6000_tls_size);
+  fprintf (stderr, DEBUG_FMT_D, "long_double_size",
+          rs6000_long_double_type_size);
+  fprintf (stderr, DEBUG_FMT_D, "sched_restricted_insns_priority",
+          (int)rs6000_sched_restricted_insns_priority);
 }
 
 /* Initialize the various global tables that are based on register size.  */
 static void
-rs6000_init_hard_regno_mode_ok (void)
+rs6000_init_hard_regno_mode_ok (bool global_init_p)
 {
   int r, m, c;
   int align64;
@@ -2330,40 +2400,43 @@ rs6000_init_hard_regno_mode_ok (void)
        }
     }
 
-  if (TARGET_DEBUG_REG)
-    rs6000_debug_reg_global ();
-
-  if (TARGET_DEBUG_COST || TARGET_DEBUG_REG)
-    fprintf (stderr,
-            "SImode variable mult cost       = %d\n"
-            "SImode constant mult cost       = %d\n"
-            "SImode short constant mult cost = %d\n"
-            "DImode multipliciation cost     = %d\n"
-            "SImode division cost            = %d\n"
-            "DImode division cost            = %d\n"
-            "Simple fp operation cost        = %d\n"
-            "DFmode multiplication cost      = %d\n"
-            "SFmode division cost            = %d\n"
-            "DFmode division cost            = %d\n"
-            "cache line size                 = %d\n"
-            "l1 cache size                   = %d\n"
-            "l2 cache size                   = %d\n"
-            "simultaneous prefetches         = %d\n"
-            "\n",
-            rs6000_cost->mulsi,
-            rs6000_cost->mulsi_const,
-            rs6000_cost->mulsi_const9,
-            rs6000_cost->muldi,
-            rs6000_cost->divsi,
-            rs6000_cost->divdi,
-            rs6000_cost->fp,
-            rs6000_cost->dmul,
-            rs6000_cost->sdiv,
-            rs6000_cost->ddiv,
-            rs6000_cost->cache_line_size,
-            rs6000_cost->l1_cache_size,
-            rs6000_cost->l2_cache_size,
-            rs6000_cost->simultaneous_prefetches);
+  if (global_init_p || TARGET_DEBUG_TARGET)
+    {
+      if (TARGET_DEBUG_REG)
+       rs6000_debug_reg_global ();
+
+      if (TARGET_DEBUG_COST || TARGET_DEBUG_REG)
+       fprintf (stderr,
+                "SImode variable mult cost       = %d\n"
+                "SImode constant mult cost       = %d\n"
+                "SImode short constant mult cost = %d\n"
+                "DImode multipliciation cost     = %d\n"
+                "SImode division cost            = %d\n"
+                "DImode division cost            = %d\n"
+                "Simple fp operation cost        = %d\n"
+                "DFmode multiplication cost      = %d\n"
+                "SFmode division cost            = %d\n"
+                "DFmode division cost            = %d\n"
+                "cache line size                 = %d\n"
+                "l1 cache size                   = %d\n"
+                "l2 cache size                   = %d\n"
+                "simultaneous prefetches         = %d\n"
+                "\n",
+                rs6000_cost->mulsi,
+                rs6000_cost->mulsi_const,
+                rs6000_cost->mulsi_const9,
+                rs6000_cost->muldi,
+                rs6000_cost->divsi,
+                rs6000_cost->divdi,
+                rs6000_cost->fp,
+                rs6000_cost->dmul,
+                rs6000_cost->sdiv,
+                rs6000_cost->ddiv,
+                rs6000_cost->cache_line_size,
+                rs6000_cost->l1_cache_size,
+                rs6000_cost->l2_cache_size,
+                rs6000_cost->simultaneous_prefetches);
+    }
 }
 
 #if TARGET_MACHO
@@ -2406,7 +2479,7 @@ darwin_rs6000_override_options (void)
       && !flag_apple_kext
       && strverscmp (darwin_macosx_version_min, "10.5") >= 0
       && ! (target_flags_explicit & MASK_ALTIVEC)
-      && ! rs6000_select[1].string)
+      && ! global_options_set.x_rs6000_cpu_index)
     {
       target_flags |= MASK_ALTIVEC;
     }
@@ -2420,187 +2493,42 @@ darwin_rs6000_override_options (void)
 #define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
 #endif
 
-/* Override command line options.  Mostly we process the processor
-   type and sometimes adjust other TARGET_ options.  */
+/* Override command line options.  Mostly we process the processor type and
+   sometimes adjust other TARGET_ options.  */
 
-static void
-rs6000_option_override_internal (const char *default_cpu)
+static bool
+rs6000_option_override_internal (bool global_init_p)
 {
-  size_t i, j;
-  struct rs6000_cpu_select *ptr;
+  bool ret = true;
+  const char *default_cpu = OPTION_TARGET_CPU_DEFAULT;
   int set_masks;
+  int cpu_index;
+  int tune_index;
+  struct cl_target_option *main_target_opt
+    = ((global_init_p || target_option_default_node == NULL)
+       ? NULL : TREE_TARGET_OPTION (target_option_default_node));
+
+  /* On 64-bit Darwin, power alignment is ABI-incompatible with some C
+     library functions, so warn about it. The flag may be useful for
+     performance studies from time to time though, so don't disable it
+     entirely.  */
+  if (global_options_set.x_rs6000_alignment_flags
+      && rs6000_alignment_flags == MASK_ALIGN_POWER
+      && DEFAULT_ABI == ABI_DARWIN
+      && TARGET_64BIT)
+    warning (0, "-malign-power is not supported for 64-bit Darwin;"
+            " it is incompatible with the installed C and C++ libraries");
 
-  /* Simplifications for entries below.  */
-
-  enum {
-    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
-    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
-  };
-
-  /* This table occasionally claims that a processor does not support
-     a particular feature even though it does, but the feature is slower
-     than the alternative.  Thus, it shouldn't be relied on as a
-     complete description of the processor's support.
-
-     Please keep this list in order, and don't forget to update the
-     documentation in invoke.texi when adding a new processor or
-     flag.  */
-  static struct ptt
-    {
-      const char *const name;          /* Canonical processor name.  */
-      const enum processor_type processor; /* Processor type enum value.  */
-      const int target_enable; /* Target flags to enable.  */
-    } const processor_target_table[]
-      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"403", PROCESSOR_PPC403,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
-        {"405", PROCESSOR_PPC405,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
-        {"405fp", PROCESSOR_PPC405,
-         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
-        {"440", PROCESSOR_PPC440,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
-        {"440fp", PROCESSOR_PPC440,
-         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
-        {"464", PROCESSOR_PPC440,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
-        {"464fp", PROCESSOR_PPC440,
-         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
-        {"476", PROCESSOR_PPC476,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_PPC_GFXOPT | MASK_MFCRF
-         | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB},
-        {"476fp", PROCESSOR_PPC476,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POPCNTB
-         | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB},
-        {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
-        {"601", PROCESSOR_PPC601,
-         MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
-        {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"620", PROCESSOR_PPC620,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
-        {"630", PROCESSOR_PPC630,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
-        {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
-        {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
-        {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN
-         | MASK_ISEL},
-        /* 8548 has a dummy entry for now.  */
-        {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN
-         | MASK_ISEL},
-        {"a2", PROCESSOR_PPCA2,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_POPCNTB
-         | MASK_CMPB | MASK_NO_UPDATE },
-        {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK},
-        {"e500mc", PROCESSOR_PPCE500MC, POWERPC_BASE_MASK | MASK_PPC_GFXOPT
-         | MASK_ISEL},
-        {"e500mc64", PROCESSOR_PPCE500MC64, POWERPC_BASE_MASK | MASK_POWERPC64
-         | MASK_PPC_GFXOPT | MASK_ISEL},
-        {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"970", PROCESSOR_POWER4,
-         POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
-        {"cell", PROCESSOR_CELL,
-         POWERPC_7400_MASK  | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
-        {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
-        {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
-        {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
-        {"G5", PROCESSOR_POWER4,
-         POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
-        {"titan", PROCESSOR_TITAN,
-         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
-        {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"power2", PROCESSOR_POWER,
-         MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
-        {"power3", PROCESSOR_PPC630,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
-        {"power4", PROCESSOR_POWER4,
-         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
-         | MASK_MFCRF},
-        {"power5", PROCESSOR_POWER5,
-         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
-         | MASK_MFCRF | MASK_POPCNTB},
-        {"power5+", PROCESSOR_POWER5,
-         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
-         | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
-        {"power6", PROCESSOR_POWER6,
-         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
-         | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
-         | MASK_RECIP_PRECISION},
-        {"power6x", PROCESSOR_POWER6,
-         POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
-         | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
-         | MASK_MFPGPR | MASK_RECIP_PRECISION},
-        {"power7", PROCESSOR_POWER7,   /* Don't add MASK_ISEL by default */
-         POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
-         | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
-         | MASK_VSX | MASK_RECIP_PRECISION},
-        {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
-        {"powerpc64", PROCESSOR_POWERPC64,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
-        {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"rios2", PROCESSOR_RIOS2,
-         MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
-        {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
-        {"rs64", PROCESSOR_RS64A,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}
-      };
-
-  const size_t ptt_size = ARRAY_SIZE (processor_target_table);
-
-  /* Some OSs don't support saving the high part of 64-bit registers on
-     context switch.  Other OSs don't support saving Altivec registers.
-     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
-     settings; if the user wants either, the user must explicitly specify
-     them and we won't interfere with 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
-                    | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
-                    | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
-                    | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP
-                    | MASK_POPCNTD | MASK_VSX | MASK_ISEL | MASK_NO_UPDATE
-                    | MASK_RECIP_PRECISION)
-  };
-
-  /* Masks for instructions set at various powerpc ISAs.  */
-  enum {
-    ISA_2_1_MASKS = MASK_MFCRF,
-    ISA_2_2_MASKS = (ISA_2_1_MASKS | MASK_POPCNTB),
-    ISA_2_4_MASKS = (ISA_2_2_MASKS | MASK_FPRND),
-
-    /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and don't
-       add ALTIVEC, since in general it isn't a win on power6.  In ISA 2.04,
-       fsel, fre, fsqrt, etc. were no longer documented as optional.  Group
-       masks by server and embedded. */
-    ISA_2_5_MASKS_EMBEDDED = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
-                             | MASK_PPC_GFXOPT | MASK_PPC_GPOPT),
-    ISA_2_5_MASKS_SERVER = (ISA_2_5_MASKS_EMBEDDED | MASK_DFP),
-
-    /* For ISA 2.06, don't add ISEL, since in general it isn't a win, but
-       altivec is a win so enable it.  */
-    ISA_2_6_MASKS_EMBEDDED = (ISA_2_5_MASKS_EMBEDDED | MASK_POPCNTD),
-    ISA_2_6_MASKS_SERVER = (ISA_2_5_MASKS_SERVER | MASK_POPCNTD | MASK_ALTIVEC
-                           | MASK_VSX)
-  };
+  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.
      So it is on only for peak performance.  */
-  if (optimize >= 3)
+  if (optimize >= 3 && global_init_p)
     flag_ira_loop_pressure = 1;
 
   /* Set the pointer size.  */
@@ -2629,34 +2557,43 @@ rs6000_option_override_internal (const char *default_cpu)
   set_masks &= ~target_flags_explicit;
 
   /* Identify the processor type.  */
-  rs6000_select[0].string = default_cpu;
-  rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
-
-  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
-    {
-      ptr = &rs6000_select[i];
-      if (ptr->string != (char *)0 && ptr->string[0] != '\0')
-       {
-         for (j = 0; j < ptt_size; j++)
-           if (! strcmp (ptr->string, processor_target_table[j].name))
-             {
-               if (ptr->set_tune_p)
-                 rs6000_cpu = processor_target_table[j].processor;
+  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;
+  else
+    rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
 
-               if (ptr->set_arch_p)
-                 {
-                   target_flags &= ~set_masks;
-                   target_flags |= (processor_target_table[j].target_enable
-                                    & set_masks);
-                 }
-               break;
-             }
+  if (rs6000_tune_index > 0)
+    tune_index = rs6000_tune_index;
+  else
+    rs6000_tune_index = tune_index = cpu_index;
 
-         if (j == ptt_size)
-           error ("bad value (%s) for %s switch", ptr->string, ptr->name);
-       }
+  if (cpu_index >= 0)
+    {
+      target_flags &= ~set_masks;
+      target_flags |= (processor_target_table[cpu_index].target_enable
+                      & set_masks);
     }
 
+  rs6000_cpu = ((tune_index >= 0)
+               ? processor_target_table[tune_index].processor
+               : (TARGET_POWERPC64
+                  ? PROCESSOR_DEFAULT64
+                  : PROCESSOR_DEFAULT));
+
   if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3
       || rs6000_cpu == PROCESSOR_PPCE500MC || rs6000_cpu == PROCESSOR_PPCE500MC64)
     {
@@ -2767,25 +2704,8 @@ rs6000_option_override_internal (const char *default_cpu)
   if (rs6000_block_move_inline_limit < (TARGET_POWERPC64 ? 64 : 32))
     rs6000_block_move_inline_limit = (TARGET_POWERPC64 ? 64 : 32);
 
-  /* Set debug flags */
-  if (rs6000_debug_name)
-    {
-      if (! strcmp (rs6000_debug_name, "all"))
-       rs6000_debug_stack = rs6000_debug_arg = rs6000_debug_reg
-         = rs6000_debug_addr = rs6000_debug_cost = 1;
-      else if (! strcmp (rs6000_debug_name, "stack"))
-       rs6000_debug_stack = 1;
-      else if (! strcmp (rs6000_debug_name, "arg"))
-       rs6000_debug_arg = 1;
-      else if (! strcmp (rs6000_debug_name, "reg"))
-       rs6000_debug_reg = 1;
-      else if (! strcmp (rs6000_debug_name, "addr"))
-       rs6000_debug_addr = 1;
-      else if (! strcmp (rs6000_debug_name, "cost"))
-       rs6000_debug_cost = 1;
-      else
-       error ("unknown -mdebug-%s switch", rs6000_debug_name);
-
+  if (global_init_p)
+    {
       /* If the appropriate debug option is enabled, replace the target hooks
         with debug versions that call the real version and then prints
         debugging information.  */
@@ -2813,53 +2733,68 @@ rs6000_option_override_internal (const char *default_cpu)
          rs6000_mode_dependent_address_ptr
            = rs6000_debug_mode_dependent_address;
        }
-    }
 
-  if (rs6000_traceback_name)
-    {
-      if (! strncmp (rs6000_traceback_name, "full", 4))
-       rs6000_traceback = traceback_full;
-      else if (! strncmp (rs6000_traceback_name, "part", 4))
-       rs6000_traceback = traceback_part;
-      else if (! strncmp (rs6000_traceback_name, "no", 2))
-       rs6000_traceback = traceback_none;
-      else
-       error ("unknown -mtraceback arg %qs; expecting %<full%>, %<partial%> or %<none%>",
-              rs6000_traceback_name);
+      if (rs6000_veclibabi_name)
+       {
+         if (strcmp (rs6000_veclibabi_name, "mass") == 0)
+           rs6000_veclib_handler = rs6000_builtin_vectorized_libmass;
+         else
+           {
+             error ("unknown vectorization library ABI type (%s) for "
+                    "-mveclibabi= switch", rs6000_veclibabi_name);
+             ret = false;
+           }
+       }
     }
 
-  if (rs6000_veclibabi_name)
+  if (!global_options_set.x_rs6000_long_double_type_size)
     {
-      if (strcmp (rs6000_veclibabi_name, "mass") == 0)
-       rs6000_veclib_handler = rs6000_builtin_vectorized_libmass;
+      if (main_target_opt != NULL
+         && (main_target_opt->x_rs6000_long_double_type_size
+             != RS6000_DEFAULT_LONG_DOUBLE_SIZE))
+       error ("target attribute or pragma changes long double size");
       else
-       error ("unknown vectorization library ABI type (%s) for "
-              "-mveclibabi= switch", rs6000_veclibabi_name);
+       rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
-  if (!rs6000_explicit_options.long_double)
-    rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
-
 #ifndef POWERPC_LINUX
-  if (!rs6000_explicit_options.ieee)
+  if (!global_options_set.x_rs6000_ieeequad)
     rs6000_ieeequad = 1;
 #endif
 
+  /* Disable VSX and Altivec silently if the user switched cpus to power7 in a
+     target attribute or pragma which automatically enables both options,
+     unless the altivec ABI was set.  This is set by default for 64-bit, but
+     not for 32-bit.  */
+  if (main_target_opt != NULL && !main_target_opt->x_rs6000_altivec_abi)
+    target_flags &= ~((MASK_VSX | MASK_ALTIVEC) & ~target_flags_explicit);
+
   /* Enable Altivec ABI for AIX -maltivec.  */
   if (TARGET_XCOFF && (TARGET_ALTIVEC || TARGET_VSX))
-    rs6000_altivec_abi = 1;
+    {
+      if (main_target_opt != NULL && !main_target_opt->x_rs6000_altivec_abi)
+       error ("target attribute or pragma changes AltiVec ABI");
+      else
+       rs6000_altivec_abi = 1;
+    }
 
   /* The AltiVec ABI is the default for PowerPC-64 GNU/Linux.  For
      PowerPC-32 GNU/Linux, -maltivec implies the AltiVec ABI.  It can
      be explicitly overridden in either case.  */
   if (TARGET_ELF)
     {
-      if (!rs6000_explicit_options.altivec_abi
+      if (!global_options_set.x_rs6000_altivec_abi
          && (TARGET_64BIT || TARGET_ALTIVEC || TARGET_VSX))
-       rs6000_altivec_abi = 1;
+       {
+         if (main_target_opt != NULL &&
+             !main_target_opt->x_rs6000_altivec_abi)
+           error ("target attribute or pragma changes AltiVec ABI");
+         else
+           rs6000_altivec_abi = 1;
+       }
 
       /* Enable VRSAVE for AltiVec ABI, unless explicitly overridden.  */
-      if (!rs6000_explicit_options.vrsave)
+      if (!global_options_set.x_TARGET_ALTIVEC_VRSAVE)
        TARGET_ALTIVEC_VRSAVE = rs6000_altivec_abi;
     }
 
@@ -2869,9 +2804,14 @@ rs6000_option_override_internal (const char *default_cpu)
       && DEFAULT_ABI == ABI_DARWIN 
       && TARGET_64BIT)
     {
-      rs6000_darwin64_abi = 1;
-      /* Default to natural alignment, for better performance.  */
-      rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+      if (main_target_opt != NULL && !main_target_opt->x_rs6000_darwin64_abi)
+       error ("target attribute or pragma changes darwin64 ABI");
+      else
+       {
+         rs6000_darwin64_abi = 1;
+         /* Default to natural alignment, for better performance.  */
+         rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+       }
     }
 
   /* Place FP constants in the constant pool instead of TOC
@@ -2879,9 +2819,6 @@ rs6000_option_override_internal (const char *default_cpu)
   if (flag_section_anchors)
     TARGET_NO_FP_IN_TOC = 1;
 
-  /* Handle -mtls-size option.  */
-  rs6000_parse_tls_size_option ();
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
@@ -2900,17 +2837,25 @@ rs6000_option_override_internal (const char *default_cpu)
       if ((target_flags & MASK_STRING) != 0)
        target_flags = target_flags & ~MASK_STRING;
     }
-  else if (rs6000_select[1].string != NULL)
+  else if (global_options_set.x_rs6000_cpu_index)
     {
       /* For the powerpc-eabispe configuration, we set all these by
         default, so let's unset them if we manually set another
         CPU that is not the E500.  */
-      if (!rs6000_explicit_options.spe_abi)
-       rs6000_spe_abi = 0;
-      if (!rs6000_explicit_options.spe)
-       rs6000_spe = 0;
-      if (!rs6000_explicit_options.float_gprs)
-       rs6000_float_gprs = 0;
+      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;
     }
@@ -2934,14 +2879,15 @@ rs6000_option_override_internal (const char *default_cpu)
                                 || rs6000_cpu == PROCESSOR_PPCE500MC
                                 || rs6000_cpu == PROCESSOR_PPCE500MC64);
 
-  /* Allow debug switches to override the above settings.  */
-  if (TARGET_ALWAYS_HINT > 0)
+  /* 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.  */
+  if (TARGET_ALWAYS_HINT >= 0)
     rs6000_always_hint = TARGET_ALWAYS_HINT;
 
-  if (TARGET_SCHED_GROUPS > 0)
+  if (TARGET_SCHED_GROUPS >= 0)
     rs6000_sched_groups = TARGET_SCHED_GROUPS;
 
-  if (TARGET_ALIGN_BRANCH_TARGETS > 0)
+  if (TARGET_ALIGN_BRANCH_TARGETS >= 0)
     rs6000_align_branch_targets = TARGET_ALIGN_BRANCH_TARGETS;
 
   rs6000_sched_restricted_insns_priority
@@ -2983,79 +2929,83 @@ rs6000_option_override_internal (const char *default_cpu)
                                    atoi (rs6000_sched_insert_nops_str));
     }
 
+  if (global_init_p)
+    {
 #ifdef TARGET_REGNAMES
-  /* If the user desires alternate register names, copy in the
-     alternate names now.  */
-  if (TARGET_REGNAMES)
-    memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
+      /* If the user desires alternate register names, copy in the
+        alternate names now.  */
+      if (TARGET_REGNAMES)
+       memcpy (rs6000_reg_names, alt_reg_names, sizeof (rs6000_reg_names));
 #endif
 
-  /* Set aix_struct_return last, after the ABI is determined.
-     If -maix-struct-return or -msvr4-struct-return was explicitly
-     used, don't override with the ABI default.  */
-  if (!rs6000_explicit_options.aix_struct_ret)
-    aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
+      /* Set aix_struct_return last, after the ABI is determined.
+        If -maix-struct-return or -msvr4-struct-return was explicitly
+        used, don't override with the ABI default.  */
+      if (!global_options_set.x_aix_struct_return)
+       aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
 
 #if 0
-  /* IBM XL compiler defaults to unsigned bitfields.  */
-  if (TARGET_XL_COMPAT)
-    flag_signed_bitfields = 0;
+      /* IBM XL compiler defaults to unsigned bitfields.  */
+      if (TARGET_XL_COMPAT)
+       flag_signed_bitfields = 0;
 #endif
 
-  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
-    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
+      if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
+       REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
 
-  if (TARGET_TOC)
-    ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
-
-  /* We can only guarantee the availability of DI pseudo-ops when
-     assembling for 64-bit targets.  */
-  if (!TARGET_64BIT)
-    {
-      targetm.asm_out.aligned_op.di = NULL;
-      targetm.asm_out.unaligned_op.di = NULL;
-    }
+      if (TARGET_TOC)
+       ASM_GENERATE_INTERNAL_LABEL (toc_label_name, "LCTOC", 1);
 
-  /* Set branch target alignment, if not optimizing for size.  */
-  if (!optimize_size)
-    {
-      /* Cell wants to be aligned 8byte for dual issue.  Titan wants to be
-        aligned 8byte to avoid misprediction by the branch predictor.  */
-      if (rs6000_cpu == PROCESSOR_TITAN
-         || rs6000_cpu == PROCESSOR_CELL)
+      /* We can only guarantee the availability of DI pseudo-ops when
+        assembling for 64-bit targets.  */
+      if (!TARGET_64BIT)
        {
-         if (align_functions <= 0)
-           align_functions = 8;
-         if (align_jumps <= 0)
-           align_jumps = 8;
-         if (align_loops <= 0)
-           align_loops = 8;
-       }
-      if (rs6000_align_branch_targets)
+         targetm.asm_out.aligned_op.di = NULL;
+         targetm.asm_out.unaligned_op.di = NULL;
+       }
+
+
+      /* Set branch target alignment, if not optimizing for size.  */
+      if (!optimize_size)
        {
-         if (align_functions <= 0)
-           align_functions = 16;
-         if (align_jumps <= 0)
-           align_jumps = 16;
-         if (align_loops <= 0)
+         /* Cell wants to be aligned 8byte for dual issue.  Titan wants to be
+            aligned 8byte to avoid misprediction by the branch predictor.  */
+         if (rs6000_cpu == PROCESSOR_TITAN
+             || rs6000_cpu == PROCESSOR_CELL)
+           {
+             if (align_functions <= 0)
+               align_functions = 8;
+             if (align_jumps <= 0)
+               align_jumps = 8;
+             if (align_loops <= 0)
+               align_loops = 8;
+           }
+         if (rs6000_align_branch_targets)
            {
-             can_override_loop_align = 1;
-             align_loops = 16;
+             if (align_functions <= 0)
+               align_functions = 16;
+             if (align_jumps <= 0)
+               align_jumps = 16;
+             if (align_loops <= 0)
+               {
+                 can_override_loop_align = 1;
+                 align_loops = 16;
+               }
            }
+         if (align_jumps_max_skip <= 0)
+           align_jumps_max_skip = 15;
+         if (align_loops_max_skip <= 0)
+           align_loops_max_skip = 15;
        }
-      if (align_jumps_max_skip <= 0)
-       align_jumps_max_skip = 15;
-      if (align_loops_max_skip <= 0)
-       align_loops_max_skip = 15;
-    }
 
-  /* Arrange to save and restore machine status around nested functions.  */
-  init_machine_status = rs6000_init_machine_status;
+      /* Arrange to save and restore machine status around nested functions.  */
+      init_machine_status = rs6000_init_machine_status;
 
-  /* We should always be splitting complex arguments, but we can't break
-     Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
-  if (DEFAULT_ABI != ABI_AIX)
-    targetm.calls.split_complex_arg = NULL;
+      /* We should always be splitting complex arguments, but we can't break
+        Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
+      if (DEFAULT_ABI != ABI_AIX)
+       targetm.calls.split_complex_arg = NULL;
+    }
 
   /* Initialize rs6000_cost with the appropriate target costs.  */
   if (optimize_size)
@@ -3174,25 +3124,29 @@ rs6000_option_override_internal (const char *default_cpu)
        gcc_unreachable ();
       }
 
-  maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
-                        rs6000_cost->simultaneous_prefetches,
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-  maybe_set_param_value (PARAM_L1_CACHE_SIZE, rs6000_cost->l1_cache_size,
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-  maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
-                        rs6000_cost->cache_line_size,
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-  maybe_set_param_value (PARAM_L2_CACHE_SIZE, rs6000_cost->l2_cache_size,
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-
-  /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
-     can be optimized to ap = __builtin_next_arg (0).  */
-  if (DEFAULT_ABI != ABI_V4)
-    targetm.expand_builtin_va_start = NULL;
+  if (global_init_p)
+    {
+      maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
+                            rs6000_cost->simultaneous_prefetches,
+                            global_options.x_param_values,
+                            global_options_set.x_param_values);
+      maybe_set_param_value (PARAM_L1_CACHE_SIZE, rs6000_cost->l1_cache_size,
+                            global_options.x_param_values,
+                            global_options_set.x_param_values);
+      maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
+                            rs6000_cost->cache_line_size,
+                            global_options.x_param_values,
+                            global_options_set.x_param_values);
+      maybe_set_param_value (PARAM_L2_CACHE_SIZE, rs6000_cost->l2_cache_size,
+                            global_options.x_param_values,
+                            global_options_set.x_param_values);
+
+      /* If using typedef char *va_list, signal that
+        __builtin_va_start (&ap, 0) can be optimized to
+        ap = __builtin_next_arg (0).  */
+      if (DEFAULT_ABI != ABI_V4)
+       targetm.expand_builtin_va_start = NULL;
+    }
 
   /* Set up single/double float flags.  
      If TARGET_HARD_FLOAT is set, but neither single or double is set, 
@@ -3211,12 +3165,25 @@ rs6000_option_override_internal (const char *default_cpu)
       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)
-    /* Avoid indexed addressing when targeting Power6 in order to avoid
-     the DERAT mispredict penalty.  */
-    TARGET_AVOID_XFORM = (rs6000_cpu == PROCESSOR_POWER6 && TARGET_CMPB);
+    /* Avoid indexed addressing when targeting Power6 in order to avoid the
+     DERAT mispredict penalty.  However the LVE and STVE altivec instructions
+     need indexed accesses and the type used is the scalar type of the element
+     being loaded or stored.  */
+    TARGET_AVOID_XFORM = (rs6000_cpu == PROCESSOR_POWER6 && TARGET_CMPB
+                         && !TARGET_ALTIVEC);
 
   /* Set the -mrecip options.  */
   if (rs6000_recip_name)
@@ -3254,6 +3221,7 @@ rs6000_option_override_internal (const char *default_cpu)
                  error ("unknown option for -mrecip=%s", q);
                  invert = false;
                  mask = 0;
+                 ret = false;
                }
            }
 
@@ -3264,7 +3232,19 @@ rs6000_option_override_internal (const char *default_cpu)
        }
     }
 
-  rs6000_init_hard_regno_mode_ok ();
+  rs6000_init_hard_regno_mode_ok (global_init_p);
+
+  /* Save the initial options in case the user does function specific options */
+  if (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;
 }
 
 /* Implement TARGET_OPTION_OVERRIDE.  On the RS/6000 this is used to
@@ -3273,9 +3253,10 @@ rs6000_option_override_internal (const char *default_cpu)
 static void
 rs6000_option_override (void)
 {
-  rs6000_option_override_internal (OPTION_TARGET_CPU_DEFAULT);
+  (void) rs6000_option_override_internal (true);
 }
 
+\f
 /* Implement targetm.vectorize.builtin_mask_for_load.  */
 static tree
 rs6000_builtin_mask_for_load (void)
@@ -3494,65 +3475,6 @@ 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,
@@ -3694,98 +3616,26 @@ rs6000_preferred_simd_mode (enum machine_mode mode)
   return word_mode;
 }
 
-/* Handle generic options of the form -mfoo=yes/no.
-   NAME is the option name.
-   VALUE is the option value.
-   FLAG is the pointer to the flag where to store a 1 or 0, depending on
-   whether the option value is 'yes' or 'no' respectively.  */
-static void
-rs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
-{
-  if (value == 0)
-    return;
-  else if (!strcmp (value, "yes"))
-    *flag = 1;
-  else if (!strcmp (value, "no"))
-    *flag = 0;
-  else
-    error ("unknown -m%s= option specified: '%s'", name, value);
-}
-
-/* Validate and record the size specified with the -mtls-size option.  */
+/* Handler for the Mathematical Acceleration Subsystem (mass) interface to a
+   library with vectorized intrinsics.  */
 
-static void
-rs6000_parse_tls_size_option (void)
+static tree
+rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
 {
-  if (rs6000_tls_size_string == 0)
-    return;
-  else if (strcmp (rs6000_tls_size_string, "16") == 0)
-    rs6000_tls_size = 16;
-  else if (strcmp (rs6000_tls_size_string, "32") == 0)
-    rs6000_tls_size = 32;
-  else if (strcmp (rs6000_tls_size_string, "64") == 0)
-    rs6000_tls_size = 64;
-  else
-    error ("bad value %qs for -mtls-size switch", rs6000_tls_size_string);
-}
+  char name[32];
+  const char *suffix = NULL;
+  tree fntype, new_fndecl, bdecl = NULL_TREE;
+  int n_args = 1;
+  const char *bname;
+  enum machine_mode el_mode, in_mode;
+  int n, in_n;
 
-/* Implement TARGET_OPTION_INIT_STRUCT.  */
-
-static void
-rs6000_option_init_struct (struct gcc_options *opts)
-{
-  if (DEFAULT_ABI == ABI_DARWIN)
-    /* The Darwin libraries never set errno, so we might as well
-       avoid calling them when that's the only reason we would.  */
-    opts->x_flag_errno_math = 0;
-
-  /* Enable section anchors by default.  */
-  if (!TARGET_MACHO)
-    opts->x_flag_section_anchors = 1;
-}
-
-/* Implement TARGET_OPTION_DEFAULT_PARAMS.  */
-
-static void
-rs6000_option_default_params (void)
-{
-  /* Double growth factor to counter reduced min jump length.  */
-  set_default_param_value (PARAM_MAX_GROW_COPY_BB_INSNS, 16);
-}
-
-static enum fpu_type_t
-rs6000_parse_fpu_option (const char *option)
-{
-  if (!strcmp("none", option)) return FPU_NONE;
-  if (!strcmp("sp_lite", option)) return FPU_SF_LITE;
-  if (!strcmp("dp_lite", option)) return FPU_DF_LITE;
-  if (!strcmp("sp_full", option)) return FPU_SF_FULL;
-  if (!strcmp("dp_full", option)) return FPU_DF_FULL;
-  error("unknown value %s for -mfpu", option);
-  return FPU_NONE;
-}
-
-
-/* Handler for the Mathematical Acceleration Subsystem (mass) interface to a
-   library with vectorized intrinsics.  */
-
-static tree
-rs6000_builtin_vectorized_libmass (tree fndecl, tree type_out, tree type_in)
-{
-  char name[32];
-  const char *suffix = NULL;
-  tree fntype, new_fndecl, bdecl = NULL_TREE;
-  int n_args = 1;
-  const char *bname;
-  enum machine_mode el_mode, in_mode;
-  int n, in_n;
-
-  /* Libmass is suitable for unsafe math only as it does not correctly support
-     parts of IEEE with the required precision such as denormals.  Only support
-     it if we have VSX to use the simd d2 or f4 functions.
-     XXX: Add variable length support.  */
-  if (!flag_unsafe_math_optimizations || !TARGET_VSX)
-    return NULL_TREE;
+  /* Libmass is suitable for unsafe math only as it does not correctly support
+     parts of IEEE with the required precision such as denormals.  Only support
+     it if we have VSX to use the simd d2 or f4 functions.
+     XXX: Add variable length support.  */
+  if (!flag_unsafe_math_optimizations || !TARGET_VSX)
+    return NULL_TREE;
 
   el_mode = TYPE_MODE (TREE_TYPE (type_out));
   n = TYPE_VECTOR_SUBPARTS (type_out);
@@ -3830,7 +3680,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)
@@ -3867,7 +3717,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)
@@ -4092,423 +3942,50 @@ rs6000_builtin_vectorized_function (tree fndecl, tree type_out,
 
   return NULL_TREE;
 }
-
-
-/* Implement TARGET_HANDLE_OPTION.  */
-
-static bool
-rs6000_handle_option (size_t code, const char *arg, int value)
-{
-  enum fpu_type_t fpu_type = FPU_NONE;
-  int isel;
-
-  switch (code)
-    {
-    case OPT_mno_power:
-      target_flags &= ~(MASK_POWER | MASK_POWER2
-                       | MASK_MULTIPLE | MASK_STRING);
-      target_flags_explicit |= (MASK_POWER | MASK_POWER2
-                               | MASK_MULTIPLE | MASK_STRING);
-      break;
-    case OPT_mno_powerpc:
-      target_flags &= ~(MASK_POWERPC | MASK_PPC_GPOPT
-                       | MASK_PPC_GFXOPT | MASK_POWERPC64);
-      target_flags_explicit |= (MASK_POWERPC | MASK_PPC_GPOPT
-                               | MASK_PPC_GFXOPT | MASK_POWERPC64);
-      break;
-    case OPT_mfull_toc:
-      target_flags &= ~MASK_MINIMAL_TOC;
-      TARGET_NO_FP_IN_TOC = 0;
-      TARGET_NO_SUM_IN_TOC = 0;
-      target_flags_explicit |= MASK_MINIMAL_TOC;
-#ifdef TARGET_USES_SYSV4_OPT
-      /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
-        just the same as -mminimal-toc.  */
-      target_flags |= MASK_MINIMAL_TOC;
-      target_flags_explicit |= MASK_MINIMAL_TOC;
-#endif
-      break;
-
-#ifdef TARGET_USES_SYSV4_OPT
-    case OPT_mtoc:
-      /* Make -mtoc behave like -mminimal-toc.  */
-      target_flags |= MASK_MINIMAL_TOC;
-      target_flags_explicit |= MASK_MINIMAL_TOC;
-      break;
-#endif
-
-#if defined (HAVE_LD_LARGE_TOC) && defined (TARGET_USES_LINUX64_OPT)
-    case OPT_mcmodel_:
-      if (strcmp (arg, "small") == 0)
-       cmodel = CMODEL_SMALL;
-      else if (strcmp (arg, "medium") == 0)
-       cmodel = CMODEL_MEDIUM;
-      else if (strcmp (arg, "large") == 0)
-       cmodel = CMODEL_LARGE;
-      else
-       {
-         error ("invalid option for -mcmodel: '%s'", arg);
-         return false;
-       }
-      rs6000_explicit_options.cmodel = true;
-#endif
-
-#ifdef TARGET_USES_AIX64_OPT
-    case OPT_maix64:
-#else
-    case OPT_m64:
-#endif
-      target_flags |= MASK_POWERPC64 | MASK_POWERPC;
-      target_flags |= ~target_flags_explicit & MASK_PPC_GFXOPT;
-      target_flags_explicit |= MASK_POWERPC64 | MASK_POWERPC;
-      break;
-
-#ifdef TARGET_USES_AIX64_OPT
-    case OPT_maix32:
-#else
-    case OPT_m32:
-#endif
-      target_flags &= ~MASK_POWERPC64;
-      target_flags_explicit |= MASK_POWERPC64;
-      break;
-
-    case OPT_minsert_sched_nops_:
-      rs6000_sched_insert_nops_str = arg;
-      break;
-
-    case OPT_mminimal_toc:
-      if (value == 1)
-       {
-         TARGET_NO_FP_IN_TOC = 0;
-         TARGET_NO_SUM_IN_TOC = 0;
-       }
-      break;
-
-    case OPT_mpower:
-      if (value == 1)
-       {
-         target_flags |= (MASK_MULTIPLE | MASK_STRING);
-         target_flags_explicit |= (MASK_MULTIPLE | MASK_STRING);
-       }
-      break;
-
-    case OPT_mpower2:
-      if (value == 1)
-       {
-         target_flags |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
-         target_flags_explicit |= (MASK_POWER | MASK_MULTIPLE | MASK_STRING);
-       }
-      break;
-
-    case OPT_mpowerpc_gpopt:
-    case OPT_mpowerpc_gfxopt:
-      if (value == 1)
-       {
-         target_flags |= MASK_POWERPC;
-         target_flags_explicit |= MASK_POWERPC;
-       }
-      break;
-
-    case OPT_maix_struct_return:
-    case OPT_msvr4_struct_return:
-      rs6000_explicit_options.aix_struct_ret = true;
-      break;
-
-    case OPT_mvrsave:
-      rs6000_explicit_options.vrsave = true;
-      TARGET_ALTIVEC_VRSAVE = value;
-      break;
-
-    case OPT_mvrsave_:
-      rs6000_explicit_options.vrsave = true;
-      rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
-      break;
-
-    case OPT_misel_:
-      target_flags_explicit |= MASK_ISEL;
-      isel = 0;
-      rs6000_parse_yes_no_option ("isel", arg, &isel);
-      if (isel)
-       target_flags |= MASK_ISEL;
-      else
-       target_flags &= ~MASK_ISEL;
-      break;
-
-    case OPT_mspe:
-      rs6000_explicit_options.spe = true;
-      rs6000_spe = value;
-      break;
-
-    case OPT_mspe_:
-      rs6000_explicit_options.spe = true;
-      rs6000_parse_yes_no_option ("spe", arg, &(rs6000_spe));
-      break;
-
-    case OPT_mdebug_:
-      rs6000_debug_name = arg;
-      break;
-
-#ifdef TARGET_USES_SYSV4_OPT
-    case OPT_mcall_:
-      rs6000_abi_name = arg;
-      break;
-
-    case OPT_msdata_:
-      rs6000_sdata_name = arg;
-      break;
-
-    case OPT_mtls_size_:
-      rs6000_tls_size_string = arg;
-      break;
-
-    case OPT_mrelocatable:
-      if (value == 1)
-       {
-         target_flags |= MASK_MINIMAL_TOC;
-         target_flags_explicit |= MASK_MINIMAL_TOC;
-         TARGET_NO_FP_IN_TOC = 1;
-       }
-      break;
-
-    case OPT_mrelocatable_lib:
-      if (value == 1)
-       {
-         target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
-         target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
-         TARGET_NO_FP_IN_TOC = 1;
-       }
-      else
-       {
-         target_flags &= ~MASK_RELOCATABLE;
-         target_flags_explicit |= MASK_RELOCATABLE;
-       }
-      break;
-#endif
-
-    case OPT_mabi_:
-      if (!strcmp (arg, "altivec"))
-       {
-         rs6000_explicit_options.altivec_abi = true;
-         rs6000_altivec_abi = 1;
-
-         /* Enabling the AltiVec ABI turns off the SPE ABI.  */
-         rs6000_spe_abi = 0;
-       }
-      else if (! strcmp (arg, "no-altivec"))
-       {
-         rs6000_explicit_options.altivec_abi = true;
-         rs6000_altivec_abi = 0;
-       }
-      else if (! strcmp (arg, "spe"))
-       {
-         rs6000_explicit_options.spe_abi = true;
-         rs6000_spe_abi = 1;
-         rs6000_altivec_abi = 0;
-         if (!TARGET_SPE_ABI)
-           error ("not configured for ABI: '%s'", arg);
-       }
-      else if (! strcmp (arg, "no-spe"))
-       {
-         rs6000_explicit_options.spe_abi = true;
-         rs6000_spe_abi = 0;
-       }
-
-      /* These are here for testing during development only, do not
-        document in the manual please.  */
-      else if (! strcmp (arg, "d64"))
-       {
-         rs6000_darwin64_abi = 1;
-         warning (0, "using darwin64 ABI");
-       }
-      else if (! strcmp (arg, "d32"))
-       {
-         rs6000_darwin64_abi = 0;
-         warning (0, "using old darwin ABI");
-       }
-
-      else if (! strcmp (arg, "ibmlongdouble"))
-       {
-         rs6000_explicit_options.ieee = true;
-         rs6000_ieeequad = 0;
-         warning (0, "using IBM extended precision long double");
-       }
-      else if (! strcmp (arg, "ieeelongdouble"))
-       {
-         rs6000_explicit_options.ieee = true;
-         rs6000_ieeequad = 1;
-         warning (0, "using IEEE extended precision long double");
-       }
-
-      else
-       {
-         error ("unknown ABI specified: '%s'", arg);
-         return false;
-       }
-      break;
-
-    case OPT_mcpu_:
-      rs6000_select[1].string = arg;
-      break;
-
-    case OPT_mtune_:
-      rs6000_select[2].string = arg;
-      break;
-
-    case OPT_mtraceback_:
-      rs6000_traceback_name = arg;
-      break;
-
-    case OPT_mfloat_gprs_:
-      rs6000_explicit_options.float_gprs = true;
-      if (! strcmp (arg, "yes") || ! strcmp (arg, "single"))
-       rs6000_float_gprs = 1;
-      else if (! strcmp (arg, "double"))
-       rs6000_float_gprs = 2;
-      else if (! strcmp (arg, "no"))
-       rs6000_float_gprs = 0;
-      else
-       {
-         error ("invalid option for -mfloat-gprs: '%s'", arg);
-         return false;
-       }
-      break;
-
-    case OPT_mlong_double_:
-      rs6000_explicit_options.long_double = true;
-      rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
-      if (value != 64 && value != 128)
-       {
-         error ("unknown switch -mlong-double-%s", arg);
-         rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
-         return false;
-       }
-      else
-       rs6000_long_double_type_size = value;
-      break;
-
-    case OPT_msched_costly_dep_:
-      rs6000_sched_costly_dep_str = arg;
-      break;
-
-    case OPT_malign_:
-      rs6000_explicit_options.alignment = true;
-      if (! strcmp (arg, "power"))
-       {
-         /* On 64-bit Darwin, power alignment is ABI-incompatible with
-            some C library functions, so warn about it. The flag may be
-            useful for performance studies from time to time though, so
-            don't disable it entirely.  */
-         if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
-           warning (0, "-malign-power is not supported for 64-bit Darwin;"
-                    " it is incompatible with the installed C and C++ libraries");
-         rs6000_alignment_flags = MASK_ALIGN_POWER;
-       }
-      else if (! strcmp (arg, "natural"))
-       rs6000_alignment_flags = MASK_ALIGN_NATURAL;
-      else
-       {
-         error ("unknown -malign-XXXXX option specified: '%s'", arg);
-         return false;
-       }
-      break;
-
-    case OPT_msingle_float:
-      if (!TARGET_SINGLE_FPU) 
-       warning (0, "-msingle-float option equivalent to -mhard-float");
-      /* -msingle-float implies -mno-double-float and TARGET_HARD_FLOAT. */
-      rs6000_double_float = 0;
-      target_flags &= ~MASK_SOFT_FLOAT;
-      target_flags_explicit |= MASK_SOFT_FLOAT;
-      break;
-
-    case OPT_mdouble_float:
-      /* -mdouble-float implies -msingle-float and TARGET_HARD_FLOAT. */
-      rs6000_single_float = 1;
-      target_flags &= ~MASK_SOFT_FLOAT;
-      target_flags_explicit |= MASK_SOFT_FLOAT;
-      break;
-
-    case OPT_msimple_fpu:
-      if (!TARGET_SINGLE_FPU) 
-       warning (0, "-msimple-fpu option ignored");
-      break;
-
-    case OPT_mhard_float:
-      /* -mhard_float implies -msingle-float and -mdouble-float. */
-      rs6000_single_float = rs6000_double_float = 1;
-      break;
-
-    case OPT_msoft_float:
-      /* -msoft_float implies -mnosingle-float and -mnodouble-float. */
-      rs6000_single_float = rs6000_double_float = 0;
-      break;
-
-    case OPT_mfpu_:
-      fpu_type = rs6000_parse_fpu_option(arg);
-      if (fpu_type != FPU_NONE) 
-      /* If -mfpu is not none, then turn off SOFT_FLOAT, turn on HARD_FLOAT. */
-      {
-        target_flags &= ~MASK_SOFT_FLOAT;
-        target_flags_explicit |= MASK_SOFT_FLOAT;
-        rs6000_xilinx_fpu = 1;
-        if (fpu_type == FPU_SF_LITE || fpu_type == FPU_SF_FULL) 
-        rs6000_single_float = 1;
-        if (fpu_type == FPU_DF_LITE || fpu_type == FPU_DF_FULL) 
-          rs6000_single_float = rs6000_double_float = 1;
-        if (fpu_type == FPU_SF_LITE || fpu_type == FPU_DF_LITE) 
-          rs6000_simple_fpu = 1;
-      }
-      else
-      {
-        /* -mfpu=none is equivalent to -msoft-float */
-        target_flags |= MASK_SOFT_FLOAT;
-        target_flags_explicit |= MASK_SOFT_FLOAT;
-        rs6000_single_float = rs6000_double_float = 0;
-      }
-
-    case OPT_mrecip:
-      rs6000_recip_name = (value) ? "default" : "none";
-      break;
-
-    case OPT_mrecip_:
-      rs6000_recip_name = arg;
-      break;
-    }
-  return true;
-}
 \f
+/* Default CPU string for rs6000*_file_start functions.  */
+static const char *rs6000_default_cpu;
+
 /* Do anything needed at the start of the asm file.  */
 
 static void
 rs6000_file_start (void)
 {
-  size_t i;
   char buffer[80];
   const char *start = buffer;
-  struct rs6000_cpu_select *ptr;
-  const char *default_cpu = TARGET_CPU_DEFAULT;
   FILE *file = asm_out_file;
 
+  rs6000_default_cpu = TARGET_CPU_DEFAULT;
+
   default_file_start ();
 
 #ifdef TARGET_BI_ARCH
   if ((TARGET_DEFAULT ^ target_flags) & MASK_64BIT)
-    default_cpu = 0;
+    rs6000_default_cpu = 0;
 #endif
 
   if (flag_verbose_asm)
     {
       sprintf (buffer, "\n%s rs6000/powerpc options:", ASM_COMMENT_START);
-      rs6000_select[0].string = default_cpu;
 
-      for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
+      if (rs6000_default_cpu != 0 && rs6000_default_cpu[0] != '\0')
        {
-         ptr = &rs6000_select[i];
-         if (ptr->string != (char *)0 && ptr->string[0] != '\0')
-           {
-             fprintf (file, "%s %s%s", start, ptr->name, ptr->string);
-             start = "";
-           }
+         fprintf (file, "%s --with-cpu=%s", start, rs6000_default_cpu);
+         start = "";
+       }
+
+      if (global_options_set.x_rs6000_cpu_index)
+       {
+         fprintf (file, "%s -mcpu=%s", start,
+                  processor_target_table[rs6000_cpu_index].name);
+         start = "";
+       }
+
+      if (global_options_set.x_rs6000_tune_index)
+       {
+         fprintf (file, "%s -mtune=%s", start,
+                  processor_target_table[rs6000_tune_index].name);
+         start = "";
        }
 
       if (PPC405_ERRATUM77)
@@ -4538,23 +4015,6 @@ rs6000_file_start (void)
        putc ('\n', file);
     }
 
-#ifdef HAVE_AS_GNU_ATTRIBUTE
-  if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
-    {
-      fprintf (file, "\t.gnu_attribute 4, %d\n",
-              ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) ? 1 
-               : (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT) ? 3 
-               : 2));
-      fprintf (file, "\t.gnu_attribute 8, %d\n",
-              (TARGET_ALTIVEC_ABI ? 2
-               : TARGET_SPE_ABI ? 3
-               : 1));
-      fprintf (file, "\t.gnu_attribute 12, %d\n",
-              aix_struct_return ? 2 : 1);
-
-    }
-#endif
-
   if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
     {
       switch_to_section (toc_section);
@@ -4707,7 +4167,13 @@ num_insns_constant (rtx op, enum machine_mode mode)
 HOST_WIDE_INT
 const_vector_elt_as_int (rtx op, unsigned int elt)
 {
-  rtx tmp = CONST_VECTOR_ELT (op, elt);
+  rtx tmp;
+
+  /* We can't handle V2DImode and V2DFmode vector constants here yet.  */
+  gcc_assert (GET_MODE (op) != V2DImode
+             && GET_MODE (op) != V2DFmode);
+
+  tmp = CONST_VECTOR_ELT (op, elt);
   if (GET_MODE (op) == V4SFmode
       || GET_MODE (op) == V2SFmode)
     tmp = gen_lowpart (SImode, tmp);
@@ -4728,13 +4194,24 @@ vspltis_constant (rtx op, unsigned step, unsigned copies)
   enum machine_mode inner = GET_MODE_INNER (mode);
 
   unsigned i;
-  unsigned nunits = GET_MODE_NUNITS (mode);
-  unsigned bitsize = GET_MODE_BITSIZE (inner);
-  unsigned mask = GET_MODE_MASK (inner);
+  unsigned nunits;
+  unsigned bitsize;
+  unsigned mask;
+
+  HOST_WIDE_INT val;
+  HOST_WIDE_INT splat_val;
+  HOST_WIDE_INT msb_val;
+
+  if (mode == V2DImode || mode == V2DFmode)
+    return false;
+
+  nunits = GET_MODE_NUNITS (mode);
+  bitsize = GET_MODE_BITSIZE (inner);
+  mask = GET_MODE_MASK (inner);
 
-  HOST_WIDE_INT val = const_vector_elt_as_int (op, nunits - 1);
-  HOST_WIDE_INT splat_val = val;
-  HOST_WIDE_INT msb_val = val > 0 ? 0 : -1;
+  val = const_vector_elt_as_int (op, nunits - 1);
+  splat_val = val;
+  msb_val = val > 0 ? 0 : -1;
 
   /* Construct the value to be splatted, if possible.  If not, return 0.  */
   for (i = 2; i <= copies; i *= 2)
@@ -4798,6 +4275,29 @@ easy_altivec_constant (rtx op, enum machine_mode mode)
   else if (mode != GET_MODE (op))
     return false;
 
+  /* V2DI/V2DF was added with VSX.  Only allow 0 and all 1's as easy
+     constants.  */
+  if (mode == V2DFmode)
+    return zero_constant (op, mode);
+
+  if (mode == V2DImode)
+    {
+      /* In case the compiler is built 32-bit, CONST_DOUBLE constants are not
+        easy.  */
+      if (GET_CODE (CONST_VECTOR_ELT (op, 0)) != CONST_INT
+         || GET_CODE (CONST_VECTOR_ELT (op, 1)) != CONST_INT)
+       return false;
+
+      if (zero_constant (op, mode))
+       return true;
+
+      if (INTVAL (CONST_VECTOR_ELT (op, 0)) == -1
+         && INTVAL (CONST_VECTOR_ELT (op, 1)) == -1)
+       return true;
+
+      return false;
+    }
+
   /* Start with a vspltisw.  */
   step = GET_MODE_NUNITS (mode) / 4;
   copies = 1;
@@ -4874,8 +4374,16 @@ output_vec_const_move (rtx *operands)
   vec = operands[1];
   mode = GET_MODE (dest);
 
-  if (TARGET_VSX && zero_constant (vec, mode))
-    return "xxlxor %x0,%x0,%x0";
+  if (TARGET_VSX)
+    {
+      if (zero_constant (vec, mode))
+       return "xxlxor %x0,%x0,%x0";
+
+      if (mode == V2DImode
+         && INTVAL (CONST_VECTOR_ELT (vec, 0)) == -1
+         && INTVAL (CONST_VECTOR_ELT (vec, 1)) == -1)
+       return "vspltisw %0,-1";
+    }
 
   if (TARGET_ALTIVEC)
     {
@@ -4936,7 +4444,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)
@@ -5088,7 +4598,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;
@@ -5135,12 +4647,18 @@ rs6000_expand_vector_init (rtx target, rtx vals)
        }
       else
        {
-         rtx op0 = copy_to_reg (XVECEXP (vals, 0, 0));
-         rtx op1 = copy_to_reg (XVECEXP (vals, 0, 1));
          if (mode == V2DFmode)
-           emit_insn (gen_vsx_concat_v2df (target, op0, op1));
+           {
+             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));
+           }
          else
-           emit_insn (gen_vsx_concat_v2di (target, op0, op1));
+           {
+             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));
+           }
        }
       return;
     }
@@ -5181,7 +4699,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
 
   /* 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);
       emit_move_insn (adjust_address_nv (mem, inner_mode, 0),
@@ -5282,30 +4800,34 @@ rs6000_expand_vector_extract (rtx target, rtx vec, int elt)
 {
   enum machine_mode mode = GET_MODE (vec);
   enum machine_mode inner_mode = GET_MODE_INNER (mode);
-  rtx mem, x;
+  rtx mem;
 
-  if (VECTOR_MEM_VSX_P (mode) && (mode == V2DFmode || mode == V2DImode))
+  if (VECTOR_MEM_VSX_P (mode))
     {
-      rtx (*extract_func) (rtx, rtx, rtx)
-       = ((mode == V2DFmode) ? gen_vsx_extract_v2df : gen_vsx_extract_v2di);
-      emit_insn (extract_func (target, vec, GEN_INT (elt)));
-      return;
+      switch (mode)
+       {
+       default:
+         break;
+       case V2DFmode:
+         emit_insn (gen_vsx_extract_v2df (target, vec, GEN_INT (elt)));
+         return;
+       case V2DImode:
+         emit_insn (gen_vsx_extract_v2di (target, vec, GEN_INT (elt)));
+         return;
+       case V4SFmode:
+         emit_insn (gen_vsx_extract_v4sf (target, vec, GEN_INT (elt)));
+         return;
+       }
     }
 
   /* Allocate mode-sized buffer.  */
   mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
 
+  emit_move_insn (mem, vec);
+
   /* Add offset to field within buffer matching vector element.  */
-  mem = adjust_address_nv (mem, mode, elt * GET_MODE_SIZE (inner_mode));
+  mem = adjust_address_nv (mem, inner_mode, elt * GET_MODE_SIZE (inner_mode));
 
-  /* Store single field into mode-sized buffer.  */
-  x = gen_rtx_UNSPEC (VOIDmode,
-                     gen_rtvec (1, const0_rtx), UNSPEC_STVE);
-  emit_insn (gen_rtx_PARALLEL (VOIDmode,
-                              gen_rtvec (2,
-                                         gen_rtx_SET (VOIDmode,
-                                                      mem, vec),
-                                         x)));
   emit_move_insn (target, adjust_address_nv (mem, inner_mode, 0));
 }
 
@@ -5595,6 +5117,94 @@ virtual_stack_registers_memory_p (rtx op)
          && regnum <= LAST_VIRTUAL_POINTER_REGISTER);
 }
 
+/* Return true if memory accesses to OP are known to never straddle
+   a 32k boundary.  */
+
+static bool
+offsettable_ok_by_alignment (rtx op, HOST_WIDE_INT offset,
+                            enum machine_mode mode)
+{
+  tree decl, type;
+  unsigned HOST_WIDE_INT dsize, dalign;
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return false;
+
+  decl = SYMBOL_REF_DECL (op);
+  if (!decl)
+    {
+      if (GET_MODE_SIZE (mode) == 0)
+       return false;
+
+      /* -fsection-anchors loses the original SYMBOL_REF_DECL when
+        replacing memory addresses with an anchor plus offset.  We
+        could find the decl by rummaging around in the block->objects
+        VEC for the given offset but that seems like too much work.  */
+      dalign = 1;
+      if (SYMBOL_REF_HAS_BLOCK_INFO_P (op)
+         && SYMBOL_REF_ANCHOR_P (op)
+         && SYMBOL_REF_BLOCK (op) != NULL)
+       {
+         struct object_block *block = SYMBOL_REF_BLOCK (op);
+         HOST_WIDE_INT lsb, mask;
+
+         /* Given the alignment of the block..  */
+         dalign = block->alignment;
+         mask = dalign / BITS_PER_UNIT - 1;
+
+         /* ..and the combined offset of the anchor and any offset
+            to this block object..  */
+         offset += SYMBOL_REF_BLOCK_OFFSET (op);
+         lsb = offset & -offset;
+
+         /* ..find how many bits of the alignment we know for the
+            object.  */
+         mask &= lsb - 1;
+         dalign = mask + 1;
+       }
+      return dalign >= GET_MODE_SIZE (mode);
+    }
+
+  if (DECL_P (decl))
+    {
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       return true;
+
+      if (!DECL_SIZE_UNIT (decl))
+       return false;
+
+      if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
+       return false;
+
+      dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
+      if (dsize > 32768)
+       return false;
+
+      dalign = DECL_ALIGN_UNIT (decl);
+      return dalign >= dsize;
+    }
+
+  type = TREE_TYPE (decl);
+
+  if (TREE_CODE (decl) == STRING_CST)
+    dsize = TREE_STRING_LENGTH (decl);
+  else if (TYPE_SIZE_UNIT (type)
+          && host_integerp (TYPE_SIZE_UNIT (type), 1))
+    dsize = tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+  else
+    return false;
+  if (dsize > 32768)
+    return false;
+
+  dalign = TYPE_ALIGN (type);
+  if (CONSTANT_CLASS_P (decl))
+    dalign = CONSTANT_ALIGNMENT (decl, dalign);
+  else
+    dalign = DATA_ALIGNMENT (decl, dalign);
+  dalign /= BITS_PER_UNIT;
+  return dalign >= dsize;
+}
+
 static bool
 constant_pool_expr_p (rtx op)
 {
@@ -5619,8 +5229,12 @@ toc_relative_expr_p (rtx op)
          && XINT (tocrel_base, 1) == UNSPEC_TOCREL);
 }
 
+/* Return true if X is a constant pool address, and also for cmodel=medium
+   if X is a toc-relative address known to be offsettable within MODE.  */
+
 bool
-legitimate_constant_pool_address_p (const_rtx x, bool strict)
+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)
@@ -5629,7 +5243,12 @@ legitimate_constant_pool_address_p (const_rtx x, bool strict)
              || ((TARGET_MINIMAL_TOC
                   || TARGET_CMODEL != CMODEL_SMALL)
                  && INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict)))
-         && toc_relative_expr_p (XEXP (x, 1)));
+         && toc_relative_expr_p (XEXP (x, 1))
+         && (TARGET_CMODEL != CMODEL_MEDIUM
+             || constant_pool_expr_p (XVECEXP (tocrel_base, 0, 0))
+             || mode == QImode
+             || offsettable_ok_by_alignment (XVECEXP (tocrel_base, 0, 0),
+                                             INTVAL (tocrel_offset), mode)));
 }
 
 static bool
@@ -5657,7 +5276,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   if (!reg_offset_addressing_ok_p (mode))
     return virtual_stack_registers_memory_p (x);
-  if (legitimate_constant_pool_address_p (x, strict))
+  if (legitimate_constant_pool_address_p (x, mode, strict))
     return true;
   if (GET_CODE (XEXP (x, 1)) != CONST_INT)
     return false;
@@ -5718,7 +5337,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
@@ -6097,19 +5716,37 @@ rs6000_delegitimize_address (rtx orig_x)
   if (MEM_P (x))
     x = XEXP (x, 0);
 
-  if ((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)
+  if (GET_CODE (x) == (TARGET_CMODEL != CMODEL_SMALL ? LO_SUM : PLUS)
       && GET_CODE (XEXP (x, 1)) == CONST)
     {
+      rtx offset = NULL_RTX;
+
       y = XEXP (XEXP (x, 1), 0);
+      if (GET_CODE (y) == PLUS
+         && GET_MODE (y) == Pmode
+         && CONST_INT_P (XEXP (y, 1)))
+       {
+         offset = XEXP (y, 1);
+         y = XEXP (y, 0);
+       }
       if (GET_CODE (y) == UNSPEC
-          && XINT (y, 1) == UNSPEC_TOCREL)
+          && 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
@@ -6119,9 +5756,9 @@ rs6000_delegitimize_address (rtx orig_x)
 
   if (TARGET_MACHO
       && GET_CODE (orig_x) == LO_SUM
-      && GET_CODE (XEXP (x, 1)) == CONST)
+      && GET_CODE (XEXP (orig_x, 1)) == CONST)
     {
-      y = XEXP (XEXP (x, 1), 0);
+      y = XEXP (XEXP (orig_x, 1), 0);
       if (GET_CODE (y) == UNSPEC
          && XINT (y, 1) == UNSPEC_MACHOPIC_OFFSET)
        return XVECEXP (y, 0, 0);
@@ -6236,6 +5873,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);
@@ -6245,10 +5884,11 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
 
       if (model == TLS_MODEL_GLOBAL_DYNAMIC)
        {
-         r3 = gen_rtx_REG (Pmode, 3);
          tga = rs6000_tls_get_addr ();
-         emit_library_call_value (tga, dest, LCT_CONST, Pmode, 1, r3, Pmode);
+         emit_library_call_value (tga, dest, LCT_CONST, Pmode,
+                                  1, const0_rtx, Pmode);
 
+         r3 = gen_rtx_REG (Pmode, 3);
          if (DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
            insn = gen_tls_gd_aix64 (r3, got, addr, tga, const0_rtx);
          else if (DEFAULT_ABI == ABI_AIX && !TARGET_64BIT)
@@ -6265,11 +5905,12 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
        }
       else if (model == TLS_MODEL_LOCAL_DYNAMIC)
        {
-         r3 = gen_rtx_REG (Pmode, 3);
          tga = rs6000_tls_get_addr ();
          tmp1 = gen_reg_rtx (Pmode);
-         emit_library_call_value (tga, tmp1, LCT_CONST, Pmode, 1, r3, Pmode);
+         emit_library_call_value (tga, tmp1, LCT_CONST, Pmode,
+                                  1, const0_rtx, Pmode);
 
+         r3 = gen_rtx_REG (Pmode, 3);
          if (DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
            insn = gen_tls_ld_aix64 (r3, got, tga, const0_rtx);
          else if (DEFAULT_ABI == ABI_AIX && !TARGET_64BIT)
@@ -6339,7 +5980,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
 
 /* Return 1 if X contains a thread-local symbol.  */
 
-bool
+static bool
 rs6000_tls_referenced_p (rtx x)
 {
   if (! TARGET_HAVE_TLS)
@@ -6348,6 +5989,19 @@ rs6000_tls_referenced_p (rtx x)
   return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
 }
 
+/* Implement TARGET_CANNOT_FORCE_CONST_MEM.  */
+
+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)
+    return true;
+
+  return rs6000_tls_referenced_p (x);
+}
+
 /* Return 1 if *X is a thread-local symbol.  This is the same as
    rs6000_tls_symbol_ref except for the type of the unused argument.  */
 
@@ -6377,6 +6031,14 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 {
   bool reg_offset_p = reg_offset_addressing_ok_p (mode);
 
+  /* Nasty hack for vsx_splat_V2DF/V2DI load from mem, which takes a
+     DFmode/DImode MEM.  */
+  if (reg_offset_p
+      && opnum == 1
+      && ((mode == DFmode && recog_data.operand_mode[0] == V2DFmode)
+         || (mode == DImode && recog_data.operand_mode[0] == V2DImode)))
+    reg_offset_p = false;
+
   /* We must recognize output that we have already generated ourselves.  */
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == PLUS
@@ -6426,11 +6088,12 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && 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)) == HIGH
+      && 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 (x, 0), 1), 0), XEXP (x, 1)))
+      && rtx_equal_p (XEXP (XEXP (XEXP (XEXP (x, 0), 1), 0), 0), XEXP (x, 1)))
     {
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
                   BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
@@ -6651,7 +6314,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
     return 1;
   if (reg_offset_p && legitimate_small_data_p (mode, x))
     return 1;
-  if (reg_offset_p && legitimate_constant_pool_address_p (x, reg_ok_strict))
+  if (reg_offset_p
+      && legitimate_constant_pool_address_p (x, mode, reg_ok_strict))
     return 1;
   /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
   if (! reg_ok_strict
@@ -6761,7 +6425,7 @@ rs6000_mode_dependent_address (const_rtx addr)
     case LO_SUM:
       /* Anything in the constant pool is sufficiently aligned that
         all bytes have the same high part address.  */
-      return !legitimate_constant_pool_address_p (addr, false);
+      return !legitimate_constant_pool_address_p (addr, QImode, false);
 
     /* Auto-increment cases are now treated generically in recog.c.  */
     case PRE_MODIFY:
@@ -6840,11 +6504,14 @@ rs6000_offsettable_memref_p (rtx op)
 }
 
 /* Change register usage conditional on target flags.  */
-void
+static void
 rs6000_conditional_register_usage (void)
 {
   int i;
 
+  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.  */
@@ -7122,53 +6789,21 @@ rs6000_eliminate_indexed_memrefs (rtx operands[2])
 
   if (GET_CODE (operands[0]) == MEM
       && GET_CODE (XEXP (operands[0], 0)) != REG
-      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0), false))
+      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0),
+                                              GET_MODE (operands[0]), false))
     operands[0]
       = replace_equiv_address (operands[0],
                               copy_addr_to_reg (XEXP (operands[0], 0)));
 
   if (GET_CODE (operands[1]) == MEM
       && GET_CODE (XEXP (operands[1], 0)) != REG
-      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0), false))
+      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0),
+                                              GET_MODE (operands[1]), false))
     operands[1]
       = replace_equiv_address (operands[1],
                               copy_addr_to_reg (XEXP (operands[1], 0)));
 }
 
-/* Return true if memory accesses to DECL are known to never straddle
-   a 32k boundary.  */
-
-static bool
-offsettable_ok_by_alignment (tree decl)
-{
-  unsigned HOST_WIDE_INT dsize, dalign;
-
-  /* Presume any compiler generated symbol_ref is suitably aligned.  */
-  if (!decl)
-    return true;
-
-  if (TREE_CODE (decl) != VAR_DECL
-      && TREE_CODE (decl) != PARM_DECL
-      && TREE_CODE (decl) != RESULT_DECL
-      && TREE_CODE (decl) != FIELD_DECL)
-    return true;
-
-  if (!DECL_SIZE_UNIT (decl))
-    return false;
-
-  if (!host_integerp (DECL_SIZE_UNIT (decl), 1))
-    return false;
-
-  dsize = tree_low_cst (DECL_SIZE_UNIT (decl), 1);
-  if (dsize <= 1)
-    return true;
-  if (dsize > 32768)
-    return false;
-
-  dalign = DECL_ALIGN_UNIT (decl);
-  return dalign >= dsize;
-}
-
 /* Emit a move from SOURCE to DEST in mode MODE.  */
 void
 rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -7490,8 +7125,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
          || (TARGET_CMODEL == CMODEL_MEDIUM
              && GET_CODE (operands[1]) == SYMBOL_REF
              && !CONSTANT_POOL_ADDRESS_P (operands[1])
-             && SYMBOL_REF_LOCAL_P (operands[1])
-             && offsettable_ok_by_alignment (SYMBOL_REF_DECL (operands[1]))))
+             && SYMBOL_REF_LOCAL_P (operands[1])))
        {
          rtx reg = NULL_RTX;
          if (TARGET_CMODEL != CMODEL_SMALL)
@@ -7505,6 +7139,11 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
        }
       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
@@ -7512,8 +7151,8 @@ 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]))))
-              && GET_CODE (operands[1]) != HIGH
-              && ! legitimate_constant_pool_address_p (operands[1], false)
+              && ! legitimate_constant_pool_address_p (operands[1], mode,
+                                                       false)
               && ! toc_relative_expr_p (operands[1])
               && (TARGET_CMODEL == CMODEL_SMALL
                   || can_create_pseudo_p ()
@@ -7617,7 +7256,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 
 /* Nonzero if we can use an AltiVec register to pass this arg.  */
 #define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)             \
-  ((ALTIVEC_VECTOR_MODE (MODE) || VSX_VECTOR_MODE (MODE))      \
+  (ALTIVEC_OR_VSX_VECTOR_MODE (MODE)                           \
    && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG                     \
    && TARGET_ALTIVEC_ABI                                       \
    && (NAMED))
@@ -7705,9 +7344,37 @@ rs6000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
   return false;
 }
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+/* Return TRUE if a call to function FNDECL may be one that
+   potentially affects the function calling ABI of the object file.  */
+
+static bool
+call_ABI_of_interest (tree fndecl)
+{
+  if (cgraph_state == CGRAPH_STATE_EXPANSION)
+    {
+      struct cgraph_node *c_node;
+
+      /* Libcalls are always interesting.  */
+      if (fndecl == NULL_TREE)
+       return true;
+
+      /* Any call to an external function is interesting.  */
+      if (DECL_EXTERNAL (fndecl))
+       return true;
+
+      /* Interesting functions that we are emitting in this object file.  */
+      c_node = cgraph_get_node (fndecl);
+      c_node = cgraph_function_or_thunk_node (c_node, NULL);
+      return !cgraph_only_called_directly_p (c_node);
+    }
+  return false;
+}
+#endif
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
-   For a library call, FNTYPE is 0.
+   For a library call, FNTYPE is 0 and RETURN_MODE the return value mode.
 
    For incoming args we set the number of arguments in the prototype large
    so we never return a PARALLEL.  */
@@ -7715,7 +7382,9 @@ rs6000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 void
 init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
                      rtx libname ATTRIBUTE_UNUSED, int incoming,
-                     int libcall, int n_named_args)
+                     int libcall, int n_named_args,
+                     tree fndecl ATTRIBUTE_UNUSED,
+                     enum machine_mode return_mode ATTRIBUTE_UNUSED)
 {
   static CUMULATIVE_ARGS zero_cumulative;
 
@@ -7723,7 +7392,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
   cum->words = 0;
   cum->fregno = FP_ARG_MIN_REG;
   cum->vregno = ALTIVEC_ARG_MIN_REG;
-  cum->prototype = (fntype && TYPE_ARG_TYPES (fntype));
+  cum->prototype = (fntype && prototype_p (fntype));
   cum->call_cookie = ((DEFAULT_ABI == ABI_V4 && libcall)
                      ? CALL_LIBCALL : CALL_NORMAL);
   cum->sysv_gregno = GP_ARG_MIN_REG;
@@ -7757,6 +7426,44 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
               cum->prototype, cum->nargs_prototype);
     }
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+  if (DEFAULT_ABI == ABI_V4)
+    {
+      cum->escapes = call_ABI_of_interest (fndecl);
+      if (cum->escapes)
+       {
+         tree return_type;
+
+         if (fntype)
+           {
+             return_type = TREE_TYPE (fntype);
+             return_mode = TYPE_MODE (return_type);
+           }
+         else
+           return_type = lang_hooks.types.type_for_mode (return_mode, 0);
+
+         if (return_type != NULL)
+           {
+             if (TREE_CODE (return_type) == RECORD_TYPE
+                 && TYPE_TRANSPARENT_AGGR (return_type))
+               {
+                 return_type = TREE_TYPE (first_field (return_type));
+                 return_mode = TYPE_MODE (return_type);
+               }
+             if (AGGREGATE_TYPE_P (return_type)
+                 && ((unsigned HOST_WIDE_INT) int_size_in_bytes (return_type)
+                     <= 8))
+               rs6000_returns_struct = true;
+           }
+         if (SCALAR_FLOAT_MODE_P (return_mode))
+           rs6000_passes_float = true;
+         else if (ALTIVEC_OR_VSX_VECTOR_MODE (return_mode)
+                  || SPE_VECTOR_MODE (return_mode))
+           rs6000_passes_vector = true;
+       }
+    }
+#endif
+
   if (fntype
       && !TARGET_ALTIVEC
       && TARGET_ALTIVEC_ABI
@@ -7848,7 +7555,7 @@ function_arg_padding (enum machine_mode mode, const_tree type)
    existing library interfaces.
 
    Doubleword align SPE vectors.
-   Quadword align Altivec vectors.
+   Quadword align Altivec/VSX vectors.
    Quadword align large synthetic vector types.   */
 
 static unsigned int
@@ -7865,7 +7572,7 @@ rs6000_function_arg_boundary (enum machine_mode mode, const_tree type)
               && int_size_in_bytes (type) >= 8
               && int_size_in_bytes (type) < 16))
     return 64;
-  else if ((ALTIVEC_VECTOR_MODE (mode) || VSX_VECTOR_MODE (mode))
+  else if (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
           || (type && TREE_CODE (type) == VECTOR_TYPE
               && int_size_in_bytes (type) >= 16))
     return 128;
@@ -7999,8 +7706,9 @@ rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
          rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
        else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
          {
+           unsigned n_fpregs = (GET_MODE_SIZE (mode) + 7) >> 3;
            rs6000_darwin64_record_arg_advance_flush (cum, bitpos, 0);
-           cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+           cum->fregno += n_fpregs;
            /* Single-precision floats present a special problem for
               us, because they are smaller than an 8-byte GPR, and so
               the structure-packing rules combined with the standard
@@ -8035,7 +7743,7 @@ rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
                  }
              }
            else
-             cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
+             cum->words += n_fpregs;
          }
        else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
          {
@@ -8074,14 +7782,27 @@ static void
 rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                               const_tree type, bool named, int depth)
 {
-
   /* Only tick off an argument if we're not recursing.  */
   if (depth == 0)
     cum->nargs_prototype--;
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+  if (DEFAULT_ABI == ABI_V4
+      && cum->escapes)
+    {
+      if (SCALAR_FLOAT_MODE_P (mode))
+       rs6000_passes_float = true;
+      else if (named && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
+       rs6000_passes_vector = true;
+      else if (SPE_VECTOR_MODE (mode)
+              && !cum->stdarg
+              && cum->sysv_gregno <= GP_ARG_MAX_REG)
+       rs6000_passes_vector = true;
+    }
+#endif
+
   if (TARGET_ALTIVEC_ABI
-      && (ALTIVEC_VECTOR_MODE (mode)
-         || VSX_VECTOR_MODE (mode)
+      && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
          || (type && TREE_CODE (type) == VECTOR_TYPE
              && int_size_in_bytes (type) == 16)))
     {
@@ -8266,10 +7987,11 @@ rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 }
 
 static void
-rs6000_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_function_arg_advance (cumulative_args_t cum, enum machine_mode mode,
                             const_tree type, bool named)
 {
-  rs6000_function_arg_advance_1 (cum, mode, type, named, 0);
+  rs6000_function_arg_advance_1 (get_cumulative_args (cum), mode, type, named,
+                                0);
 }
 
 static rtx
@@ -8461,6 +8183,7 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, const_tree type,
          rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
        else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
          {
+           unsigned n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
 #if 0
            switch (mode)
              {
@@ -8471,6 +8194,14 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, const_tree type,
              }
 #endif
            rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
+           if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
+             {
+               gcc_assert (cum->fregno == FP_ARG_MAX_REG
+                           && (mode == TFmode || mode == TDmode));
+               /* Long double or _Decimal128 split over regs and memory.  */
+               mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode : DFmode;
+               cum->use_stack=1;
+             }
            rvec[(*k)++]
              = gen_rtx_EXPR_LIST (VOIDmode,
                                   gen_rtx_REG (mode, cum->fregno++),
@@ -8528,7 +8259,7 @@ rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, const_tree type,
      for the chunks of memory that go in int regs.  Note we start at
      element 1; 0 is reserved for an indication of using memory, and
      may or may not be filled in below. */
-  rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k);
+  rs6000_darwin64_record_arg_recurse (cum, type, /* startbit pos= */ 0, rvec, &k);
   rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k);
 
   /* If any part of the struct went on the stack put all of it there.
@@ -8624,9 +8355,10 @@ rs6000_mixed_function_arg (enum machine_mode mode, const_tree type,
    itself.  */
 
 static rtx
-rs6000_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
                     const_tree type, bool named)
 {
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   enum rs6000_abi abi = DEFAULT_ABI;
 
   /* Return a marker to indicate whether CR1 needs to set or clear the
@@ -8651,12 +8383,12 @@ rs6000_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                               : CALL_V4_CLEAR_FP_ARGS));
        }
 
-      return GEN_INT (cum->call_cookie);
+      return GEN_INT (cum->call_cookie & ~CALL_LIBCALL);
     }
 
   if (TARGET_MACHO && rs6000_darwin64_struct_check_p (mode, type))
     {
-      rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
+      rtx rslt = rs6000_darwin64_record_arg (cum, type, named, /*retval= */false);
       if (rslt != NULL_RTX)
        return rslt;
       /* Else fall through to usual handling.  */
@@ -8690,8 +8422,7 @@ rs6000_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     else
       return gen_rtx_REG (mode, cum->vregno);
   else if (TARGET_ALTIVEC_ABI
-          && (ALTIVEC_VECTOR_MODE (mode)
-              || VSX_VECTOR_MODE (mode)
+          && (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
               || (type && TREE_CODE (type) == VECTOR_TYPE
                   && int_size_in_bytes (type) == 16)))
     {
@@ -8897,9 +8628,10 @@ rs6000_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    returns the number of bytes used by the first element of the PARALLEL.  */
 
 static int
-rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+rs6000_arg_partial_bytes (cumulative_args_t cum_v, enum machine_mode mode,
                          tree type, bool named)
 {
+  CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
   int ret = 0;
   int align_words;
 
@@ -8960,7 +8692,7 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    reference.  */
 
 static bool
-rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+rs6000_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
                          enum machine_mode mode, const_tree type,
                          bool named ATTRIBUTE_UNUSED)
 {
@@ -9060,7 +8792,7 @@ rs6000_move_block_from_reg (int regno, rtx x, int nregs)
    stack and set PRETEND_SIZE to the length of the registers pushed.  */
 
 static void
-setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+setup_incoming_varargs (cumulative_args_t cum, enum machine_mode mode,
                        tree type, int *pretend_size ATTRIBUTE_UNUSED,
                        int no_rtl)
 {
@@ -9071,7 +8803,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   alias_set_type set;
 
   /* Skip the last named argument.  */
-  next_cum = *cum;
+  next_cum = *get_cumulative_args (cum);
   rs6000_function_arg_advance_1 (&next_cum, mode, type, true, 0);
 
   if (DEFAULT_ABI == ABI_V4)
@@ -9334,13 +9066,17 @@ rs6000_va_start (tree valist, rtx nextarg)
                  build_int_cst (NULL_TREE, n_fpr));
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+      if (call_ABI_of_interest (cfun->decl))
+       rs6000_passes_float = true;
+#endif
     }
 
   /* Find the overflow area.  */
   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
   if (words != 0)
-    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), t,
-               size_int (words * UNITS_PER_WORD));
+    t = fold_build_pointer_plus_hwi (t, words * UNITS_PER_WORD);
   t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -9356,8 +9092,7 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the register save area.  */
   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
   if (cfun->machine->varargs_save_offset)
-    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (sav), t,
-               size_int (cfun->machine->varargs_save_offset));
+    t = fold_build_pointer_plus_hwi (t, cfun->machine->varargs_save_offset);
   t = build2 (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -9410,9 +9145,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
          /* This updates arg ptr by the amount that would be necessary
             to align the zero-sized (but not zero-alignment) item.  */
          t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp,
-                 fold_build2 (POINTER_PLUS_EXPR,
-                              TREE_TYPE (valist),
-                              valist_tmp, size_int (boundary - 1)));
+                     fold_build_pointer_plus_hwi (valist_tmp, boundary - 1));
          gimplify_and_add (t, pre_p);
 
          t = fold_convert (sizetype, valist_tmp);
@@ -9547,20 +9280,20 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
 
       t = sav;
       if (sav_ofs)
-       t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
+       t = fold_build_pointer_plus_hwi (sav, sav_ofs);
 
       u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), unshare_expr (reg),
                  build_int_cst (TREE_TYPE (reg), n_reg));
       u = fold_convert (sizetype, u);
       u = build2 (MULT_EXPR, sizetype, u, size_int (sav_scale));
-      t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, u);
+      t = fold_build_pointer_plus (t, u);
 
       /* _Decimal32 varargs are located in the second word of the 64-bit
         FP register for 32-bit binaries.  */
       if (!TARGET_POWERPC64
          && TARGET_HARD_FLOAT && TARGET_FPRS
          && TYPE_MODE (type) == SDmode)
-       t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+       t = fold_build_pointer_plus_hwi (t, size);
 
       gimplify_assign (addr, t, pre_p);
 
@@ -9583,17 +9316,15 @@ rs6000_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   t = ovf;
   if (align != 1)
     {
-      t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
-      t = fold_convert (sizetype, t);
+      t = fold_build_pointer_plus_hwi (t, align - 1);
       t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
-                 size_int (-align));
-      t = fold_convert (TREE_TYPE (ovf), t);
+                 build_int_cst (TREE_TYPE (t), -align));
     }
   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
 
   gimplify_assign (unshare_expr (addr), t, pre_p);
 
-  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+  t = fold_build_pointer_plus_hwi (t, size);
   gimplify_assign (unshare_expr (ovf), t, pre_p);
 
   if (lab_over)
@@ -9612,7 +9343,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);
@@ -10957,6 +10688,7 @@ altivec_expand_stv_builtin (enum insn_code icode, tree exp)
   rtx op2 = expand_normal (arg2);
   rtx pat, addr;
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode smode = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = Pmode;
   enum machine_mode mode2 = Pmode;
 
@@ -10966,8 +10698,8 @@ altivec_expand_stv_builtin (enum insn_code icode, tree exp)
       || arg2 == error_mark_node)
     return const0_rtx;
 
-  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
-    op0 = copy_to_mode_reg (tmode, op0);
+  if (! (*insn_data[icode].operand[1].predicate) (op0, smode))
+    op0 = copy_to_mode_reg (smode, op0);
 
   op2 = copy_to_mode_reg (mode2, op2);
 
@@ -11101,16 +10833,22 @@ altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
-      icode = CODE_FOR_vector_load_v16qi;
+      icode = CODE_FOR_vector_altivec_load_v16qi;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
-      icode = CODE_FOR_vector_load_v8hi;
+      icode = CODE_FOR_vector_altivec_load_v8hi;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
-      icode = CODE_FOR_vector_load_v4si;
+      icode = CODE_FOR_vector_altivec_load_v4si;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
-      icode = CODE_FOR_vector_load_v4sf;
+      icode = CODE_FOR_vector_altivec_load_v4sf;
+      break;
+    case ALTIVEC_BUILTIN_LD_INTERNAL_2df:
+      icode = CODE_FOR_vector_altivec_load_v2df;
+      break;
+    case ALTIVEC_BUILTIN_LD_INTERNAL_2di:
+      icode = CODE_FOR_vector_altivec_load_v2di;
       break;
     default:
       *expandedp = false;
@@ -11154,16 +10892,22 @@ altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
-      icode = CODE_FOR_vector_store_v16qi;
+      icode = CODE_FOR_vector_altivec_store_v16qi;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
-      icode = CODE_FOR_vector_store_v8hi;
+      icode = CODE_FOR_vector_altivec_store_v8hi;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
-      icode = CODE_FOR_vector_store_v4si;
+      icode = CODE_FOR_vector_altivec_store_v4si;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
-      icode = CODE_FOR_vector_store_v4sf;
+      icode = CODE_FOR_vector_altivec_store_v4sf;
+      break;
+    case ALTIVEC_BUILTIN_ST_INTERNAL_2df:
+      icode = CODE_FOR_vector_altivec_store_v2df;
+      break;
+    case ALTIVEC_BUILTIN_ST_INTERNAL_2di:
+      icode = CODE_FOR_vector_altivec_store_v2di;
       break;
     default:
       *expandedp = false;
@@ -11395,7 +11139,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_STVX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, exp);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx_v4si, exp);
     case ALTIVEC_BUILTIN_STVEBX:
       return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, exp);
     case ALTIVEC_BUILTIN_STVEHX:
@@ -11414,6 +11158,19 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     case ALTIVEC_BUILTIN_STVRXL:
       return altivec_expand_stv_builtin (CODE_FOR_altivec_stvrxl, exp);
 
+    case VSX_BUILTIN_STXVD2X_V2DF:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2df, exp);
+    case VSX_BUILTIN_STXVD2X_V2DI:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v2di, exp);
+    case VSX_BUILTIN_STXVW4X_V4SF:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4sf, exp);
+    case VSX_BUILTIN_STXVW4X_V4SI:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v4si, exp);
+    case VSX_BUILTIN_STXVW4X_V8HI:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v8hi, exp);
+    case VSX_BUILTIN_STXVW4X_V16QI:
+      return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v16qi, exp);
+
     case ALTIVEC_BUILTIN_MFVSCR:
       icode = CODE_FOR_altivec_mfvscr;
       tmode = insn_data[icode].operand[0].mode;
@@ -11538,7 +11295,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
                                        exp, target, false);
     case ALTIVEC_BUILTIN_LVX:
-      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx_v4si,
                                        exp, target, false);
     case ALTIVEC_BUILTIN_LVLX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvlx,
@@ -11552,6 +11309,25 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     case ALTIVEC_BUILTIN_LVRXL:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvrxl,
                                        exp, target, true);
+    case VSX_BUILTIN_LXVD2X_V2DF:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2df,
+                                       exp, target, false);
+    case VSX_BUILTIN_LXVD2X_V2DI:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v2di,
+                                       exp, target, false);
+    case VSX_BUILTIN_LXVW4X_V4SF:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4sf,
+                                       exp, target, false);
+    case VSX_BUILTIN_LXVW4X_V4SI:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v4si,
+                                       exp, target, false);
+    case VSX_BUILTIN_LXVW4X_V8HI:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v8hi,
+                                       exp, target, false);
+    case VSX_BUILTIN_LXVW4X_V16QI:
+      return altivec_expand_lv_builtin (CODE_FOR_vsx_load_v16qi,
+                                       exp, target, false);
+      break;
     default:
       break;
       /* Fall through.  */
@@ -12169,6 +11945,8 @@ rs6000_init_builtins (void)
 
   long_integer_type_internal_node = long_integer_type_node;
   long_unsigned_type_internal_node = long_unsigned_type_node;
+  long_long_integer_type_internal_node = long_long_integer_type_node;
+  long_long_unsigned_type_internal_node = long_long_unsigned_type_node;
   intQI_type_internal_node = intQI_type_node;
   uintQI_type_internal_node = unsigned_intQI_type_node;
   intHI_type_internal_node = intHI_type_node;
@@ -12178,7 +11956,7 @@ rs6000_init_builtins (void)
   intDI_type_internal_node = intDI_type_node;
   uintDI_type_internal_node = unsigned_intDI_type_node;
   float_type_internal_node = float_type_node;
-  double_type_internal_node = float_type_node;
+  double_type_internal_node = double_type_node;
   void_type_internal_node = void_type_node;
 
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
@@ -12378,8 +12156,8 @@ rs6000_init_builtins (void)
 
 #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
@@ -12429,107 +12207,97 @@ enable_mask_for_builtins (struct builtin_description *desc, int size,
 static void
 spe_init_builtins (void)
 {
-  tree endlink = void_list_node;
   tree puint_type_node = build_pointer_type (unsigned_type_node);
   tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
   struct builtin_description *d;
   size_t i;
 
   tree v2si_ftype_4_v2si
-    = build_function_type
-    (opaque_V2SI_type_node,
-     tree_cons (NULL_TREE, opaque_V2SI_type_node,
-               tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                                endlink)))));
+    = build_function_type_list (opaque_V2SI_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_V2SI_type_node,
+                                NULL_TREE);
 
   tree v2sf_ftype_4_v2sf
-    = build_function_type
-    (opaque_V2SF_type_node,
-     tree_cons (NULL_TREE, opaque_V2SF_type_node,
-               tree_cons (NULL_TREE, opaque_V2SF_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SF_type_node,
-                                     tree_cons (NULL_TREE, opaque_V2SF_type_node,
-                                                endlink)))));
+    = build_function_type_list (opaque_V2SF_type_node,
+                                opaque_V2SF_type_node,
+                                opaque_V2SF_type_node,
+                                opaque_V2SF_type_node,
+                                opaque_V2SF_type_node,
+                                NULL_TREE);
 
   tree int_ftype_int_v2si_v2si
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     endlink))));
+    = build_function_type_list (integer_type_node,
+                                integer_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_V2SI_type_node,
+                                NULL_TREE);
 
   tree int_ftype_int_v2sf_v2sf
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, opaque_V2SF_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SF_type_node,
-                                     endlink))));
+    = build_function_type_list (integer_type_node,
+                                integer_type_node,
+                                opaque_V2SF_type_node,
+                                opaque_V2SF_type_node,
+                                NULL_TREE);
 
   tree void_ftype_v2si_puint_int
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     tree_cons (NULL_TREE, puint_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           integer_type_node,
-                                                           endlink))));
+    = build_function_type_list (void_type_node,
+                                opaque_V2SI_type_node,
+                                puint_type_node,
+                                integer_type_node,
+                                NULL_TREE);
 
   tree void_ftype_v2si_puint_char
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     tree_cons (NULL_TREE, puint_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
+    = build_function_type_list (void_type_node,
+                                opaque_V2SI_type_node,
+                                puint_type_node,
+                                char_type_node,
+                                NULL_TREE);
 
   tree void_ftype_v2si_pv2si_int
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           integer_type_node,
-                                                           endlink))));
+    = build_function_type_list (void_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_p_V2SI_type_node,
+                                integer_type_node,
+                                NULL_TREE);
 
   tree void_ftype_v2si_pv2si_char
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
-                                     tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
-                                                tree_cons (NULL_TREE,
-                                                           char_type_node,
-                                                           endlink))));
+    = build_function_type_list (void_type_node,
+                                opaque_V2SI_type_node,
+                                opaque_p_V2SI_type_node,
+                                char_type_node,
+                                NULL_TREE);
 
   tree void_ftype_int
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, integer_type_node, endlink));
+    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
 
   tree int_ftype_void
-    = build_function_type (integer_type_node, endlink);
+    = build_function_type_list (integer_type_node, NULL_TREE);
 
   tree v2si_ftype_pv2si_int
-    = build_function_type (opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                endlink)));
+    = build_function_type_list (opaque_V2SI_type_node,
+                                opaque_p_V2SI_type_node,
+                                integer_type_node,
+                                NULL_TREE);
 
   tree v2si_ftype_puint_int
-    = build_function_type (opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, puint_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                endlink)));
+    = build_function_type_list (opaque_V2SI_type_node,
+                                puint_type_node,
+                                integer_type_node,
+                                NULL_TREE);
 
   tree v2si_ftype_pushort_int
-    = build_function_type (opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, pushort_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                endlink)));
+    = build_function_type_list (opaque_V2SI_type_node,
+                                pushort_type_node,
+                                integer_type_node,
+                                NULL_TREE);
 
   tree v2si_ftype_signed_char
-    = build_function_type (opaque_V2SI_type_node,
-                          tree_cons (NULL_TREE, signed_char_type_node,
-                                     endlink));
+    = build_function_type_list (opaque_V2SI_type_node,
+                                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
@@ -12651,15 +12419,13 @@ paired_init_builtins (void)
 {
   const struct builtin_description *d;
   size_t i;
-  tree endlink = void_list_node;
 
    tree int_ftype_int_v2sf_v2sf
-    = build_function_type
-    (integer_type_node,
-     tree_cons (NULL_TREE, integer_type_node,
-                tree_cons (NULL_TREE, V2SF_type_node,
-                           tree_cons (NULL_TREE, V2SF_type_node,
-                                      endlink))));
+    = build_function_type_list (integer_type_node,
+                                integer_type_node,
+                                V2SF_type_node,
+                                V2SF_type_node,
+                                NULL_TREE);
   tree pcfloat_type_node =
     build_pointer_type (build_qualified_type
                        (float_type_node, TYPE_QUAL_CONST));
@@ -12710,26 +12476,17 @@ altivec_init_builtins (void)
   size_t i;
   tree ftype;
 
-  tree pfloat_type_node = build_pointer_type (float_type_node);
-  tree pint_type_node = build_pointer_type (integer_type_node);
-  tree pshort_type_node = build_pointer_type (short_integer_type_node);
-  tree pchar_type_node = build_pointer_type (char_type_node);
-
   tree pvoid_type_node = build_pointer_type (void_type_node);
 
-  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
-  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
-  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
-  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
-
-  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
+  tree pcvoid_type_node
+    = build_pointer_type (build_qualified_type (void_type_node,
+                                               TYPE_QUAL_CONST));
 
   tree int_ftype_opaque
     = build_function_type_list (integer_type_node,
                                opaque_V4SI_type_node, NULL_TREE);
   tree opaque_ftype_opaque
-    = build_function_type (integer_type_node,
-                               NULL_TREE);
+    = build_function_type_list (integer_type_node, NULL_TREE);
   tree opaque_ftype_opaque_int
     = build_function_type_list (opaque_V4SI_type_node,
                                opaque_V4SI_type_node, integer_type_node, NULL_TREE);
@@ -12745,47 +12502,43 @@ altivec_init_builtins (void)
     = build_function_type_list (integer_type_node,
                                integer_type_node, V4SI_type_node,
                                V4SI_type_node, NULL_TREE);
-  tree v4sf_ftype_pcfloat
-    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
-  tree void_ftype_pfloat_v4sf
-    = build_function_type_list (void_type_node,
-                               pfloat_type_node, V4SF_type_node, NULL_TREE);
-  tree v4si_ftype_pcint
-    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
-  tree void_ftype_pint_v4si
-    = build_function_type_list (void_type_node,
-                               pint_type_node, V4SI_type_node, NULL_TREE);
-  tree v8hi_ftype_pcshort
-    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
-  tree void_ftype_pshort_v8hi
-    = build_function_type_list (void_type_node,
-                               pshort_type_node, V8HI_type_node, NULL_TREE);
-  tree v16qi_ftype_pcchar
-    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
-  tree void_ftype_pchar_v16qi
-    = build_function_type_list (void_type_node,
-                               pchar_type_node, V16QI_type_node, NULL_TREE);
   tree void_ftype_v4si
     = build_function_type_list (void_type_node, V4SI_type_node, NULL_TREE);
   tree v8hi_ftype_void
-    = build_function_type (V8HI_type_node, void_list_node);
+    = build_function_type_list (V8HI_type_node, NULL_TREE);
   tree void_ftype_void
-    = build_function_type (void_type_node, void_list_node);
+    = build_function_type_list (void_type_node, NULL_TREE);
   tree void_ftype_int
     = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
 
   tree opaque_ftype_long_pcvoid
     = build_function_type_list (opaque_V4SI_type_node,
-                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
   tree v16qi_ftype_long_pcvoid
     = build_function_type_list (V16QI_type_node,
-                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
   tree v8hi_ftype_long_pcvoid
     = build_function_type_list (V8HI_type_node,
-                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
   tree v4si_ftype_long_pcvoid
     = build_function_type_list (V4SI_type_node,
-                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
+  tree v4sf_ftype_long_pcvoid
+    = build_function_type_list (V4SF_type_node,
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
+  tree v2df_ftype_long_pcvoid
+    = build_function_type_list (V2DF_type_node,
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
+  tree v2di_ftype_long_pcvoid
+    = build_function_type_list (V2DI_type_node,
+                               long_integer_type_node, pcvoid_type_node,
+                               NULL_TREE);
 
   tree void_ftype_opaque_long_pvoid
     = build_function_type_list (void_type_node,
@@ -12803,6 +12556,18 @@ altivec_init_builtins (void)
     = build_function_type_list (void_type_node,
                                V8HI_type_node, long_integer_type_node,
                                pvoid_type_node, NULL_TREE);
+  tree void_ftype_v4sf_long_pvoid
+    = build_function_type_list (void_type_node,
+                               V4SF_type_node, long_integer_type_node,
+                               pvoid_type_node, NULL_TREE);
+  tree void_ftype_v2df_long_pvoid
+    = build_function_type_list (void_type_node,
+                               V2DF_type_node, long_integer_type_node,
+                               pvoid_type_node, NULL_TREE);
+  tree void_ftype_v2di_long_pvoid
+    = build_function_type_list (void_type_node,
+                               V2DI_type_node, long_integer_type_node,
+                               pvoid_type_node, NULL_TREE);
   tree int_ftype_int_v8hi_v8hi
     = build_function_type_list (integer_type_node,
                                integer_type_node, V8HI_type_node,
@@ -12834,22 +12599,6 @@ altivec_init_builtins (void)
                                pcvoid_type_node, integer_type_node,
                                integer_type_node, NULL_TREE);
 
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
-              ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
-              ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
-              ALTIVEC_BUILTIN_LD_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
-              ALTIVEC_BUILTIN_ST_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
-              ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
-              ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
-              ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
-              ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
@@ -12881,6 +12630,35 @@ altivec_init_builtins (void)
   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,
+              VSX_BUILTIN_LXVD2X_V2DF);
+  def_builtin (MASK_VSX, "__builtin_vsx_lxvd2x_v2di", v2di_ftype_long_pcvoid,
+              VSX_BUILTIN_LXVD2X_V2DI);
+  def_builtin (MASK_VSX, "__builtin_vsx_lxvw4x_v4sf", v4sf_ftype_long_pcvoid,
+              VSX_BUILTIN_LXVW4X_V4SF);
+  def_builtin (MASK_VSX, "__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,
+              VSX_BUILTIN_VEC_LD);
+  def_builtin (MASK_VSX, "__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);
@@ -13192,7 +12970,6 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
   int i;
   tree ret_type = NULL_TREE;
   tree arg_type[3] = { NULL_TREE, NULL_TREE, NULL_TREE };
-  tree args;
 
   /* Create builtin_hash_table.  */
   if (builtin_hash_table == NULL)
@@ -13295,6 +13072,9 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
     fatal_error ("internal error: builtin function %s had an unexpected "
                 "return type %s", name, GET_MODE_NAME (h.mode[0]));
 
+  for (i = 0; i < (int) ARRAY_SIZE (arg_type); i++)
+    arg_type[i] = NULL_TREE;
+
   for (i = 0; i < num_args; i++)
     {
       int m = (int) h.mode[i+1];
@@ -13316,12 +13096,9 @@ builtin_function_type (enum machine_mode mode_ret, enum machine_mode mode_arg0,
       h2 = ggc_alloc_builtin_hash_struct ();
       *h2 = h;
       *found = (void *)h2;
-      args = void_list_node;
 
-      for (i = num_args - 1; i >= 0; i--)
-       args = tree_cons (NULL_TREE, arg_type[i], args);
-
-      h2->type = build_function_type (ret_type, args);
+      h2->type = build_function_type_list (ret_type, arg_type[0], arg_type[1],
+                                          arg_type[2], NULL_TREE);
     }
 
   return ((struct builtin_hash_struct *)(*found))->type;
@@ -13847,14 +13624,14 @@ expand_block_move (rtx operands[])
              rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
              src = replace_equiv_address (src, src_reg);
            }
-         set_mem_size (src, GEN_INT (move_bytes));
+         set_mem_size (src, move_bytes);
 
          if (!REG_P (XEXP (dest, 0)))
            {
              rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
              dest = replace_equiv_address (dest, dest_reg);
            }
-         set_mem_size (dest, GEN_INT (move_bytes));
+         set_mem_size (dest, move_bytes);
 
          emit_insn ((*gen_func.movmemsi) (dest, src,
                                           GEN_INT (move_bytes & 31),
@@ -14363,7 +14140,10 @@ rs6000_reload_register_type (enum reg_class rclass)
    needed for the immediate register.
 
    For VSX and Altivec, we may need a register to convert sp+offset into
-   reg+sp.  */
+   reg+sp.
+
+   For misaligned 64-bit gpr loads and stores we need a register to
+   convert an offset address to indirect.  */
 
 static reg_class_t
 rs6000_secondary_reload (bool in_p,
@@ -14466,6 +14246,34 @@ rs6000_secondary_reload (bool in_p,
       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 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);
+
+      if (GET_CODE (addr) == PLUS
+         && GET_CODE (XEXP (addr, 1)) == CONST_INT
+         && (INTVAL (XEXP (addr, 1)) & 3) != 0)
+       {
+         if (in_p)
+           sri->icode = CODE_FOR_reload_di_load;
+         else
+           sri->icode = CODE_FOR_reload_di_store;
+         sri->extra_cost = 2;
+         ret = NO_REGS;
+       }
+      else
+       default_p = true;
+    }
   else
     default_p = true;
 
@@ -14754,24 +14562,54 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
   return;
 }
 
-/* Target hook to return the cover classes for Integrated Register Allocator.
-   Cover classes is a set of non-intersected register classes covering all hard
-   registers used for register allocation purpose.  Any move between two
-   registers of a cover class should be cheaper than load or store of the
-   registers.  The value is array of register classes with LIM_REG_CLASSES used
-   as the end marker.
+/* Convert reloads involving 64-bit gprs and misaligned offset
+   addressing to use indirect addressing.  */
 
-   We need two IRA_COVER_CLASSES, one for pre-VSX, and the other for VSX to
-   account for the Altivec and Floating registers being subsets of the VSX
-   register set under VSX, but distinct register sets on pre-VSX machines.  */
-
-static const reg_class_t *
-rs6000_ira_cover_classes (void)
+void
+rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
 {
-  static const reg_class_t cover_pre_vsx[] = IRA_COVER_CLASSES_PRE_VSX;
-  static const reg_class_t cover_vsx[]     = IRA_COVER_CLASSES_VSX;
+  int regno = true_regnum (reg);
+  enum reg_class rclass;
+  rtx addr;
+  rtx scratch_or_premodify = scratch;
+
+  if (TARGET_DEBUG_ADDR)
+    {
+      fprintf (stderr, "\nrs6000_secondary_reload_ppc64, type = %s\n",
+              store_p ? "store" : "load");
+      fprintf (stderr, "reg:\n");
+      debug_rtx (reg);
+      fprintf (stderr, "mem:\n");
+      debug_rtx (mem);
+      fprintf (stderr, "scratch:\n");
+      debug_rtx (scratch);
+    }
+
+  gcc_assert (regno >= 0 && regno < FIRST_PSEUDO_REGISTER);
+  gcc_assert (GET_CODE (mem) == MEM);
+  rclass = REGNO_REG_CLASS (regno);
+  gcc_assert (rclass == GENERAL_REGS || rclass == BASE_REGS);
+  addr = XEXP (mem, 0);
+
+  if (GET_CODE (addr) == PRE_MODIFY)
+    {
+      scratch_or_premodify = XEXP (addr, 0);
+      gcc_assert (REG_P (scratch_or_premodify));
+      addr = XEXP (addr, 1);
+    }
+  gcc_assert (GET_CODE (addr) == PLUS || GET_CODE (addr) == LO_SUM);
+
+  rs6000_emit_move (scratch_or_premodify, addr, Pmode);
+
+  mem = replace_equiv_address_nv (mem, scratch_or_premodify);
+
+  /* Now create the move.  */
+  if (store_p)
+    emit_insn (gen_rtx_SET (VOIDmode, mem, reg));
+  else
+    emit_insn (gen_rtx_SET (VOIDmode, reg, mem));
 
-  return (TARGET_VSX) ? cover_vsx : cover_pre_vsx;
+  return;
 }
 
 /* Allocate a 64-bit stack slot to be used for copying SDmode
@@ -16020,7 +15858,18 @@ print_operand (FILE *file, rtx x, int code)
            output_address (XEXP (x, 0));
        }
       else
-       output_addr_const (file, x);
+       {
+         if (toc_relative_expr_p (x))
+           /* 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))
+              without this hack would be output as "x@toc+4".  We
+              want "x+4@toc".  */
+           output_addr_const (file, tocrel_base);
+         else
+           output_addr_const (file, x);
+       }
       return;
 
     case '&':
@@ -16071,7 +15920,7 @@ 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, true))
+  else if (legitimate_constant_pool_address_p (x, QImode, true))
     {
       /* This hack along with a corresponding hack in
         rs6000_output_addr_const_extra arranges to output addends
@@ -16196,7 +16045,7 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
   return default_assemble_integer (x, size, aligned_p);
 }
 
-#ifdef HAVE_GAS_HIDDEN
+#if defined (HAVE_GAS_HIDDEN) && !defined (TARGET_MACHO)
 /* Emit an assembler directive to set symbol visibility for DECL to
    VISIBILITY_TYPE.  */
 
@@ -16978,7 +16827,7 @@ 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);
+  cond2 = gen_rtx_fmt_ee (NE, cc_mode, mask, CONST0_RTX (dest_mode));
   emit_insn (gen_rtx_SET (VOIDmode,
                          dest,
                          gen_rtx_IF_THEN_ELSE (dest_mode,
@@ -18039,7 +17888,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
@@ -18141,9 +17990,11 @@ rs6000_savres_strategy (rs6000_stack_t *info,
 
   /* 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.  */
+     static chain is rarely used anyway.  FPRs are saved w.r.t the stack
+     pointer on Darwin.  */
   if (using_static_chain_p)
-    strategy |= SAVE_INLINE_FPRS | SAVE_INLINE_GPRS;
+    strategy |= (DEFAULT_ABI == ABI_DARWIN ? 0 : SAVE_INLINE_FPRS)
+               | SAVE_INLINE_GPRS;
 
   /* If we are going to use store multiple, then don't even bother
      with the out-of-line routines, since the store-multiple
@@ -18191,6 +18042,9 @@ rs6000_savres_strategy (rs6000_stack_t *info,
   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;
 }
 
@@ -18294,9 +18148,6 @@ rs6000_savres_strategy (rs6000_stack_t *info,
 static rs6000_stack_t *
 rs6000_stack_info (void)
 {
-#ifdef ENABLE_CHECKING
-  static rs6000_stack_t info_save;
-#endif
   rs6000_stack_t *info_ptr = &stack_info;
   int reg_size = TARGET_32BIT ? 4 : 8;
   int ehrd_size;
@@ -18305,14 +18156,10 @@ rs6000_stack_info (void)
   HOST_WIDE_INT non_fixed_size;
   bool using_static_chain_p;
 
-#ifdef ENABLE_CHECKING
-  memcpy (&info_save, &stack_info, sizeof stack_info);
-#else
   if (reload_completed && info_ptr->reload_completed)
     return info_ptr;
-#endif
 
-  memset (&stack_info, 0, sizeof (stack_info));
+  memset (info_ptr, 0, sizeof (*info_ptr));
   info_ptr->reload_completed = reload_completed;
 
   if (TARGET_SPE)
@@ -18616,10 +18463,6 @@ rs6000_stack_info (void)
   if (! info_ptr->cr_save_p)
     info_ptr->cr_save_offset = 0;
 
-#ifdef ENABLE_CHECKING
-  gcc_assert (!(reload_completed && info_save.reload_completed)
-             || memcmp (&info_save, &stack_info, sizeof stack_info) == 0);
-#endif
   return info_ptr;
 }
 
@@ -18797,6 +18640,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");
 }
 
@@ -18825,39 +18670,68 @@ rs6000_return_addr (int count, rtx frame)
   return get_hard_reg_initial_val (Pmode, LR_REGNO);
 }
 
-/* Say whether a function is a candidate for sibcall handling or not.
-   We do not allow indirect calls to be optimized into sibling calls.
-   Also, we can't do it if there are any vector parameters; there's
-   nowhere to put the VRsave code so it works; note that functions with
-   vector parameters are required to have a prototype, so the argument
-   type info must be available here.  (The tail recursion case can work
-   with vector parameters, but there's no way to distinguish here.) */
+/* Say whether a function is a candidate for sibcall handling or not.  */
+
 static bool
-rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
+rs6000_function_ok_for_sibcall (tree decl, tree exp)
 {
-  tree type;
+  tree fntype;
+
   if (decl)
-    {
-      if (TARGET_ALTIVEC_VRSAVE)
-       {
-         for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
-              type; type = TREE_CHAIN (type))
-           {
-             if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
-               return false;
-           }
-       }
-      if (DEFAULT_ABI == ABI_DARWIN
-         || ((*targetm.binds_local_p) (decl)
-             && (DEFAULT_ABI != ABI_AIX || !DECL_EXTERNAL (decl))))
-       {
-         tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
+    fntype = TREE_TYPE (decl);
+  else
+    fntype = TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (exp)));
+
+  /* We can't do it if the called function has more vector parameters
+     than the current function; there's nowhere to put the VRsave code.  */
+  if (TARGET_ALTIVEC_ABI
+      && TARGET_ALTIVEC_VRSAVE
+      && !(decl && decl == current_function_decl))
+    {
+      function_args_iterator args_iter;
+      tree type;
+      int nvreg = 0;
+
+      /* Functions with vector parameters are required to have a
+        prototype, so the argument type info must be available
+        here.  */
+      FOREACH_FUNCTION_ARGS(fntype, type, args_iter)
+       if (TREE_CODE (type) == VECTOR_TYPE
+           && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+         nvreg++;
+
+      FOREACH_FUNCTION_ARGS(TREE_TYPE (current_function_decl), type, args_iter)
+       if (TREE_CODE (type) == VECTOR_TYPE
+           && ALTIVEC_OR_VSX_VECTOR_MODE (TYPE_MODE (type)))
+         nvreg--;
+
+      if (nvreg > 0)
+       return false;
+    }
+
+  /* Under the AIX ABI we can't allow calls to non-local functions,
+     because the callee may have a different TOC pointer to the
+     caller and there's no way to ensure we restore the TOC when we
+     return.  With the secure-plt SYSV ABI we can't make non-local
+     calls when -fpic/PIC because the plt call stubs use r30.  */
+  if (DEFAULT_ABI == ABI_DARWIN
+      || (DEFAULT_ABI == ABI_AIX
+         && decl
+         && !DECL_EXTERNAL (decl)
+         && (*targetm.binds_local_p) (decl))
+      || (DEFAULT_ABI == ABI_V4
+         && (!TARGET_SECURE_PLT
+             || !flag_pic
+             || (decl
+                 && (*targetm.binds_local_p) (decl)))))
+    {
+      tree attr_list = TYPE_ATTRIBUTES (fntype);
+
+      if (!lookup_attribute ("longcall", attr_list)
+         || lookup_attribute ("shortcall", attr_list))
+       return true;
+    }
 
-         if (!lookup_attribute ("longcall", attr_list)
-             || lookup_attribute ("shortcall", attr_list))
-           return true;
-       }
-    }
   return false;
 }
 
@@ -18999,6 +18873,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));
@@ -19137,7 +19013,9 @@ create_TOC_reference (rtx symbol, rtx largetoc_reg)
   tocreg = gen_rtx_REG (Pmode, TOC_REGISTER);
   if (TARGET_CMODEL != CMODEL_SMALL)
     {
-      rtx hi = gen_rtx_PLUS (Pmode, tocreg, gen_rtx_HIGH (Pmode, tocrel));
+      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);
@@ -19377,7 +19255,8 @@ output_probe_stack_range (rtx reg1, rtx reg2)
   output_asm_insn ("{cal %0,%1(%0)|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 ("{st|stw} %1,0(%0)", xops);
   fprintf (asm_out_file, "\tb ");
   assemble_name_raw (asm_out_file, loop_lab);
   fputc ('\n', asm_out_file);
@@ -19393,7 +19272,7 @@ output_probe_stack_range (rtx reg1, rtx reg2)
    deduce these equivalences by itself so it wasn't necessary to hold
    its hand so much.  */
 
-static void
+static rtx
 rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
                      rtx reg2, rtx rreg)
 {
@@ -19466,6 +19345,8 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
 
   RTX_FRAME_RELATED_P (insn) = 1;
   add_reg_note (insn, REG_FRAME_RELATED_EXPR, real);
+
+  return insn;
 }
 
 /* Returns an insn that has a vrsave set operation with the
@@ -19530,7 +19411,7 @@ generate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
 /* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
    Save REGNO into [FRAME_REG + OFFSET] in mode MODE.  */
 
-static void
+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)
 {
@@ -19541,7 +19422,7 @@ emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
 
   /* Some cases that need register indexed addressing.  */
   if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
-      || (TARGET_VSX && VSX_VECTOR_MODE (mode))
+      || (TARGET_VSX && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
       || (TARGET_E500_DOUBLE && mode == DFmode)
       || (TARGET_SPE_ABI
          && SPE_VECTOR_MODE (mode)
@@ -19568,7 +19449,7 @@ emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
 
   insn = emit_move_insn (mem, reg);
 
-  rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
+  return rs6000_frame_related (insn, frame_ptr, total_size, replacea, replaceb);
 }
 
 /* Emit an offset memory reference suitable for a frame store, while
@@ -19708,10 +19589,25 @@ rs6000_savres_routine_name (rs6000_stack_t *info, int regno,
          suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX;
        }
     }
-  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);
+   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 = savep ? "save" : "rest" ;
+      if (gpr)
+       sprintf (savres_routine_name, "*%sGPR%s%s%.0d ; %s r%d-r31",
+              prefix, (lr ? "x" : ""), (regno == 13 ? "" : "+"),
+              (regno-13) * 4, prefix, regno);
+      else
+       sprintf (savres_routine_name, "*%sFP%s%.0d ; %s f%d-f31",
+              prefix, (regno == 14 ? "" : "+"),  (regno-14) * 4, prefix, regno);
+    }
+  else
+    sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix);
 
   return savres_routine_name;
 }
@@ -19776,8 +19672,10 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
       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)));
+         rtx insn = emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx,
+                                              GEN_INT (sp_offset)));
+         if (!savres)
+           return insn;
        }
       else if (!savres)
        return emit_move_insn (sp_reg_rtx, frame_reg_rtx);
@@ -19801,19 +19699,21 @@ rs6000_emit_stack_reset (rs6000_stack_t *info,
 }
 
 /* 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,
+rs6000_emit_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)
 {
   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
@@ -19824,18 +19724,19 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
   p = rtvec_alloc ((lr ? 4 : 3) + n_regs);
 
   if (!savep && lr)
-    RTVEC_ELT (p, offset++) = gen_rtx_RETURN (VOIDmode);
+    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);
   RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym);
+  use_reg = DEFAULT_ABI == ABI_AIX ? (gpr && !lr ? 12 : 1)
+                                  : DEFAULT_ABI == ABI_DARWIN && !gpr ? 1
+                                                                      : 11;
   RTVEC_ELT (p, offset++)
     = gen_rtx_USE (VOIDmode,
-                  gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11
-                                      : gpr && !lr ? 12
-                                      : 1));
+                  gen_rtx_REG (Pmode, use_reg));
 
   for (i = 0; i < end_reg - start_reg; i++)
     {
@@ -19860,7 +19761,16 @@ rs6000_make_savres_rtx (rs6000_stack_t *info,
       RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg);
     }
 
-  return gen_rtx_PARALLEL (VOIDmode, p);
+  par = gen_rtx_PARALLEL (VOIDmode, p);
+
+  if (!savep && lr)
+    {
+      insn = emit_jump_insn (par);
+      JUMP_LABEL (insn) = ret_rtx;
+    }
+  else
+    insn = emit_insn (par);
+  return insn;
 }
 
 /* Determine whether the gp REG is really used.  */
@@ -19876,8 +19786,10 @@ rs6000_reg_live_or_pic_offset_p (int reg)
   return (((crtl->calls_eh_return || df_regs_ever_live_p (reg))
            && (!call_used_regs[reg]
                || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+                  && !TARGET_SINGLE_PIC_BASE
                    && TARGET_TOC && TARGET_MINIMAL_TOC)))
           || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+             && !TARGET_SINGLE_PIC_BASE
               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
 }
@@ -19904,7 +19816,7 @@ rs6000_emit_prologue (void)
                              && call_used_regs[STATIC_CHAIN_REGNUM]);
   HOST_WIDE_INT sp_offset = 0;
 
-  if (flag_stack_usage)
+  if (flag_stack_usage_info)
     current_function_static_stack_size = info->total_size;
 
   if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && info->total_size)
@@ -20157,16 +20069,13 @@ rs6000_emit_prologue (void)
     }
   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);
+      insn = rs6000_emit_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));
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
@@ -20256,13 +20165,10 @@ rs6000_emit_prologue (void)
        }
       else
        {
-         rtx par;
-
-         par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11),
-                                       0, reg_mode,
-                                       /*savep=*/true, /*gpr=*/true,
-                                       /*lr=*/false);
-         insn = emit_insn (par);
+         insn = rs6000_emit_savres_rtx (info, gen_rtx_REG (Pmode, 11),
+                                        0, reg_mode,
+                                        /*savep=*/true, /*gpr=*/true,
+                                        /*lr=*/false);
          rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                                NULL_RTX, NULL_RTX);
        }
@@ -20274,10 +20180,21 @@ rs6000_emit_prologue (void)
     }
   else if (!WORLD_SAVE_P (info) && !saving_GPRs_inline)
     {
-      rtx par;
-
+      if (DEFAULT_ABI == ABI_DARWIN)
+       {
+         rtx dest_reg = gen_rtx_REG (reg_mode, 11);
+         if (info->first_fp_reg_save == 64)
+           /* we only need a copy, no fprs were saved.  */
+           emit_move_insn (dest_reg, frame_reg_rtx);
+         else
+           {
+             rtx offset = GEN_INT (sp_offset
+                                   + (-8 * (64-info->first_fp_reg_save)));
+             emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
+           }
+       }
       /* Need to adjust r11 (r12) if we saved any FPRs.  */
-      if (info->first_fp_reg_save != 64)
+      else if (info->first_fp_reg_save != 64)
         {
          rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX
                                      ? 12 : 11);
@@ -20286,14 +20203,13 @@ rs6000_emit_prologue (void)
          emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset));
         }
 
-      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);
+      insn = rs6000_emit_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));
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
@@ -20362,6 +20278,7 @@ rs6000_emit_prologue (void)
   if (TARGET_AIX && crtl->calls_eh_return)
     {
       rtx tmp_reg, tmp_reg_si, hi, lo, compare_result, toc_save_done, jump;
+      rtx save_insn, join_insn, note;
       long toc_restore_insn;
 
       gcc_assert (frame_reg_rtx == frame_ptr_rtx
@@ -20396,9 +20313,29 @@ rs6000_emit_prologue (void)
       JUMP_LABEL (jump) = toc_save_done;
       LABEL_NUSES (toc_save_done) += 1;
 
-      emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, 2,
-                      sp_offset + 5 * reg_size, info->total_size);
+      save_insn = emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode,
+                                  TOC_REGNUM, sp_offset + 5 * reg_size,
+                                  info->total_size);
+
       emit_label (toc_save_done);
+
+      /* ??? If we leave SAVE_INSN as marked as saving R2, then we'll
+        have a CFG that has different saves along different paths.
+        Move the note to a dummy blockage insn, which describes that
+        R2 is unconditionally saved after the label.  */
+      /* ??? An alternate representation might be a special insn pattern
+        containing both the branch and the store.  That might let the
+        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);
+      RTX_FRAME_RELATED_P (save_insn) = 0;
+
+      join_insn = emit_insn (gen_blockage ());
+      REG_NOTES (join_insn) = note;
+      RTX_FRAME_RELATED_P (join_insn) = 1;
+
       if (using_static_chain_p)
        emit_move_insn (tmp_reg, gen_rtx_REG (Pmode, 0));
     }
@@ -20533,10 +20470,11 @@ rs6000_emit_prologue (void)
     }
 
   /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
-  if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
-      || (DEFAULT_ABI == ABI_V4
-         && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
-         && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM)))
+  if (!TARGET_SINGLE_PIC_BASE
+      && ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
+         || (DEFAULT_ABI == ABI_V4
+             && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
+             && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))))
     {
       /* If emit_load_toc_table will use the link register, we need to save
         it.  We use R12 for this purpose because emit_load_toc_table
@@ -20557,6 +20495,7 @@ rs6000_emit_prologue (void)
          rs6000_emit_load_toc_table (TRUE);
 
          insn = emit_move_insn (lr, frame_ptr_rtx);
+         add_reg_note (insn, REG_CFA_RESTORE, lr);
          RTX_FRAME_RELATED_P (insn) = 1;
        }
       else
@@ -20564,7 +20503,8 @@ rs6000_emit_prologue (void)
     }
 
 #if TARGET_MACHO
-  if (DEFAULT_ABI == ABI_DARWIN
+  if (!TARGET_SINGLE_PIC_BASE
+      && DEFAULT_ABI == ABI_DARWIN
       && flag_pic && crtl->uses_pic_offset_table)
     {
       rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
@@ -20584,6 +20524,27 @@ rs6000_emit_prologue (void)
        emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
     }
 #endif
+
+  /* If we need to, save the TOC register after doing the stack setup.
+     Do not emit eh frame info for this save.  The unwinder wants info,
+     conceptually attached to instructions in this function, about
+     register values in the caller of this function.  This R2 may have
+     already been changed from the value in the caller.
+     We don't attempt to write accurate DWARF EH frame info for R2
+     because code emitted by gcc for a (non-pointer) function call
+     doesn't save and restore R2.  Instead, R2 is managed out-of-line
+     by a linker generated plt call stub when the function resides in
+     a shared library.  This behaviour is costly to describe in DWARF,
+     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.  */ 
+  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));
+    }
 }
 
 /* Write function prologue.  */
@@ -20599,7 +20560,8 @@ 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)
     {
       char *name;
       int regno = info->first_fp_reg_save - 32;
@@ -20630,39 +20592,6 @@ rs6000_output_function_prologue (FILE *file,
       common_mode_defined = 1;
     }
 
-  if (! HAVE_prologue)
-    {
-      rtx prologue;
-
-      start_sequence ();
-
-      /* A NOTE_INSN_DELETED is supposed to be at the start and end of
-        the "toplevel" insn chain.  */
-      emit_note (NOTE_INSN_DELETED);
-      rs6000_emit_prologue ();
-      emit_note (NOTE_INSN_DELETED);
-
-      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
-      {
-       rtx insn;
-       unsigned addr = 0;
-       for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
-         {
-           INSN_ADDRESSES_NEW (insn, addr);
-           addr += 4;
-         }
-      }
-
-      prologue = get_insns ();
-      end_sequence ();
-
-      if (TARGET_DEBUG_STACK)
-       debug_rtx_list (prologue, 100);
-
-      emit_insn_before_noloc (prologue, BB_HEAD (ENTRY_BLOCK_PTR->next_bb),
-                             ENTRY_BLOCK_PTR);
-    }
-
   rs6000_pic_labelno++;
 }
 
@@ -20730,6 +20659,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
@@ -20774,10 +20717,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
@@ -20811,7 +20751,7 @@ rs6000_emit_epilogue (int sibcall)
       alloc_rname = ggc_strdup (rname);
 
       j = 0;
-      RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
+      RTVEC_ELT (p, j++) = ret_rtx;
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
                                        gen_rtx_REG (Pmode,
                                                     LR_REGNO));
@@ -20830,6 +20770,14 @@ rs6000_emit_epilogue (int sibcall)
        rtx mem = gen_frame_mem (reg_mode, addr);
 
        RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+
+       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++)
@@ -20841,6 +20789,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx mem = gen_frame_mem (reg_mode, addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         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++)
        {
@@ -20851,6 +20801,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx mem = gen_frame_mem (V4SImode, addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         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++)
        {
@@ -20864,6 +20816,8 @@ rs6000_emit_epilogue (int sibcall)
                                     ? DFmode : SFmode), addr);
 
          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+         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));
@@ -20875,8 +20829,14 @@ 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;
     }
 
@@ -20921,9 +20881,10 @@ rs6000_emit_epilogue (int sibcall)
 
            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))
+           if (flag_shrink_wrap
+               || 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);
          }
@@ -21062,7 +21023,7 @@ rs6000_emit_epilogue (int sibcall)
 
            reg = gen_rtx_REG (V4SImode, i);
            emit_move_insn (reg, mem);
-           if (DEFAULT_ABI == ABI_V4)
+           if (DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
              cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
                                             cfa_restores);
          }
@@ -21112,8 +21073,7 @@ rs6000_emit_epilogue (int sibcall)
       emit_move_insn (cr_save_reg, mem);
     }
 
-  /* 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));
@@ -21151,7 +21111,7 @@ 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
@@ -21175,7 +21135,7 @@ rs6000_emit_epilogue (int sibcall)
          int ool_adjust = (restoring_GPRs_inline
                            ? 0
                            : (info->first_gp_reg_save
-                              - (FIRST_SAVRES_REGISTER+1))*8);
+                              - (FIRST_SAVRES_REGISTER + 1)) * 8);
 
          if (frame_reg_rtx == sp_reg_rtx)
            frame_reg_rtx = gen_rtx_REG (Pmode, 11);
@@ -21206,48 +21166,32 @@ 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, gen_rtx_REG (Pmode, 11),
+                               0, reg_mode,
+                               /*savep=*/false, /*gpr=*/true,
+                               /*lr=*/true);
     }
   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;
 
       /* Emit stack reset code if we need it.  */
       if (can_use_exit)
-       rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
+       {
+         rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx,
                                 sp_offset, can_use_exit);
+         if (DEFAULT_ABI == ABI_DARWIN)
+           /* we only need a copy, no fprs were saved.  */
+           emit_move_insn (gen_rtx_REG (reg_mode, 11), frame_reg_rtx);
+
+         if (info->cr_save_p)
+           rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
+       }
       else
        {
          emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX
@@ -21258,45 +21202,10 @@ rs6000_emit_epilogue (int sibcall)
            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_savres_rtx (info, frame_reg_rtx,
+                             info->gp_save_offset, reg_mode,
+                             /*savep=*/false, /*gpr=*/true,
+                             /*lr=*/can_use_exit);
     }
   else if (using_load_multiple)
     {
@@ -21312,17 +21221,8 @@ rs6000_emit_epilogue (int sibcall)
          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + 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)
-       {
-         add_reg_note (insn, REG_CFA_DEF_CFA,
-                       plus_constant (frame_reg_rtx, sp_offset));
-         RTX_FRAME_RELATED_P (insn) = 1;
        }
+      emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
   else
     {
@@ -21336,24 +21236,70 @@ rs6000_emit_epilogue (int sibcall)
             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;
-                 }
-
-               cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg,
-                                              cfa_restores);
-             }
+           emit_move_insn (reg, mem);
           }
     }
 
+  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));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+
+      /* 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 the LR cfa_restore condition below is a little
+        complicated.  It's also 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 (info->cr_save_p)
+       cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                      gen_rtx_REG (SImode, CR2_REGNO),
+                                      cfa_restores);
+      if (flag_shrink_wrap
+         && (restore_lr
+             || (info->lr_save_p
+                 && !restoring_GPRs_inline
+                 && info->first_fp_reg_save == 64)))
+       cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                      gen_rtx_REG (Pmode, LR_REGNO),
+                                      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 reg = gen_rtx_REG (reg_mode, i);
+
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE, reg, cfa_restores);
+         }
+    }
+
+  if (!restoring_GPRs_inline
+      && info->first_fp_reg_save == 64)
+    {
+      /* We are jumping to an out-of-line function.  */
+      if (cfa_restores)
+       emit_cfa_restores (cfa_restores);
+      return;
+    }
+
   if (restore_lr && !restoring_GPRs_inline)
     {
       rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx,
@@ -21367,8 +21313,8 @@ rs6000_emit_epilogue (int sibcall)
   /* 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 ((df_regs_ever_live_p (info->first_fp_reg_save + i)
+          && !call_used_regs[info->first_fp_reg_save + i]))
        {
          rtx addr, mem, reg;
          addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
@@ -21382,20 +21328,13 @@ rs6000_emit_epilogue (int sibcall)
                             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);
+         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)
-    {
-      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);
-    }
+    rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple);
 
   /* If this is V.4, unwind the stack pointer after all of the loads
      have been done.  */
@@ -21423,15 +21362,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) = gen_rtx_RETURN (VOIDmode);
       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.  */
@@ -21440,6 +21404,12 @@ rs6000_emit_epilogue (int sibcall)
          int i;
          rtx sym;
 
+         if ((DEFAULT_ABI == ABI_V4 || flag_shrink_wrap)
+             && lr)
+           cfa_restores = alloc_reg_note (REG_CFA_RESTORE,
+                                          gen_rtx_REG (Pmode, LR_REGNO),
+                                          cfa_restores);
+
          sym = rs6000_savres_routine_sym (info,
                                           /*savep=*/false,
                                           /*gpr=*/false,
@@ -21451,20 +21421,32 @@ rs6000_emit_epilogue (int sibcall)
                                                       ? 1 : 11));
          for (i = 0; i < 64 - info->first_fp_reg_save; i++)
            {
-             rtx addr, mem;
+             rtx addr, mem, reg;
+
              addr = gen_rtx_PLUS (Pmode, sp_reg_rtx,
-                                  GEN_INT (info->fp_save_offset + 8*i));
+                                  GEN_INT (info->fp_save_offset + 8 * i));
              mem = gen_frame_mem (DFmode, addr);
+             reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
 
-             RTVEC_ELT (p, i+4) =
-               gen_rtx_SET (VOIDmode,
-                            gen_rtx_REG (DFmode, info->first_fp_reg_save + i),
-                            mem);
+             RTVEC_ELT (p, i + 4) = gen_rtx_SET (VOIDmode, reg, mem);
+             if (DEFAULT_ABI == ABI_V4 || 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.  */
@@ -21473,43 +21455,6 @@ static void
 rs6000_output_function_epilogue (FILE *file,
                                 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  if (! HAVE_epilogue)
-    {
-      rtx insn = get_last_insn ();
-      /* If the last insn was a BARRIER, we don't have to write anything except
-        the trace table.  */
-      if (GET_CODE (insn) == NOTE)
-       insn = prev_nonnote_insn (insn);
-      if (insn == 0 ||  GET_CODE (insn) != BARRIER)
-       {
-         /* This is slightly ugly, but at least we don't have two
-            copies of the epilogue-emitting code.  */
-         start_sequence ();
-
-         /* A NOTE_INSN_DELETED is supposed to be at the start
-            and end of the "toplevel" insn chain.  */
-         emit_note (NOTE_INSN_DELETED);
-         rs6000_emit_epilogue (FALSE);
-         emit_note (NOTE_INSN_DELETED);
-
-         /* Expand INSN_ADDRESSES so final() doesn't crash.  */
-         {
-           rtx insn;
-           unsigned addr = 0;
-           for (insn = get_insns (); insn != 0; insn = NEXT_INSN (insn))
-             {
-               INSN_ADDRESSES_NEW (insn, addr);
-               addr += 4;
-             }
-         }
-
-         if (TARGET_DEBUG_STACK)
-           debug_rtx_list (get_insns (), 100);
-         final (get_insns (), file, FALSE);
-         end_sequence ();
-       }
-    }
-
 #if TARGET_MACHO
   macho_branch_islands ();
   /* Mach-O doesn't support labels at the end of objects, so if
@@ -21592,10 +21537,11 @@ rs6000_output_function_epilogue (FILE *file,
         use language_string.
         C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
         Java is 13.  Objective-C is 14.  Objective-C++ isn't assigned
-        a number, so for now use 9.  LTO isn't assigned a number either,
-        so for now use 0.  */
+        a number, so for now use 9.  LTO and Go aren't assigned numbers
+        either, so for now use 0.  */
       if (! strcmp (language_string, "GNU C")
-         || ! strcmp (language_string, "GNU GIMPLE"))
+         || ! strcmp (language_string, "GNU GIMPLE")
+         || ! strcmp (language_string, "GNU Go"))
        i = 0;
       else if (! strcmp (language_string, "GNU F77")
               || ! strcmp (language_string, "GNU Fortran"))
@@ -21865,7 +21811,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                        gen_rtx_USE (VOIDmode,
                                     gen_rtx_REG (SImode,
                                                  LR_REGNO)),
-                       gen_rtx_RETURN (VOIDmode))));
+                       simple_return_rtx)));
   SIBLING_CALL_P (insn) = 1;
   emit_barrier ();
 
@@ -22029,17 +21975,18 @@ const char *
 rs6000_xcoff_strip_dollar (const char *name)
 {
   char *strip, *p;
-  int len;
+  const char *q;
+  size_t len;
 
-  p = strchr (name, '$');
+  q = (const char *) strchr (name, '$');
 
-  if (p == 0 || p == name)
+  if (q == 0 || q == name)
     return name;
 
   len = strlen (name);
-  strip = (char *) alloca (len + 1);
+  strip = XALLOCAVEC (char, len + 1);
   strcpy (strip, name);
-  p = strchr (strip, '$');
+  p = strip + (q - name);
   while (p)
     {
       *p = '_';
@@ -22533,7 +22480,7 @@ output_profile_hook (int labelno ATTRIBUTE_UNUSED)
          rtx fun;
 
          ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
-         label_name = (*targetm.strip_name_encoding) (ggc_strdup (buf));
+         label_name = ggc_strdup ((*targetm.strip_name_encoding) (buf));
          fun = gen_rtx_SYMBOL_REF (Pmode, label_name);
 
          emit_library_call (init_one_libfunc (RS6000_MCOUNT),
@@ -22588,7 +22535,15 @@ output_function_profiler (FILE *file, int labelno)
        }
       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, "\t{st|stw} %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
          asm_fprintf (file, "\t{cau|addis} %s,%s,",
@@ -22613,10 +22568,24 @@ output_function_profiler (FILE *file, int labelno)
          asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          /* Now, we need to get the address of the label.  */
-         fputs ("\tbcl 20,31,1f\n\t.long ", file);
-         assemble_name (file, buf);
-         fputs ("-.\n1:", file);
-         asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
+         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, "\t{l|lwz} %s,0(%s)\n",
                       reg_names[0], reg_names[11]);
          asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
@@ -23192,8 +23161,8 @@ adjacent_mem_locations (rtx insn1, rtx insn2)
       val_diff = val1 - val0;
 
       return ((REGNO (reg0) == REGNO (reg1))
-             && ((MEM_SIZE (a) && val_diff == INTVAL (MEM_SIZE (a)))
-                 || (MEM_SIZE (b) && val_diff == -INTVAL (MEM_SIZE (b)))));
+             && ((MEM_SIZE_KNOWN_P (a) && val_diff == MEM_SIZE (a))
+                 || (MEM_SIZE_KNOWN_P (b) && val_diff == -MEM_SIZE (b))));
     }
 
   return false;
@@ -24536,9 +24505,14 @@ rs6000_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
     /* Under AIX, just build the 3 word function descriptor */
     case ABI_AIX:
       {
-       rtx fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
-       rtx fn_reg = gen_reg_rtx (Pmode);
-       rtx toc_reg = gen_reg_rtx (Pmode);
+       rtx fnmem, fn_reg, toc_reg;
+
+       if (!TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+         error ("-mno-r11 must not be used if you have trampolines");
+
+       fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr));
+       fn_reg = gen_reg_rtx (Pmode);
+       toc_reg = gen_reg_rtx (Pmode);
 
   /* Macro to shorten the code expansions below.  */
 # define MEM_PLUS(MEM, OFFSET) adjust_address (MEM, Pmode, OFFSET)
@@ -25094,11 +25068,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_ppc64_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);
@@ -25244,8 +25231,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");
@@ -25366,10 +25363,12 @@ rs6000_darwin_file_start (void)
   darwin_file_start ();
 
   /* Determine the argument to -mcpu=.  Default to G3 if not specified.  */
-  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
-    if (rs6000_select[i].set_arch_p && rs6000_select[i].string
-       && rs6000_select[i].string[0] != '\0')
-      cpu_id = rs6000_select[i].string;
+  
+  if (rs6000_default_cpu != 0 && rs6000_default_cpu[0] != '\0')
+    cpu_id = rs6000_default_cpu;
+
+  if (global_options_set.x_rs6000_cpu_index)
+    cpu_id = processor_target_table[rs6000_cpu_index].name;
 
   /* Look through the mapping array.  Pick the first name that either
      matches the argument, has a bit set in IF_SET that is also set
@@ -25540,10 +25539,30 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
 }
 
 static void
-rs6000_elf_end_indicate_exec_stack (void)
+rs6000_elf_file_end (void)
 {
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+  if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
+    {
+      if (rs6000_passes_float)
+       fprintf (asm_out_file, "\t.gnu_attribute 4, %d\n",
+                ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) ? 1 
+                 : (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT) ? 3 
+                 : 2));
+      if (rs6000_passes_vector)
+       fprintf (asm_out_file, "\t.gnu_attribute 8, %d\n",
+                (TARGET_ALTIVEC_ABI ? 2
+                 : TARGET_SPE_ABI ? 3
+                 : 1));
+      if (rs6000_returns_struct)
+       fprintf (asm_out_file, "\t.gnu_attribute 12, %d\n",
+                aix_struct_return ? 2 : 1);
+    }
+#endif
+#ifdef POWERPC_LINUX
   if (TARGET_32BIT)
     file_end_indicate_exec_stack ();
+#endif
 }
 #endif
 
@@ -25803,8 +25822,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);
 
@@ -25911,54 +25930,9 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total,
       return true;
 
     case PLUS:
-      if (mode == DFmode)
-       {
-         if (GET_CODE (XEXP (x, 0)) == MULT)
-           {
-             /* FNMA accounted in outer NEG.  */
-             if (outer_code == NEG)
-               *total = rs6000_cost->dmul - rs6000_cost->fp;
-             else
-               *total = rs6000_cost->dmul;
-           }
-         else
-           *total = rs6000_cost->fp;
-       }
-      else if (mode == SFmode)
-       {
-         /* FNMA accounted in outer NEG.  */
-         if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
-           *total = 0;
-         else
-           *total = rs6000_cost->fp;
-       }
-      else
-       *total = COSTS_N_INSNS (1);
-      return false;
-
     case MINUS:
-      if (mode == DFmode)
-       {
-         if (GET_CODE (XEXP (x, 0)) == MULT
-             || GET_CODE (XEXP (x, 1)) == MULT)
-           {
-             /* FNMA accounted in outer NEG.  */
-             if (outer_code == NEG)
-               *total = rs6000_cost->dmul - rs6000_cost->fp;
-             else
-               *total = rs6000_cost->dmul;
-           }
-         else
-           *total = rs6000_cost->fp;
-       }
-      else if (mode == SFmode)
-       {
-         /* FNMA accounted in outer NEG.  */
-         if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
-           *total = 0;
-         else
-           *total = rs6000_cost->fp;
-       }
+      if (FLOAT_MODE_P (mode))
+       *total = rs6000_cost->fp;
       else
        *total = COSTS_N_INSNS (1);
       return false;
@@ -25973,20 +25947,23 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total,
          else
            *total = rs6000_cost->mulsi_const;
        }
-      /* FMA accounted in outer PLUS/MINUS.  */
-      else if ((mode == DFmode || mode == SFmode)
-              && (outer_code == PLUS || outer_code == MINUS))
-       *total = 0;
-      else if (mode == DFmode)
-       *total = rs6000_cost->dmul;
       else if (mode == SFmode)
        *total = rs6000_cost->fp;
+      else if (FLOAT_MODE_P (mode))
+       *total = rs6000_cost->dmul;
       else if (mode == DImode)
        *total = rs6000_cost->muldi;
       else
        *total = rs6000_cost->mulsi;
       return false;
 
+    case FMA:
+      if (mode == SFmode)
+       *total = rs6000_cost->fp;
+      else
+       *total = rs6000_cost->dmul;
+      break;
+
     case DIV:
     case MOD:
       if (FLOAT_MODE_P (mode))
@@ -26189,17 +26166,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");
 
@@ -26232,26 +26210,32 @@ rs6000_register_move_cost (enum machine_mode mode,
 {
   int ret;
 
+  if (TARGET_DEBUG_COST)
+    dbg_cost_ctrl++;
+
   /*  Moves from/to GENERAL_REGS.  */
   if (reg_classes_intersect_p (to, GENERAL_REGS)
       || reg_classes_intersect_p (from, GENERAL_REGS))
     {
+      reg_class_t rclass = from;
+
       if (! reg_classes_intersect_p (to, GENERAL_REGS))
-       from = to;
+       rclass = to;
 
-      if (from == FLOAT_REGS || from == ALTIVEC_REGS || from == VSX_REGS)
-       ret = (rs6000_memory_move_cost (mode, from, false)
+      if (rclass == FLOAT_REGS || rclass == ALTIVEC_REGS || rclass == VSX_REGS)
+       ret = (rs6000_memory_move_cost (mode, rclass, false)
               + rs6000_memory_move_cost (mode, GENERAL_REGS, false));
 
       /* It's more expensive to move CR_REGS than CR0_REGS because of the
         shift.  */
-      else if (from == CR_REGS)
+      else if (rclass == CR_REGS)
        ret = 4;
 
-      /* Power6 has slower LR/CTR moves so make them more expensive than
-        memory in order to bias spills to memory .*/
-      else if (rs6000_cpu == PROCESSOR_POWER6
-              && reg_classes_intersect_p (from, LINK_OR_CTR_REGS))
+      /* For those processors that have slow LR/CTR moves, make them more
+         expensive than memory in order to bias spills to memory .*/
+      else if ((rs6000_cpu == PROCESSOR_POWER6
+               || rs6000_cpu == PROCESSOR_POWER7)
+              && reg_classes_intersect_p (rclass, LINK_OR_CTR_REGS))
         ret = 6 * hard_regno_nregs[0][mode];
 
       else
@@ -26275,10 +26259,14 @@ rs6000_register_move_cost (enum machine_mode mode,
           + rs6000_register_move_cost (mode, from, GENERAL_REGS));
 
   if (TARGET_DEBUG_COST)
-    fprintf (stderr,
-            "rs6000_register_move_cost:, ret=%d, mode=%s, from=%s, to=%s\n",
-            ret, GET_MODE_NAME (mode), reg_class_names[from],
-            reg_class_names[to]);
+    {
+      if (dbg_cost_ctrl == 1)
+       fprintf (stderr,
+                "rs6000_register_move_cost:, ret=%d, mode=%s, from=%s, to=%s\n",
+                ret, GET_MODE_NAME (mode), reg_class_names[from],
+                reg_class_names[to]);
+      dbg_cost_ctrl--;
+    }
 
   return ret;
 }
@@ -26292,6 +26280,9 @@ rs6000_memory_move_cost (enum machine_mode mode, reg_class_t rclass,
 {
   int ret;
 
+  if (TARGET_DEBUG_COST)
+    dbg_cost_ctrl++;
+
   if (reg_classes_intersect_p (rclass, GENERAL_REGS))
     ret = 4 * hard_regno_nregs[0][mode];
   else if (reg_classes_intersect_p (rclass, FLOAT_REGS))
@@ -26302,9 +26293,13 @@ rs6000_memory_move_cost (enum machine_mode mode, reg_class_t rclass,
     ret = 4 + rs6000_register_move_cost (mode, rclass, GENERAL_REGS);
 
   if (TARGET_DEBUG_COST)
-    fprintf (stderr,
-            "rs6000_memory_move_cost: ret=%d, mode=%s, rclass=%s, in=%d\n",
-            ret, GET_MODE_NAME (mode), reg_class_names[rclass], in);
+    {
+      if (dbg_cost_ctrl == 1)
+       fprintf (stderr,
+                "rs6000_memory_move_cost: ret=%d, mode=%s, rclass=%s, in=%d\n",
+                ret, GET_MODE_NAME (mode), reg_class_names[rclass], in);
+      dbg_cost_ctrl--;
+    }
 
   return ret;
 }
@@ -26787,7 +26782,7 @@ rs6000_function_value (const_tree valtype,
       valcum.vregno = ALTIVEC_ARG_MIN_REG;
       /* Do a trial code generation as if this were going to be passed as
         an argument; if any part goes in memory, we return NULL.  */
-      valret = rs6000_darwin64_record_arg (&valcum, valtype, true, true);
+      valret = rs6000_darwin64_record_arg (&valcum, valtype, true, /* retval= */ true);
       if (valret)
        return valret;
       /* Otherwise fall through to standard ABI rules.  */
@@ -26841,13 +26836,12 @@ rs6000_function_value (const_tree valtype,
   else if (TREE_CODE (valtype) == COMPLEX_TYPE
           && targetm.calls.split_complex_arg)
     return rs6000_complex_function_value (mode);
+  /* VSX is a superset of Altivec and adds V2DImode/V2DFmode.  Since the same
+     return register is used in both cases, and we won't see V2DImode/V2DFmode
+     for pure altivec, combine the two cases.  */
   else if (TREE_CODE (valtype) == VECTOR_TYPE
           && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
-          && ALTIVEC_VECTOR_MODE (mode))
-    regno = ALTIVEC_ARG_RETURN;
-  else if (TREE_CODE (valtype) == VECTOR_TYPE
-          && TARGET_VSX && TARGET_ALTIVEC_ABI
-          && VSX_VECTOR_MODE (mode))
+          && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
     regno = ALTIVEC_ARG_RETURN;
   else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
           && (mode == DFmode || mode == DCmode
@@ -26887,12 +26881,12 @@ rs6000_libcall_value (enum machine_mode mode)
           && TARGET_HARD_FLOAT && TARGET_FPRS
            && ((TARGET_SINGLE_FLOAT && mode == SFmode) || TARGET_DOUBLE_FLOAT))
     regno = FP_ARG_RETURN;
-  else if (ALTIVEC_VECTOR_MODE (mode)
+  /* VSX is a superset of Altivec and adds V2DImode/V2DFmode.  Since the same
+     return register is used in both cases, and we won't see V2DImode/V2DFmode
+     for pure altivec, combine the two cases.  */
+  else if (ALTIVEC_OR_VSX_VECTOR_MODE (mode)
           && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
     regno = ALTIVEC_ARG_RETURN;
-  else if (VSX_VECTOR_MODE (mode)
-          && TARGET_VSX && TARGET_ALTIVEC_ABI)
-    regno = ALTIVEC_ARG_RETURN;
   else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
     return rs6000_complex_function_value (mode);
   else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
@@ -27109,7 +27103,7 @@ invalid_arg_for_unprototyped_fn (const_tree typelist, const_tree funcdecl, const
    calling __stack_chk_fail directly.  Otherwise it is better to call
    __stack_chk_fail directly.  */
 
-static tree
+static tree ATTRIBUTE_UNUSED
 rs6000_stack_protect_fail (void)
 {
   return (DEFAULT_ABI == ABI_V4 && TARGET_SECURE_PLT && flag_pic)
@@ -27145,6 +27139,585 @@ rs6000_final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED,
 }
 
 \f
+/* Mask options that we want to support inside of attribute((target)) and
+   #pragma GCC target operations.  Note, we do not include things like
+   64/32-bit, endianess, hard/soft floating point, etc. that would have
+   different calling sequences.  */
+
+struct rs6000_opt_mask {
+  const char *name;            /* option name */
+  int mask;                    /* mask to set */
+  bool invert;                 /* invert sense of mask */
+  bool valid_target;           /* option is a target option */
+};
+
+static struct rs6000_opt_mask const rs6000_opt_masks[] =
+{
+  { "altivec",         MASK_ALTIVEC,           false, true  },
+  { "cmpb",            MASK_CMPB,              false, true  },
+  { "dlmzb",           MASK_DLMZB,             false, true  },
+  { "fprnd",           MASK_FPRND,             false, true  },
+  { "hard-dfp",                MASK_DFP,               false, true  },
+  { "isel",            MASK_ISEL,              false, true  },
+  { "mfcrf",           MASK_MFCRF,             false, true  },
+  { "mfpgpr",          MASK_MFPGPR,            false, true  },
+  { "mulhw",           MASK_MULHW,             false, true  },
+  { "multiple",                MASK_MULTIPLE,          false, true  },
+  { "update",          MASK_NO_UPDATE,         true , true  },
+  { "popcntb",         MASK_POPCNTB,           false, true  },
+  { "popcntd",         MASK_POPCNTD,           false, true  },
+  { "powerpc-gfxopt",  MASK_PPC_GFXOPT,        false, true  },
+  { "powerpc-gpopt",   MASK_PPC_GPOPT,         false, true  },
+  { "recip-precision", MASK_RECIP_PRECISION,   false, true  },
+  { "string",          MASK_STRING,            false, true  },
+  { "vsx",             MASK_VSX,               false, true  },
+#ifdef MASK_64BIT
+#if TARGET_AIX_OS
+  { "aix64",           MASK_64BIT,             false, false },
+  { "aix32",           MASK_64BIT,             true,  false },
+#else
+  { "64",              MASK_64BIT,             false, false },
+  { "32",              MASK_64BIT,             true,  false },
+#endif
+#endif
+#ifdef MASK_EABI
+  { "eabi",            MASK_EABI,              false, false },
+#endif
+#ifdef MASK_LITTLE_ENDIAN
+  { "little",          MASK_LITTLE_ENDIAN,     false, false },
+  { "big",             MASK_LITTLE_ENDIAN,     true,  false },
+#endif
+#ifdef MASK_RELOCATABLE
+  { "relocatable",     MASK_RELOCATABLE,       false, false },
+#endif
+#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 },
+};
+
+/* Option variables that we want to support inside attribute((target)) and
+   #pragma GCC target operations.  */
+
+struct rs6000_opt_var {
+  const char *name;            /* option name */
+  size_t global_offset;                /* offset of the option in global_options.  */
+  size_t target_offset;                /* offset of the option in target optiosn.  */
+};
+
+static struct rs6000_opt_var const rs6000_opt_vars[] =
+{
+  { "friz",
+    offsetof (struct gcc_options, x_TARGET_FRIZ),
+    offsetof (struct cl_target_option, x_TARGET_FRIZ), },
+  { "avoid-indexed-addresses",
+    offsetof (struct gcc_options, x_TARGET_AVOID_XFORM),
+    offsetof (struct cl_target_option, x_TARGET_AVOID_XFORM) },
+  { "paired",
+    offsetof (struct gcc_options, x_rs6000_paired_float),
+    offsetof (struct cl_target_option, x_rs6000_paired_float), },
+  { "longcall",
+    offsetof (struct gcc_options, x_rs6000_default_long_calls),
+    offsetof (struct cl_target_option, x_rs6000_default_long_calls), },
+};
+
+/* Inner function to handle attribute((target("..."))) and #pragma GCC target
+   parsing.  Return true if there were no errors.  */
+
+static bool
+rs6000_inner_target_options (tree args, bool attr_p)
+{
+  bool ret = true;
+
+  if (args == NULL_TREE)
+    ;
+
+  else if (TREE_CODE (args) == STRING_CST)
+    {
+      char *p = ASTRDUP (TREE_STRING_POINTER (args));
+      char *q;
+
+      while ((q = strtok (p, ",")) != NULL)
+       {
+         bool error_p = false;
+         bool not_valid_p = false;
+         const char *cpu_opt = NULL;
+
+         p = NULL;
+         if (strncmp (q, "cpu=", 4) == 0)
+           {
+             int cpu_index = rs6000_cpu_name_lookup (q+4);
+             if (cpu_index >= 0)
+               rs6000_cpu_index = cpu_index;
+             else
+               {
+                 error_p = true;
+                 cpu_opt = q+4;
+               }
+           }
+         else if (strncmp (q, "tune=", 5) == 0)
+           {
+             int tune_index = rs6000_cpu_name_lookup (q+5);
+             if (tune_index >= 0)
+               rs6000_tune_index = tune_index;
+             else
+               {
+                 error_p = true;
+                 cpu_opt = q+5;
+               }
+           }
+         else
+           {
+             size_t i;
+             bool invert = false;
+             char *r = q;
+
+             error_p = true;
+             if (strncmp (r, "no-", 3) == 0)
+               {
+                 invert = true;
+                 r += 3;
+               }
+
+             for (i = 0; i < ARRAY_SIZE (rs6000_opt_masks); i++)
+               if (strcmp (r, rs6000_opt_masks[i].name) == 0)
+                 {
+                   int mask = rs6000_opt_masks[i].mask;
+
+                   if (!rs6000_opt_masks[i].valid_target)
+                     not_valid_p = true;
+                   else
+                     {
+                       error_p = false;
+                       target_flags_explicit |= mask;
+
+                       if (rs6000_opt_masks[i].invert)
+                         invert = !invert;
+
+                       if (invert)
+                         target_flags &= ~mask;
+                       else
+                         target_flags |= mask;
+                     }
+                   break;
+                 }
+
+             if (error_p && !not_valid_p)
+               {
+                 for (i = 0; i < ARRAY_SIZE (rs6000_opt_vars); i++)
+                   if (strcmp (r, rs6000_opt_vars[i].name) == 0)
+                     {
+                       size_t j = rs6000_opt_vars[i].global_offset;
+                       ((int *) &global_options)[j] = !invert;
+                       error_p = false;
+                       break;
+                     }
+               }
+           }
+
+         if (error_p)
+           {
+             const char *eprefix, *esuffix;
+
+             ret = false;
+             if (attr_p)
+               {
+                 eprefix = "__attribute__((__target__(";
+                 esuffix = ")))";
+               }
+             else
+               {
+                 eprefix = "#pragma GCC target ";
+                 esuffix = "";
+               }
+
+             if (cpu_opt)
+               error ("invalid cpu \"%s\" for %s\"%s\"%s", cpu_opt, eprefix,
+                      q, esuffix);
+             else if (not_valid_p)
+               error ("%s\"%s\"%s is not allowed", eprefix, q, esuffix);
+             else
+               error ("%s\"%s\"%s is invalid", eprefix, q, esuffix);
+           }
+       }
+    }
+
+  else if (TREE_CODE (args) == TREE_LIST)
+    {
+      do
+       {
+         tree value = TREE_VALUE (args);
+         if (value)
+           {
+             bool ret2 = rs6000_inner_target_options (value, attr_p);
+             if (!ret2)
+               ret = false;
+           }
+         args = TREE_CHAIN (args);
+       }
+      while (args != NULL_TREE);
+    }
+
+  else
+    gcc_unreachable ();
+
+  return ret;
+}
+
+/* Print out the target options as a list for -mdebug=target.  */
+
+static void
+rs6000_debug_target_options (tree args, const char *prefix)
+{
+  if (args == NULL_TREE)
+    fprintf (stderr, "%s<NULL>", prefix);
+
+  else if (TREE_CODE (args) == STRING_CST)
+    {
+      char *p = ASTRDUP (TREE_STRING_POINTER (args));
+      char *q;
+
+      while ((q = strtok (p, ",")) != NULL)
+       {
+         p = NULL;
+         fprintf (stderr, "%s\"%s\"", prefix, q);
+         prefix = ", ";
+       }
+    }
+
+  else if (TREE_CODE (args) == TREE_LIST)
+    {
+      do
+       {
+         tree value = TREE_VALUE (args);
+         if (value)
+           {
+             rs6000_debug_target_options (value, prefix);
+             prefix = ", ";
+           }
+         args = TREE_CHAIN (args);
+       }
+      while (args != NULL_TREE);
+    }
+
+  else
+    gcc_unreachable ();
+
+  return;
+}
+
+\f
+/* Hook to validate attribute((target("..."))).  */
+
+static bool
+rs6000_valid_attribute_p (tree fndecl,
+                         tree ARG_UNUSED (name),
+                         tree args,
+                         int flags)
+{
+  struct cl_target_option cur_target;
+  bool ret;
+  tree old_optimize = build_optimization_node ();
+  tree new_target, new_optimize;
+  tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  gcc_assert ((fndecl != NULL_TREE) && (args != NULL_TREE));
+
+  if (TARGET_DEBUG_TARGET)
+    {
+      tree tname = DECL_NAME (fndecl);
+      fprintf (stderr, "\n==================== rs6000_valid_attribute_p:\n");
+      if (tname)
+       fprintf (stderr, "function: %.*s\n",
+                (int) IDENTIFIER_LENGTH (tname),
+                IDENTIFIER_POINTER (tname));
+      else
+       fprintf (stderr, "function: unknown\n");
+  
+      fprintf (stderr, "args:");
+      rs6000_debug_target_options (args, " ");
+      fprintf (stderr, "\n");
+
+      if (flags)
+       fprintf (stderr, "flags: 0x%x\n", flags);
+
+      fprintf (stderr, "--------------------\n");
+    }
+
+  old_optimize = build_optimization_node ();
+  func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+
+  /* If the function changed the optimization levels as well as setting target
+     options, start with the optimizations specified.  */
+  if (func_optimize && func_optimize != old_optimize)
+    cl_optimization_restore (&global_options,
+                            TREE_OPTIMIZATION (func_optimize));
+
+  /* The target attributes may also change some optimization flags, so update
+     the optimization options if necessary.  */
+  cl_target_option_save (&cur_target, &global_options);
+  rs6000_cpu_index = rs6000_tune_index = -1;
+  ret = rs6000_inner_target_options (args, true);
+
+  /* Set up any additional state.  */
+  if (ret)
+    {
+      ret = rs6000_option_override_internal (false);
+      new_target = build_target_option_node ();
+    }
+  else
+    new_target = NULL;
+
+  new_optimize = build_optimization_node ();
+
+  if (!new_target)
+    ret = false;
+
+  else if (fndecl)
+    {
+      DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target;
+
+      if (old_optimize != new_optimize)
+       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize;
+    }
+
+  cl_target_option_restore (&global_options, &cur_target);
+
+  if (old_optimize != new_optimize)
+    cl_optimization_restore (&global_options,
+                            TREE_OPTIMIZATION (old_optimize));
+
+  return ret;
+}
+
+\f
+/* Hook to validate the current #pragma GCC target and set the state, and
+   update the macros based on what was changed.  If ARGS is NULL, then
+   POP_TARGET is used to reset the options.  */
+
+bool
+rs6000_pragma_target_parse (tree args, tree pop_target)
+{
+  tree cur_tree;
+  bool ret;
+
+  if (TARGET_DEBUG_TARGET)
+    {
+      fprintf (stderr, "\n==================== rs6000_pragma_target_parse\n");
+      fprintf (stderr, "args:");
+      rs6000_debug_target_options (args, " ");
+      fprintf (stderr, "\n");
+
+      if (pop_target)
+       {
+         fprintf (stderr, "pop_target:\n");
+         debug_tree (pop_target);
+       }
+      else
+       fprintf (stderr, "pop_target: <NULL>\n");
+
+      fprintf (stderr, "--------------------\n");
+    }
+
+  if (! args)
+    {
+      ret = true;
+      cur_tree = ((pop_target)
+                 ? pop_target
+                 : target_option_default_node);
+      cl_target_option_restore (&global_options,
+                               TREE_TARGET_OPTION (cur_tree));
+    }
+  else
+    {
+      rs6000_cpu_index = rs6000_tune_index = -1;
+      ret = rs6000_inner_target_options (args, false);
+      cur_tree = build_target_option_node ();
+
+      if (!cur_tree)
+       ret = false;
+    }
+
+  if (cur_tree)
+    target_option_current_node = cur_tree;
+
+  return ret;
+}
+
+\f
+/* Remember the last target of rs6000_set_current_function.  */
+static GTY(()) tree rs6000_previous_fndecl;
+
+/* Establish appropriate back-end context for processing the function
+   FNDECL.  The argument might be NULL to indicate processing at top
+   level, outside of any function scope.  */
+static void
+rs6000_set_current_function (tree fndecl)
+{
+  tree old_tree = (rs6000_previous_fndecl
+                  ? DECL_FUNCTION_SPECIFIC_TARGET (rs6000_previous_fndecl)
+                  : NULL_TREE);
+
+  tree new_tree = (fndecl
+                  ? DECL_FUNCTION_SPECIFIC_TARGET (fndecl)
+                  : NULL_TREE);
+
+  if (TARGET_DEBUG_TARGET)
+    {
+      bool print_final = false;
+      fprintf (stderr, "\n==================== rs6000_set_current_function");
+
+      if (fndecl)
+       fprintf (stderr, ", fndecl %s (%p)",
+                (DECL_NAME (fndecl)
+                 ? IDENTIFIER_POINTER (DECL_NAME (fndecl))
+                 : "<unknown>"), (void *)fndecl);
+
+      if (rs6000_previous_fndecl)
+       fprintf (stderr, ", prev_fndecl (%p)", (void *)rs6000_previous_fndecl);
+
+      fprintf (stderr, "\n");
+      if (new_tree)
+       {
+         fprintf (stderr, "\nnew fndecl target specific options:\n");
+         debug_tree (new_tree);
+         print_final = true;
+       }
+
+      if (old_tree)
+       {
+         fprintf (stderr, "\nold fndecl target specific options:\n");
+         debug_tree (old_tree);
+         print_final = true;
+       }
+
+      if (print_final)
+       fprintf (stderr, "--------------------\n");
+    }
+
+  /* Only change the context if the function changes.  This hook is called
+     several times in the course of compiling a function, and we don't want to
+     slow things down too much or call target_reinit when it isn't safe.  */
+  if (fndecl && fndecl != rs6000_previous_fndecl)
+    {
+      rs6000_previous_fndecl = fndecl;
+      if (old_tree == new_tree)
+       ;
+
+      else if (new_tree)
+       {
+         cl_target_option_restore (&global_options,
+                                   TREE_TARGET_OPTION (new_tree));
+         target_reinit ();
+       }
+
+      else if (old_tree)
+       {
+         struct cl_target_option *def
+           = TREE_TARGET_OPTION (target_option_current_node);
+
+         cl_target_option_restore (&global_options, def);
+         target_reinit ();
+       }
+    }
+}
+
+\f
+/* Save the current options */
+
+static void
+rs6000_function_specific_save (struct cl_target_option *ptr)
+{
+  ptr->rs6000_target_flags_explicit = target_flags_explicit;
+}
+
+/* Restore the current options */
+
+static void
+rs6000_function_specific_restore (struct cl_target_option *ptr)
+{
+  target_flags_explicit = ptr->rs6000_target_flags_explicit;
+  (void) rs6000_option_override_internal (false);
+}
+
+/* Print the current options */
+
+static void
+rs6000_function_specific_print (FILE *file, int indent,
+                               struct cl_target_option *ptr)
+{
+  size_t i;
+  int flags = ptr->x_target_flags;
+
+  /* Print the various mask options.  */
+  for (i = 0; i < ARRAY_SIZE (rs6000_opt_masks); i++)
+    if ((flags & rs6000_opt_masks[i].mask) != 0)
+      {
+       flags &= ~ rs6000_opt_masks[i].mask;
+       fprintf (file, "%*s-m%s%s\n", indent, "",
+                rs6000_opt_masks[i].invert ? "no-" : "",
+                rs6000_opt_masks[i].name);
+      }
+
+  /* Print the various options that are variables.  */
+  for (i = 0; i < ARRAY_SIZE (rs6000_opt_vars); i++)
+    {
+      size_t j = rs6000_opt_vars[i].target_offset;
+      if (((signed char *) ptr)[j])
+       fprintf (file, "%*s-m%s\n", indent, "",
+                rs6000_opt_vars[i].name);
+    }
+}
+
+\f
+/* Hook to determine if one function can safely inline another.  */
+
+static bool
+rs6000_can_inline_p (tree caller, tree callee)
+{
+  bool ret = false;
+  tree caller_tree = DECL_FUNCTION_SPECIFIC_TARGET (caller);
+  tree callee_tree = DECL_FUNCTION_SPECIFIC_TARGET (callee);
+
+  /* If callee has no option attributes, then it is ok to inline.  */
+  if (!callee_tree)
+    ret = true;
+
+  /* If caller has no option attributes, but callee does then it is not ok to
+     inline.  */
+  else if (!caller_tree)
+    ret = false;
+
+  else
+    {
+      struct cl_target_option *caller_opts = TREE_TARGET_OPTION (caller_tree);
+      struct cl_target_option *callee_opts = TREE_TARGET_OPTION (callee_tree);
+
+      /* Callee's options should a subset of the caller's, i.e. a vsx function
+        can inline an altivec function but a non-vsx function can't inline a
+        vsx function.  */
+      if ((caller_opts->x_target_flags & callee_opts->x_target_flags)
+         == callee_opts->x_target_flags)
+       ret = true;
+    }
+
+  if (TARGET_DEBUG_TARGET)
+    fprintf (stderr, "rs6000_can_inline_p:, caller %s, callee %s, %s inline\n",
+            (DECL_NAME (caller)
+             ? IDENTIFIER_POINTER (DECL_NAME (caller))
+             : "<unknown>"),
+            (DECL_NAME (callee)
+             ? IDENTIFIER_POINTER (DECL_NAME (callee))
+             : "<unknown>"),
+            (ret ? "can" : "cannot"));
+
+  return ret;
+}
+\f
 /* Allocate a stack temp and fixup the address so it meets the particular
    memory requirements (either offetable or REG+REG addressing).  */
 
@@ -27210,4 +27783,239 @@ rs6000_address_for_fpconvert (rtx x)
   return x;
 }
 
+/* Given a memory reference, if it is not in the form for altivec memory
+   reference instructions (i.e. reg or reg+reg addressing with AND of -16),
+   convert to the altivec format.  */
+
+rtx
+rs6000_address_for_altivec (rtx x)
+{
+  gcc_assert (MEM_P (x));
+  if (!altivec_indexed_or_indirect_operand (x, GET_MODE (x)))
+    {
+      rtx addr = XEXP (x, 0);
+      int strict_p = (reload_in_progress || reload_completed);
+
+      if (!legitimate_indexed_address_p (addr, strict_p)
+         && !legitimate_indirect_address_p (addr, strict_p))
+       addr = copy_to_mode_reg (Pmode, addr);
+
+      addr = gen_rtx_AND (Pmode, addr, GEN_INT (-16));
+      x = change_address (x, GET_MODE (x), addr);
+    }
+
+  return x;
+}
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P.
+
+   On the RS/6000, all integer constants are acceptable, most won't be valid
+   for particular insns, though.  Only easy FP constants are acceptable.  */
+
+static bool
+rs6000_legitimate_constant_p (enum machine_mode mode, rtx x)
+{
+  if (rs6000_tls_referenced_p (x))
+    return false;
+
+  return ((GET_CODE (x) != CONST_DOUBLE && GET_CODE (x) != CONST_VECTOR)
+         || GET_MODE (x) == VOIDmode
+         || (TARGET_POWERPC64 && mode == DImode)
+         || easy_fp_constant (x, mode)
+         || easy_vector_constant (x, mode));
+}
+
+\f
+/* A function pointer under AIX is a pointer to a data area whose first word
+   contains the actual address of the function, whose second word contains a
+   pointer to its TOC, and whose third word contains a value to place in the
+   static chain register (r11).  Note that if we load the static chain, our
+   "trampoline" need not have any executable code.  */
+
+void
+rs6000_call_indirect_aix (rtx value, rtx func_desc, rtx flag)
+{
+  rtx func_addr;
+  rtx toc_reg;
+  rtx sc_reg;
+  rtx stack_ptr;
+  rtx stack_toc_offset;
+  rtx stack_toc_mem;
+  rtx func_toc_offset;
+  rtx func_toc_mem;
+  rtx func_sc_offset;
+  rtx func_sc_mem;
+  rtx insn;
+  rtx (*call_func) (rtx, rtx, rtx, rtx);
+  rtx (*call_value_func) (rtx, rtx, rtx, rtx, rtx);
+
+  stack_ptr = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
+  toc_reg = gen_rtx_REG (Pmode, TOC_REGNUM);
+
+  /* Load up address of the actual function.  */
+  func_desc = force_reg (Pmode, func_desc);
+  func_addr = gen_reg_rtx (Pmode);
+  emit_move_insn (func_addr, gen_rtx_MEM (Pmode, func_desc));
+
+  if (TARGET_32BIT)
+    {
+
+      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_32BIT);
+      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_32BIT);
+      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_32BIT);
+      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+       {
+         call_func = gen_call_indirect_aix32bit;
+         call_value_func = gen_call_value_indirect_aix32bit;
+       }
+      else
+       {
+         call_func = gen_call_indirect_aix32bit_nor11;
+         call_value_func = gen_call_value_indirect_aix32bit_nor11;
+       }
+    }
+  else
+    {
+      stack_toc_offset = GEN_INT (TOC_SAVE_OFFSET_64BIT);
+      func_toc_offset = GEN_INT (AIX_FUNC_DESC_TOC_64BIT);
+      func_sc_offset = GEN_INT (AIX_FUNC_DESC_SC_64BIT);
+      if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+       {
+         call_func = gen_call_indirect_aix64bit;
+         call_value_func = gen_call_value_indirect_aix64bit;
+       }
+      else
+       {
+         call_func = gen_call_indirect_aix64bit_nor11;
+         call_value_func = gen_call_value_indirect_aix64bit_nor11;
+       }
+    }
+
+  /* Reserved spot to store the TOC.  */
+  stack_toc_mem = gen_frame_mem (Pmode,
+                                gen_rtx_PLUS (Pmode,
+                                              stack_ptr,
+                                              stack_toc_offset));
+
+  gcc_assert (cfun);
+  gcc_assert (cfun->machine);
+
+  /* Can we optimize saving the TOC in the prologue or do we need to do it at
+     every call?  */
+  if (TARGET_SAVE_TOC_INDIRECT && !cfun->calls_alloca)
+    cfun->machine->save_toc_in_prologue = true;
+
+  else
+    {
+      MEM_VOLATILE_P (stack_toc_mem) = 1;
+      emit_move_insn (stack_toc_mem, toc_reg);
+    }
+
+  /* Calculate the address to load the TOC of the called function.  We don't
+     actually load this until the split after reload.  */
+  func_toc_mem = gen_rtx_MEM (Pmode,
+                             gen_rtx_PLUS (Pmode,
+                                           func_desc,
+                                           func_toc_offset));
+
+  /* If we have a static chain, load it up.  */
+  if (TARGET_POINTERS_TO_NESTED_FUNCTIONS)
+    {
+      func_sc_mem = gen_rtx_MEM (Pmode,
+                                gen_rtx_PLUS (Pmode,
+                                              func_desc,
+                                              func_sc_offset));
+
+      sc_reg = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
+      emit_move_insn (sc_reg, func_sc_mem);
+    }
+
+  /* Create the call.  */
+  if (value)
+    insn = call_value_func (value, func_addr, flag, func_toc_mem,
+                           stack_toc_mem);
+  else
+    insn = call_func (func_addr, flag, func_toc_mem, stack_toc_mem);
+
+  emit_call_insn (insn);
+}
+
+/* Return whether we need to always update the saved TOC pointer when we update
+   the stack pointer.  */
+
+static bool
+rs6000_save_toc_in_prologue_p (void)
+{
+  return (cfun && cfun->machine && cfun->machine->save_toc_in_prologue);
+}
+
+/* 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 (HAVE_GAS_HIDDEN)
+    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)
+{
+  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 (HAVE_GAS_HIDDEN)
+    {
+      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;
+}
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
 #include "gt-rs6000.h"