OSDN Git Service

PR target/35713
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 2d4f5e8..0105239 100644 (file)
@@ -8,7 +8,7 @@
 
    GCC is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published
-   by the Free Software Foundation; either version 2, or (at your
+   by the Free Software Foundation; either version 3, or (at your
    option) any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -17,9 +17,8 @@
    License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the
-   Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
-   MA 02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -54,6 +53,7 @@
 #include "cfglayout.h"
 #include "sched-int.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
 #include "intl.h"
 #include "params.h"
 #include "tm-constrs.h"
@@ -126,6 +126,10 @@ typedef struct machine_function GTY(())
   /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4
      varargs save area.  */
   HOST_WIDE_INT varargs_save_offset;
+  /* Temporary stack slot to use for SDmode copies.  This slot is
+     64-bits wide and is allocated early enough so that the offset
+     does not overflow the 16-bit load/store offset field.  */
+  rtx sdmode_stack_slot;
 } machine_function;
 
 /* Target cpu type */
@@ -167,7 +171,7 @@ int rs6000_long_double_type_size;
 /* IEEE quad extended precision long double. */
 int rs6000_ieeequad;
 
-/* Whether -mabi=altivec has appeared.  */
+/* Nonzero to use AltiVec ABI.  */
 int rs6000_altivec_abi;
 
 /* Nonzero if we want SPE ABI extensions.  */
@@ -258,12 +262,14 @@ int rs6000_alignment_flags;
 struct {
   bool aix_struct_ret;         /* True if -maix-struct-ret was used.  */
   bool alignment;              /* True if -malign- was used.  */
-  bool abi;                    /* True if -mabi=spe/nospe 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 isel;                   /* True if -misel 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.  */
 } rs6000_explicit_options;
 
 struct builtin_description
@@ -290,6 +296,11 @@ struct processor_costs {
   const int dmul;        /* cost of DFmode multiplication (and fmadd).  */
   const int sdiv;        /* cost of SFmode division (fdivs).  */
   const int ddiv;        /* cost of DFmode division (fdiv).  */
+  const int cache_line_size;    /* cache line size in bytes. */
+  const int l1_cache_size;     /* size of l1 cache, in kilobytes.  */
+  const int l2_cache_size;     /* size of l2 cache, in kilobytes.  */
+  const int simultaneous_prefetches; /* number of parallel prefetch
+                                       operations.  */
 };
 
 const struct processor_costs *rs6000_cost;
@@ -309,6 +320,10 @@ struct processor_costs size32_cost = {
   COSTS_N_INSNS (1),    /* dmul */
   COSTS_N_INSNS (1),    /* sdiv */
   COSTS_N_INSNS (1),    /* ddiv */
+  32,
+  0,
+  0,
+  0,
 };
 
 /* Instruction size costs on 64bit processors.  */
@@ -324,6 +339,10 @@ struct processor_costs size64_cost = {
   COSTS_N_INSNS (1),    /* dmul */
   COSTS_N_INSNS (1),    /* sdiv */
   COSTS_N_INSNS (1),    /* ddiv */
+  128,
+  0,
+  0,
+  0,
 };
 
 /* Instruction costs on RIOS1 processors.  */
@@ -339,6 +358,10 @@ struct processor_costs rios1_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (19),   /* ddiv */
+  128,                 /* cache line size */
+  64,                  /* l1 cache */
+  512,                 /* l2 cache */
+  0,                   /* streams */
 };
 
 /* Instruction costs on RIOS2 processors.  */
@@ -354,6 +377,10 @@ struct processor_costs rios2_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  256,                 /* cache line size */
+  256,                 /* l1 cache */
+  1024,                        /* l2 cache */
+  0,                   /* streams */
 };
 
 /* Instruction costs on RS64A processors.  */
@@ -369,6 +396,10 @@ struct processor_costs rs64a_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (31),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  128,                 /* cache line size */
+  128,                 /* l1 cache */
+  2048,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on MPCCORE processors.  */
@@ -384,6 +415,10 @@ struct processor_costs mpccore_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (10),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  32,                  /* cache line size */
+  4,                   /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC403 processors.  */
@@ -399,6 +434,10 @@ struct processor_costs ppc403_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
+  32,                  /* cache line size */
+  4,                   /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC405 processors.  */
@@ -414,6 +453,10 @@ struct processor_costs ppc405_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
+  32,                  /* cache line size */
+  16,                  /* l1 cache */
+  128,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC440 processors.  */
@@ -429,6 +472,10 @@ struct processor_costs ppc440_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC601 processors.  */
@@ -444,6 +491,10 @@ struct processor_costs ppc601_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC603 processors.  */
@@ -459,6 +510,10 @@ struct processor_costs ppc603_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
+  32,                  /* cache line size */
+  8,                   /* l1 cache */
+  64,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC604 processors.  */
@@ -474,6 +529,10 @@ struct processor_costs ppc604_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  32,                  /* cache line size */
+  16,                  /* l1 cache */
+  512,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC604e processors.  */
@@ -489,6 +548,10 @@ struct processor_costs ppc604e_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC620 processors.  */
@@ -504,6 +567,10 @@ struct processor_costs ppc620_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  128,                 /* cache line size */
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC630 processors.  */
@@ -519,6 +586,10 @@ struct processor_costs ppc630_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (21),   /* ddiv */
+  128,                 /* cache line size */
+  64,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on Cell processor.  */
@@ -535,6 +606,10 @@ struct processor_costs ppccell_cost = {
   COSTS_N_INSNS (10/2),   /* dmul */
   COSTS_N_INSNS (74/2),   /* sdiv */
   COSTS_N_INSNS (74/2),   /* ddiv */
+  128,                 /* cache line size */
+  32,                  /* l1 cache */
+  512,                 /* l2 cache */
+  6,                   /* streams */
 };
 
 /* Instruction costs on PPC750 and PPC7400 processors.  */
@@ -550,6 +625,10 @@ struct processor_costs ppc750_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  512,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC7450 processors.  */
@@ -565,6 +644,10 @@ struct processor_costs ppc7450_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (21),   /* sdiv */
   COSTS_N_INSNS (35),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC8540 processors.  */
@@ -580,6 +663,29 @@ struct processor_costs ppc8540_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (29),   /* sdiv */
   COSTS_N_INSNS (29),   /* ddiv */
+  32,                  /* cache line size */
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* prefetch streams /*/
+};
+
+/* Instruction costs on E300C2 and E300C3 cores.  */
+static const
+struct processor_costs ppce300c2c3_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (19),   /* divsi */
+  COSTS_N_INSNS (19),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (4),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (33),   /* ddiv */
+  32,
+  16,                  /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* prefetch streams /*/
 };
 
 /* Instruction costs on POWER4 and POWER5 processors.  */
@@ -595,6 +701,10 @@ struct processor_costs power4_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  128,                 /* cache line size */
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  8,                   /* prefetch streams /*/
 };
 
 /* Instruction costs on POWER6 processors.  */
@@ -610,15 +720,18 @@ struct processor_costs power6_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (13),   /* sdiv */
   COSTS_N_INSNS (16),   /* ddiv */
+  128,                 /* cache line size */
+  64,                  /* l1 cache */
+  2048,                        /* l2 cache */
+  16,                  /* prefetch streams */
 };
 
 \f
 static bool rs6000_function_ok_for_sibcall (tree, tree);
-static const char *rs6000_invalid_within_doloop (rtx);
+static const char *rs6000_invalid_within_doloop (const_rtx);
 static rtx rs6000_generate_compare (enum rtx_code);
 static void rs6000_emit_stack_tie (void);
 static void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
-static rtx spe_synthesize_frame_save (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);
@@ -640,10 +753,10 @@ static void rs6000_assemble_visibility (tree, int);
 static int rs6000_ra_ever_killed (void);
 static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
 static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
-static bool rs6000_ms_bitfield_layout_p (tree);
+static bool rs6000_ms_bitfield_layout_p (const_tree);
 static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
 static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
-static const char *rs6000_mangle_fundamental_type (tree);
+static const char *rs6000_mangle_type (const_tree);
 extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes (tree);
 static bool rs6000_reg_live_or_pic_offset_p (int);
@@ -652,7 +765,7 @@ static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
                                    tree);
 static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
-static bool rs6000_return_in_memory (tree, tree);
+static bool rs6000_return_in_memory (const_tree, const_tree);
 static void rs6000_file_start (void);
 #if TARGET_ELF
 static int rs6000_elf_reloc_rw_mask (void);
@@ -665,7 +778,9 @@ static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
 static void rs6000_elf_encode_section_info (tree, rtx, int)
      ATTRIBUTE_UNUSED;
 #endif
-static bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx);
+static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx);
+static void rs6000_alloc_sdmode_stack_slot (void);
+static void rs6000_instantiate_decls (void);
 #if TARGET_XCOFF
 static void rs6000_xcoff_asm_output_anchor (rtx);
 static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
@@ -711,13 +826,14 @@ static int rs6000_sched_reorder (FILE *, int, rtx *, int *, int);
 static int rs6000_sched_reorder2 (FILE *, int, rtx *, int *, int);
 static int rs6000_use_sched_lookahead (void);
 static int rs6000_use_sched_lookahead_guard (rtx);
+static tree rs6000_builtin_reciprocal (unsigned int, bool, bool);
 static tree rs6000_builtin_mask_for_load (void);
 static tree rs6000_builtin_mul_widen_even (tree);
 static tree rs6000_builtin_mul_widen_odd (tree);
 static tree rs6000_builtin_conversion (enum tree_code, tree);
 
 static void def_builtin (int, const char *, tree, int);
-static bool rs6000_vector_alignment_reachable (tree, bool);
+static bool rs6000_vector_alignment_reachable (const_tree, bool);
 static void rs6000_init_builtins (void);
 static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
@@ -727,6 +843,12 @@ static void altivec_init_builtins (void);
 static void rs6000_common_init_builtins (void);
 static void rs6000_init_libfuncs (void);
 
+static void paired_init_builtins (void);
+static rtx paired_expand_builtin (tree, rtx, bool *);
+static rtx paired_expand_lv_builtin (enum insn_code, tree, rtx);
+static rtx paired_expand_stv_builtin (enum insn_code, tree);
+static rtx paired_expand_predicate_builtin (enum insn_code, tree, rtx);
+
 static void enable_mask_for_builtins (struct builtin_description *, int,
                                      enum rs6000_builtins,
                                      enum rs6000_builtins);
@@ -762,7 +884,7 @@ static void compute_save_world_info (rs6000_stack_t *info_ptr);
 static void is_altivec_return_reg (rtx, void *);
 static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
 int easy_vector_constant (rtx, enum machine_mode);
-static bool rs6000_is_opaque_type (tree);
+static bool rs6000_is_opaque_type (const_tree);
 static rtx rs6000_dwarf_register_span (rtx);
 static void rs6000_init_dwarf_reg_sizes_extra (tree);
 static rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
@@ -783,19 +905,19 @@ static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
                                              HOST_WIDE_INT,
                                              rtx[], int *);
 static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
-                                              tree, HOST_WIDE_INT,
-                                              rtx[], int *);
-static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool);
+                                               const_tree, HOST_WIDE_INT,
+                                               rtx[], int *);
+static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, int, bool);
 static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
 static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
 static void setup_incoming_varargs (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree,
                                    int *, int);
 static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
-                                     tree, bool);
+                                     const_tree, bool);
 static int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                     tree, bool);
-static const char *invalid_arg_for_unprototyped_fn (tree, tree, tree);
+static const char *invalid_arg_for_unprototyped_fn (const_tree, const_tree, const_tree);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
 static int no_previous_def (tree function_name);
@@ -804,8 +926,9 @@ static void rs6000_darwin_file_start (void);
 #endif
 
 static tree rs6000_build_builtin_va_list (void);
+static void rs6000_va_start (tree, rtx);
 static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
-static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
+static bool rs6000_must_pass_in_stack (enum machine_mode, const_tree);
 static bool rs6000_scalar_mode_supported_p (enum machine_mode);
 static bool rs6000_vector_mode_supported_p (enum machine_mode);
 static int get_vec_cmp_insn (enum rtx_code, enum machine_mode,
@@ -994,8 +1117,8 @@ static const char alt_reg_names[][8] =
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
 
-#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
-#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE rs6000_mangle_type
 
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
@@ -1012,7 +1135,7 @@ static const char alt_reg_names[][8] =
 #define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
 
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
@@ -1037,9 +1160,9 @@ static const char alt_reg_names[][8] =
 /* On rs6000, function arguments are promoted, as are function return
    values.  */
 #undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
 #undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
 
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
@@ -1053,7 +1176,7 @@ static const char alt_reg_names[][8] =
 #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
 #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
 #undef TARGET_SPLIT_COMPLEX_ARG
-#define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
+#define TARGET_SPLIT_COMPLEX_ARG hook_bool_const_tree_true
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
 #undef TARGET_PASS_BY_REFERENCE
@@ -1064,6 +1187,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
 
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START rs6000_va_start
+
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
 
@@ -1119,6 +1245,15 @@ static const char alt_reg_names[][8] =
 #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
 #define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
 
+#undef TARGET_BUILTIN_RECIPROCAL
+#define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal
+
+#undef TARGET_EXPAND_TO_RTL_HOOK
+#define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot
+
+#undef TARGET_INSTANTIATE_DECLS
+#define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -1136,12 +1271,13 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
      This excludes the 32-bit decimal float mode for now.  */
   if (FP_REGNO_P (regno))
     return
-      (SCALAR_FLOAT_MODE_P (mode)
+      ((SCALAR_FLOAT_MODE_P (mode)
        && (mode != TDmode || (regno % 2) == 0)
-       && mode != SDmode
        && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
       || (GET_MODE_CLASS (mode) == MODE_INT
-         && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
+         && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD)
+      || (PAIRED_SIMD_REGNO_P (regno) && TARGET_PAIRED_FLOAT
+           && PAIRED_VECTOR_MODE (mode)));
 
   /* The CR register can only hold CC modes.  */
   if (CR_REGNO_P (regno))
@@ -1302,6 +1438,8 @@ rs6000_override_options (const char *default_cpu)
         {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         /* 8548 has a dummy entry for now.  */
         {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
+        {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK},
         {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
          POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
@@ -1408,6 +1546,14 @@ rs6000_override_options (const char *default_cpu)
   if (TARGET_E500)
     rs6000_isel = 1;
 
+  if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3)
+    {
+      if (TARGET_ALTIVEC)
+       error ("AltiVec not supported in this target");
+      if (TARGET_SPE)
+       error ("Spe not supported in this target");
+    }
+
   /* If we are optimizing big endian systems for space, use the load/store
      multiple and string instructions.  */
   if (BYTES_BIG_ENDIAN && optimize_size)
@@ -1470,11 +1616,22 @@ rs6000_override_options (const char *default_cpu)
     rs6000_ieeequad = 1;
 #endif
 
-  /* Set Altivec ABI as default for powerpc64 linux.  */
-  if (TARGET_ELF && TARGET_64BIT)
+  /* Enable Altivec ABI for AIX -maltivec.  */
+  if (TARGET_XCOFF && TARGET_ALTIVEC)
+    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)
     {
-      rs6000_altivec_abi = 1;
-      TARGET_ALTIVEC_VRSAVE = 1;
+      if (!rs6000_explicit_options.altivec_abi
+         && (TARGET_64BIT || TARGET_ALTIVEC))
+       rs6000_altivec_abi = 1;
+
+      /* Enable VRSAVE for AltiVec ABI, unless explicitly overridden.  */
+      if (!rs6000_explicit_options.vrsave)
+       TARGET_ALTIVEC_VRSAVE = rs6000_altivec_abi;
     }
 
   /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
@@ -1518,7 +1675,7 @@ rs6000_override_options (const char *default_cpu)
       /* 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.abi)
+      if (!rs6000_explicit_options.spe_abi)
        rs6000_spe_abi = 0;
       if (!rs6000_explicit_options.spe)
        rs6000_spe = 0;
@@ -1716,6 +1873,11 @@ rs6000_override_options (const char *default_cpu)
        rs6000_cost = &ppc8540_cost;
        break;
 
+      case PROCESSOR_PPCE300C2:
+      case PROCESSOR_PPCE300C3:
+       rs6000_cost = &ppce300c2c3_cost;
+       break;
+
       case PROCESSOR_POWER4:
       case PROCESSOR_POWER5:
        rs6000_cost = &power4_cost;
@@ -1728,6 +1890,21 @@ rs6000_override_options (const char *default_cpu)
       default:
        gcc_unreachable ();
       }
+
+  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
+    set_param_value ("simultaneous-prefetches",
+                    rs6000_cost->simultaneous_prefetches);
+  if (!PARAM_SET_P (PARAM_L1_CACHE_SIZE))
+    set_param_value ("l1-cache-size", rs6000_cost->l1_cache_size);
+  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
+    set_param_value ("l1-cache-line-size", rs6000_cost->cache_line_size);
+  if (!PARAM_SET_P (PARAM_L2_CACHE_SIZE))
+    set_param_value ("l2-cache-size", rs6000_cost->l2_cache_size);
+
+  /* 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;
 }
 
 /* Implement targetm.vectorize.builtin_mask_for_load.  */
@@ -1816,7 +1993,7 @@ rs6000_builtin_mul_widen_odd (tree type)
    how may iterations are required to reach desired alignment.  */
 
 static bool
-rs6000_vector_alignment_reachable (tree type ATTRIBUTE_UNUSED, bool is_packed)
+rs6000_vector_alignment_reachable (const_tree type ATTRIBUTE_UNUSED, bool is_packed)
 {
   if (is_packed)
     return false;
@@ -1996,6 +2173,7 @@ rs6000_handle_option (size_t code, const char *arg, int value)
       break;
 
     case OPT_mvrsave_:
+      rs6000_explicit_options.vrsave = true;
       rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
       break;
 
@@ -2053,19 +2231,20 @@ rs6000_handle_option (size_t code, const char *arg, int value)
     case OPT_mabi_:
       if (!strcmp (arg, "altivec"))
        {
-         rs6000_explicit_options.abi = true;
+         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"))
        {
-         /* ??? Don't set rs6000_explicit_options.abi here, to allow
-            the default for rs6000_spe_abi to be chosen later.  */
+         rs6000_explicit_options.altivec_abi = true;
          rs6000_altivec_abi = 0;
        }
       else if (! strcmp (arg, "spe"))
        {
-         rs6000_explicit_options.abi = true;
+         rs6000_explicit_options.spe_abi = true;
          rs6000_spe_abi = 1;
          rs6000_altivec_abi = 0;
          if (!TARGET_SPE_ABI)
@@ -2073,7 +2252,7 @@ rs6000_handle_option (size_t code, const char *arg, int value)
        }
       else if (! strcmp (arg, "no-spe"))
        {
-         rs6000_explicit_options.abi = true;
+         rs6000_explicit_options.spe_abi = true;
          rs6000_spe_abi = 0;
        }
 
@@ -2242,8 +2421,14 @@ rs6000_file_start (void)
 
 #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) ? 1 : 2);
+    {
+      fprintf (file, "\t.gnu_attribute 4, %d\n",
+              (TARGET_HARD_FLOAT && TARGET_FPRS) ? 1 : 2);
+      fprintf (file, "\t.gnu_attribute 8, %d\n",
+              (TARGET_ALTIVEC_ABI ? 2
+               : TARGET_SPE_ABI ? 3
+               : 1));
+    }
 #endif
 
   if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
@@ -2331,13 +2516,16 @@ num_insns_constant (rtx op, enum machine_mode mode)
        return num_insns_constant_wide (INTVAL (op));
 
       case CONST_DOUBLE:
-       if (mode == SFmode)
+       if (mode == SFmode || mode == SDmode)
          {
            long l;
            REAL_VALUE_TYPE rv;
 
            REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-           REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+           if (DECIMAL_FLOAT_MODE_P (mode))
+             REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
+           else
+             REAL_VALUE_TO_TARGET_SINGLE (rv, l);
            return num_insns_constant_wide ((HOST_WIDE_INT) l);
          }
 
@@ -2600,6 +2788,156 @@ output_vec_const_move (rtx *operands)
     return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
 }
 
+/* Initialize TARGET of vector PAIRED to VALS.  */
+
+void
+paired_expand_vector_init (rtx target, rtx vals)
+{
+  enum machine_mode mode = GET_MODE (target);
+  int n_elts = GET_MODE_NUNITS (mode);
+  int n_var = 0;
+  rtx x, new, tmp, constant_op, op1, op2;
+  int i;
+
+  for (i = 0; i < n_elts; ++i)
+    {
+      x = XVECEXP (vals, 0, i);
+      if (!CONSTANT_P (x))
+       ++n_var;
+    }
+  if (n_var == 0)
+    {
+      /* Load from constant pool.  */
+      emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+      return;
+    }
+
+  if (n_var == 2)
+    {
+      /* The vector is initialized only with non-constants.  */
+      new = gen_rtx_VEC_CONCAT (V2SFmode, XVECEXP (vals, 0, 0),
+                               XVECEXP (vals, 0, 1));
+
+      emit_move_insn (target, new);
+      return;
+    }
+  
+  /* One field is non-constant and the other one is a constant.  Load the
+     constant from the constant pool and use ps_merge instruction to
+     construct the whole vector.  */
+  op1 = XVECEXP (vals, 0, 0);
+  op2 = XVECEXP (vals, 0, 1);
+
+  constant_op = (CONSTANT_P (op1)) ? op1 : op2;
+
+  tmp = gen_reg_rtx (GET_MODE (constant_op));
+  emit_move_insn (tmp, constant_op);
+
+  if (CONSTANT_P (op1))
+    new = gen_rtx_VEC_CONCAT (V2SFmode, tmp, op2);
+  else
+    new = gen_rtx_VEC_CONCAT (V2SFmode, op1, tmp);
+
+  emit_move_insn (target, new);
+}
+
+void
+paired_expand_vector_move (rtx operands[])
+{
+  rtx op0 = operands[0], op1 = operands[1];
+
+  emit_move_insn (op0, op1);
+}
+
+/* Emit vector compare for code RCODE.  DEST is destination, OP1 and
+   OP2 are two VEC_COND_EXPR operands, CC_OP0 and CC_OP1 are the two
+   operands for the relation operation COND.  This is a recursive
+   function.  */
+
+static void
+paired_emit_vector_compare (enum rtx_code rcode,
+                            rtx dest, rtx op0, rtx op1,
+                            rtx cc_op0, rtx cc_op1)
+{
+  rtx tmp = gen_reg_rtx (V2SFmode);
+  rtx tmp1, max, min, equal_zero;
+
+  gcc_assert (TARGET_PAIRED_FLOAT);
+  gcc_assert (GET_MODE (op0) == GET_MODE (op1));
+
+  switch (rcode)
+    {
+    case LT:
+    case LTU:
+      paired_emit_vector_compare (GE, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case GE:
+    case GEU:
+      emit_insn (gen_subv2sf3 (tmp, cc_op0, cc_op1));
+      emit_insn (gen_selv2sf4 (dest, tmp, op0, op1, CONST0_RTX (SFmode)));
+      return;
+    case LE:
+    case LEU:
+      paired_emit_vector_compare (GE, dest, op0, op1, cc_op1, cc_op0);
+      return;
+    case GT:
+      paired_emit_vector_compare (LE, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case EQ:
+      tmp1 = gen_reg_rtx (V2SFmode);
+      max = gen_reg_rtx (V2SFmode);
+      min = gen_reg_rtx (V2SFmode);
+      equal_zero = gen_reg_rtx (V2SFmode);
+
+      emit_insn (gen_subv2sf3 (tmp, cc_op0, cc_op1));
+      emit_insn (gen_selv2sf4
+                 (max, tmp, cc_op0, cc_op1, CONST0_RTX (SFmode)));
+      emit_insn (gen_subv2sf3 (tmp, cc_op1, cc_op0));
+      emit_insn (gen_selv2sf4
+                 (min, tmp, cc_op0, cc_op1, CONST0_RTX (SFmode)));
+      emit_insn (gen_subv2sf3 (tmp1, min, max));
+      emit_insn (gen_selv2sf4 (dest, tmp1, op0, op1, CONST0_RTX (SFmode)));
+      return;
+    case NE:
+      paired_emit_vector_compare (EQ, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case UNLE:
+      paired_emit_vector_compare (LE, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case UNLT:
+      paired_emit_vector_compare (LT, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case UNGE:
+      paired_emit_vector_compare (GE, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    case UNGT:
+      paired_emit_vector_compare (GT, dest, op1, op0, cc_op0, cc_op1);
+      return;
+    default:
+      gcc_unreachable ();
+    }
+
+  return;
+}
+
+/* Emit vector conditional expression.
+   DEST is destination. OP1 and OP2 are two VEC_COND_EXPR operands.
+   CC_OP0 and CC_OP1 are the two operands for the relation operation COND.  */
+
+int
+paired_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2,
+                             rtx cond, rtx cc_op0, rtx cc_op1)
+{
+  enum rtx_code rcode = GET_CODE (cond);
+
+  if (!TARGET_PAIRED_FLOAT)
+    return 0;
+
+  paired_emit_vector_compare (rcode, dest, op1, op2, cc_op0, cc_op1);
+
+  return 1;
+}
+
 /* Initialize vector TARGET to VALS.  */
 
 void
@@ -2627,6 +2965,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
 
   if (n_var == 0)
     {
+      rtx const_vec = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
       if (mode != V4SFmode && all_const_zero)
        {
          /* Zero register.  */
@@ -2634,10 +2973,10 @@ rs6000_expand_vector_init (rtx target, rtx vals)
                                  gen_rtx_XOR (mode, target, target)));
          return;
        }
-      else if (mode != V4SFmode && easy_vector_constant (vals, mode))
+      else if (mode != V4SFmode && easy_vector_constant (const_vec, mode))
        {
          /* Splat immediate.  */
-         emit_insn (gen_rtx_SET (VOIDmode, target, vals));
+         emit_insn (gen_rtx_SET (VOIDmode, target, const_vec));
          return;
        }
       else if (all_same)
@@ -2645,7 +2984,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
       else
        {
          /* Load from constant pool.  */
-         emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+         emit_move_insn (target, const_vec);
          return;
        }
     }
@@ -2845,13 +3184,16 @@ invalid_e500_subreg (rtx op, enum machine_mode mode)
          && (mode == SImode || mode == DImode || mode == TImode)
          && REG_P (SUBREG_REG (op))
          && (GET_MODE (SUBREG_REG (op)) == DFmode
-             || GET_MODE (SUBREG_REG (op)) == TFmode))
+             || GET_MODE (SUBREG_REG (op)) == TFmode
+             || GET_MODE (SUBREG_REG (op)) == DDmode
+             || GET_MODE (SUBREG_REG (op)) == TDmode))
        return true;
 
       /* Reject (subreg:DF (reg:DI)); likewise with subreg:TF and
         reg:TI.  */
       if (GET_CODE (op) == SUBREG
-         && (mode == DFmode || mode == TFmode)
+         && (mode == DFmode || mode == TFmode
+             || mode == DDmode || mode == TDmode)
          && REG_P (SUBREG_REG (op))
          && (GET_MODE (SUBREG_REG (op)) == DImode
              || GET_MODE (SUBREG_REG (op)) == TImode))
@@ -2941,6 +3283,13 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
   if (DEFAULT_ABI != ABI_V4)
     return 0;
 
+  /* Vector and float memory instructions have a limited offset on the
+     SPE, so using a vector or float variable directly as an operand is
+     not useful.  */
+  if (TARGET_SPE
+      && (SPE_VECTOR_MODE (mode) || FLOAT_MODE_P (mode)))
+    return 0;
+
   if (GET_CODE (op) == SYMBOL_REF)
     sym_ref = op;
 
@@ -3083,14 +3432,17 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     case V4SFmode:
     case V4SImode:
       /* AltiVec vector modes.  Only reg+reg addressing is valid and
-        constant offset zero should not occur due to canonicalization.
-        Allow any offset when not strict before reload.  */
-      return !strict;
+        constant offset zero should not occur due to canonicalization.  */
+      return false;
 
     case V4HImode:
     case V2SImode:
     case V1DImode:
     case V2SFmode:
+       /* Paired vector modes.  Only reg+reg addressing is valid and
+         constant offset zero should not occur due to canonicalization.  */
+      if (TARGET_PAIRED_FLOAT)
+        return false;
       /* SPE vector modes.  */
       return SPE_CONST_OFFSET_OK (offset);
 
@@ -3115,12 +3467,12 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       break;
 
     case TFmode:
+    case TDmode:
       if (TARGET_E500_DOUBLE)
        return (SPE_CONST_OFFSET_OK (offset)
                && SPE_CONST_OFFSET_OK (offset + 8));
 
     case TImode:
-    case TDmode:
       if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
        extra = 12;
       else if (offset & 3)
@@ -3199,6 +3551,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   /* Restrict addressing for DI because of our SUBREG hackery.  */
   if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                            || mode == DDmode || mode == TDmode
                             || mode == DImode))
     return false;
   x = XEXP (x, 1);
@@ -3213,7 +3566,8 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_BITSIZE (mode) > 64
          || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
-             && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode)))
+             && !(TARGET_HARD_FLOAT && TARGET_FPRS
+                  && (mode == DFmode || mode == DDmode))))
        return false;
 
       return CONSTANT_P (x);
@@ -3260,7 +3614,11 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000)
+      && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000
+      && !(SPE_VECTOR_MODE (mode)
+          || ALTIVEC_VECTOR_MODE (mode)
+          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                     || mode == DImode))))
     {
       HOST_WIDE_INT high_int, low_int;
       rtx sum;
@@ -3276,11 +3634,12 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_MODE_NUNITS (mode) == 1
           && ((TARGET_HARD_FLOAT && TARGET_FPRS)
               || TARGET_POWERPC64
-              || (((mode != DImode && mode != DFmode && mode != DDmode)
-                   || TARGET_E500_DOUBLE)
-                  && mode != TFmode && mode != TDmode))
+              || ((mode != DImode && mode != DFmode && mode != DDmode)
+                  || TARGET_E500_DOUBLE))
           && (TARGET_POWERPC64 || mode != DImode)
-          && mode != TImode)
+          && mode != TImode
+          && mode != TFmode
+          && mode != TDmode)
     {
       return gen_rtx_PLUS (Pmode, XEXP (x, 0),
                           force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
@@ -3307,19 +3666,29 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       /* We accept [reg + reg] and [reg + OFFSET].  */
 
       if (GET_CODE (x) == PLUS)
-       {
-         rtx op1 = XEXP (x, 0);
-         rtx op2 = XEXP (x, 1);
+       {
+         rtx op1 = XEXP (x, 0);
+         rtx op2 = XEXP (x, 1);
+         rtx y;
 
-         op1 = force_reg (Pmode, op1);
+         op1 = force_reg (Pmode, op1);
 
-         if (GET_CODE (op2) != REG
-             && (GET_CODE (op2) != CONST_INT
-                 || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
-           op2 = force_reg (Pmode, op2);
+         if (GET_CODE (op2) != REG
+             && (GET_CODE (op2) != CONST_INT
+                 || !SPE_CONST_OFFSET_OK (INTVAL (op2))
+                 || (GET_MODE_SIZE (mode) > 8
+                     && !SPE_CONST_OFFSET_OK (INTVAL (op2) + 8))))
+           op2 = force_reg (Pmode, op2);
 
-         return gen_rtx_PLUS (Pmode, op1, op2);
-       }
+         /* We can't always do [reg + reg] for these, because [reg +
+            reg + offset] is not a legitimate addressing mode.  */
+         y = gen_rtx_PLUS (Pmode, op1, op2);
+
+         if (GET_MODE_SIZE (mode) > 8 && REG_P (op2))
+           return force_reg (Pmode, y);
+         else
+           return y;
+       }
 
       return force_reg (Pmode, x);
     }
@@ -3332,7 +3701,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && CONSTANT_P (x)
           && GET_MODE_NUNITS (mode) == 1
           && (GET_MODE_BITSIZE (mode) <= 32
-              || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
+              || ((TARGET_HARD_FLOAT && TARGET_FPRS)
+                  && (mode == DFmode || mode == DDmode))))
     {
       rtx reg = gen_reg_rtx (Pmode);
       emit_insn (gen_elf_high (reg, x));
@@ -3346,7 +3716,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE
           && CONSTANT_P (x)
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS) || mode != DFmode)
+          && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+              || (mode != DFmode && mode != DDmode))
           && mode != DImode
           && mode != TImode)
     {
@@ -3702,6 +4073,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && !SPE_VECTOR_MODE (mode)
       && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                 || mode == DDmode || mode == TDmode
                                  || mode == DImode))
       && !ALTIVEC_VECTOR_MODE (mode))
     {
@@ -3743,12 +4115,12 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && !flag_pic
 #endif
       /* Don't do this for TFmode or TDmode, since the result isn't offsettable.
-        The same goes for DImode without 64-bit gprs and DFmode
+        The same goes for DImode without 64-bit gprs and DFmode and DDmode
         without fprs.  */
       && mode != TFmode
       && mode != TDmode
       && (mode != DImode || TARGET_POWERPC64)
-      && (mode != DFmode || TARGET_POWERPC64
+      && ((mode != DFmode && mode != DDmode) || TARGET_POWERPC64
          || (TARGET_FPRS && TARGET_HARD_FLOAT)))
     {
 #if TARGET_MACHO
@@ -3811,11 +4183,11 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
    refers to a constant pool entry of an address (or the sum of it
    plus a constant), a short (16-bit signed) constant plus a register,
    the sum of two registers, or a register indirect, possibly with an
-   auto-increment.  For DFmode and DImode with a constant plus register,
-   we must ensure that both words are addressable or PowerPC64 with offset
-   word aligned.
+   auto-increment.  For DFmode, DDmode and DImode with a constant plus
+   register, we must ensure that both words are addressable or PowerPC64
+   with offset word aligned.
 
-   For modes spanning multiple registers (DFmode in 32-bit GPRs,
+   For modes spanning multiple registers (DFmode and DDmode in 32-bit GPRs,
    32-bit DImode, TImode, TFmode, TDmode), indexed addressing cannot be used
    because adjacent memory cells are accessed by adding word-sized offsets
    during assembly output.  */
@@ -3840,8 +4212,8 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && mode != TFmode
       && mode != TDmode
       /* Restrict addressing for DI because of our SUBREG hackery.  */
-      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                                 || mode == DImode))
+      && !(TARGET_E500_DOUBLE
+          && (mode == DFmode || mode == DDmode || mode == DImode))
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
@@ -3864,7 +4236,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && mode != TDmode
       && ((TARGET_HARD_FLOAT && TARGET_FPRS)
          || TARGET_POWERPC64
-         || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
+         || ((mode != DFmode && mode != DDmode) || TARGET_E500_DOUBLE))
       && (TARGET_POWERPC64 || mode != DImode)
       && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
@@ -3874,12 +4246,13 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && mode != TDmode
       && ((TARGET_HARD_FLOAT && TARGET_FPRS)
          || TARGET_POWERPC64
-         || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
+         || ((mode != DFmode && mode != DDmode) || TARGET_E500_DOUBLE))
       && (TARGET_POWERPC64 || mode != DImode)
       && !ALTIVEC_VECTOR_MODE (mode)
       && !SPE_VECTOR_MODE (mode)
       /* Restrict addressing for DI because of our SUBREG hackery.  */
-      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
+      && !(TARGET_E500_DOUBLE
+          && (mode == DFmode || mode == DDmode || mode == DImode))
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
       && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), reg_ok_strict)
@@ -4043,9 +4416,6 @@ rs6000_conditional_register_usage (void)
     fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
       = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
 
-  if (TARGET_ALTIVEC)
-    global_regs[VSCR_REGNO] = 1;
-
   if (TARGET_SPE)
     {
       global_regs[SPEFSCR_REGNO] = 1;
@@ -4060,16 +4430,26 @@ rs6000_conditional_register_usage (void)
        = call_really_used_regs[14] = 1;
     }
 
-  if (! TARGET_ALTIVEC)
+  if (!TARGET_ALTIVEC)
     {
       for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
        fixed_regs[i] = call_used_regs[i] = call_really_used_regs[i] = 1;
       call_really_used_regs[VRSAVE_REGNO] = 1;
     }
 
+  if (TARGET_ALTIVEC)
+    global_regs[VSCR_REGNO] = 1;
+
   if (TARGET_ALTIVEC_ABI)
-    for (i = FIRST_ALTIVEC_REGNO; i < FIRST_ALTIVEC_REGNO + 20; ++i)
-      call_used_regs[i] = call_really_used_regs[i] = 1;
+    {
+      for (i = FIRST_ALTIVEC_REGNO; i < FIRST_ALTIVEC_REGNO + 20; ++i)
+       call_used_regs[i] = call_really_used_regs[i] = 1;
+
+      /* AIX reserves VR20:31 in non-extended ABI mode.  */
+      if (TARGET_XCOFF)
+       for (i = FIRST_ALTIVEC_REGNO + 20; i < FIRST_ALTIVEC_REGNO + 32; ++i)
+         fixed_regs[i] = call_used_regs[i] = call_really_used_regs[i] = 1;
+    }
 }
 \f
 /* Try to output insns to set TARGET equal to the constant C if it can
@@ -4396,6 +4776,55 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       return;
     }
 
+  if (reload_in_progress && cfun->machine->sdmode_stack_slot != NULL_RTX)
+    cfun->machine->sdmode_stack_slot =
+      eliminate_regs (cfun->machine->sdmode_stack_slot, VOIDmode, NULL_RTX);
+
+  if (reload_in_progress
+      && mode == SDmode
+      && MEM_P (operands[0])
+      && rtx_equal_p (operands[0], cfun->machine->sdmode_stack_slot)
+      && REG_P (operands[1]))
+    {
+      if (FP_REGNO_P (REGNO (operands[1])))
+       {
+         rtx mem = adjust_address_nv (operands[0], DDmode, 0);
+         mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+         emit_insn (gen_movsd_store (mem, operands[1]));
+       }
+      else if (INT_REGNO_P (REGNO (operands[1])))
+       {
+         rtx mem = adjust_address_nv (operands[0], mode, 4);
+         mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+         emit_insn (gen_movsd_hardfloat (mem, operands[1]));
+       }
+      else
+       gcc_unreachable();
+      return;
+    }
+  if (reload_in_progress
+      && mode == SDmode
+      && REG_P (operands[0])
+      && MEM_P (operands[1])
+      && rtx_equal_p (operands[1], cfun->machine->sdmode_stack_slot))
+    {
+      if (FP_REGNO_P (REGNO (operands[0])))
+       {
+         rtx mem = adjust_address_nv (operands[1], DDmode, 0);
+         mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+         emit_insn (gen_movsd_load (operands[0], mem));
+       }
+      else if (INT_REGNO_P (REGNO (operands[0])))
+       {
+         rtx mem = adjust_address_nv (operands[1], mode, 4);
+         mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+         emit_insn (gen_movsd_hardfloat (operands[0], mem));
+       }
+      else
+       gcc_unreachable();
+      return;
+    }
+
   /* FIXME:  In the long term, this switch statement should go away
      and be replaced by a sequence of tests based on things like
      mode == Pmode.  */
@@ -4416,6 +4845,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
     case DFmode:
     case DDmode:
     case SFmode:
+    case SDmode:
       if (CONSTANT_P (operands[1])
          && ! easy_fp_constant (operands[1], mode))
        operands[1] = force_const_mem (mode, operands[1]);
@@ -4628,7 +5058,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
   (SCALAR_FLOAT_MODE_P (MODE)                  \
-   && (MODE) != SDmode                         \
    && (CUM)->fregno <= FP_ARG_MAX_REG          \
    && TARGET_HARD_FLOAT && TARGET_FPRS)
 
@@ -4661,7 +5090,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
    memory always.  The cast to unsigned makes -1 > 8.  */
 
 static bool
-rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+rs6000_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   /* In the darwin64 abi, try to use registers for larger structs
      if possible.  */
@@ -4783,7 +5212,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
 /* Return true if TYPE must be passed on the stack and not in registers.  */
 
 static bool
-rs6000_must_pass_in_stack (enum machine_mode mode, tree type)
+rs6000_must_pass_in_stack (enum machine_mode mode, const_tree type)
 {
   if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
     return must_pass_in_stack_var_size (mode, type);
@@ -4801,7 +5230,7 @@ rs6000_must_pass_in_stack (enum machine_mode mode, tree type)
    argument slot.  */
 
 enum direction
-function_arg_padding (enum machine_mode mode, tree type)
+function_arg_padding (enum machine_mode mode, const_tree type)
 {
 #ifndef AGGREGATE_PADDING_FIXED
 #define AGGREGATE_PADDING_FIXED 0
@@ -5108,7 +5537,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode
-             || mode == DDmode || mode == TDmode
+             || mode == SDmode || mode == DDmode || mode == TDmode
              || (mode == TFmode && !TARGET_IEEEQUAD)))
        {
          /* _Decimal128 must use an even/odd register pair.  This assumes
@@ -5122,7 +5551,8 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          else
            {
              cum->fregno = FP_ARG_V4_MAX_REG + 1;
-             if (mode == DFmode || mode == TFmode || mode == DDmode || mode == TDmode)
+             if (mode == DFmode || mode == TFmode
+                 || mode == DDmode || mode == TDmode)
                cum->words += cum->words & 1;
              cum->words += rs6000_arg_size (mode, type);
            }
@@ -5174,7 +5604,6 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       cum->words = align_words + n_words;
 
       if (SCALAR_FLOAT_MODE_P (mode)
-         && mode != SDmode
          && TARGET_HARD_FLOAT && TARGET_FPRS)
        {
          /* _Decimal128 must be passed in an even/odd float register pair.
@@ -5205,12 +5634,14 @@ spe_build_register_parallel (enum machine_mode mode, int gregno)
   switch (mode)
     {
     case DFmode:
+    case DDmode:
       r1 = gen_rtx_REG (DImode, gregno);
       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
       return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
 
     case DCmode:
     case TFmode:
+    case TDmode:
       r1 = gen_rtx_REG (DImode, gregno);
       r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
       r3 = gen_rtx_REG (DImode, gregno + 2);
@@ -5242,13 +5673,14 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   /* On E500 v2, double arithmetic is done on the full 64-bit GPR, but
      are passed and returned in a pair of GPRs for ABI compatibility.  */
-  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode
-                            || mode == TFmode || mode == TCmode))
+  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                            || mode == DDmode || mode == TDmode
+                            || mode == DCmode || mode == TCmode))
     {
       int n_words = rs6000_arg_size (mode, type);
 
       /* Doubles go in an odd/even register pair (r5/r6, etc).  */
-      if (mode == DFmode)
+      if (mode == DFmode || mode == DDmode)
        gregno += (1 - gregno) & 1;
 
       /* Multi-reg args are not split between registers and stack.  */
@@ -5360,7 +5792,7 @@ rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum,
 /* Recursive workhorse for the following.  */
 
 static void
-rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
+rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, const_tree type,
                                    HOST_WIDE_INT startbitpos, rtx rvec[],
                                    int *k)
 {
@@ -5430,7 +5862,7 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
    calling convention.  */
 
 static rtx
-rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
+rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, const_tree type,
                            int named, bool retval)
 {
   rtx rvec[FIRST_PSEUDO_REGISTER];
@@ -5673,7 +6105,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode
              || (mode == TFmode && !TARGET_IEEEQUAD)
-             || mode == DDmode || mode == TDmode))
+             || mode == SDmode || mode == DDmode || mode == TDmode))
        {
          /* _Decimal128 must use an even/odd register pair.  This assumes
             that the register number is odd when fregno is odd.  */
@@ -5888,7 +6320,7 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static bool
 rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
-                         enum machine_mode mode, tree type,
+                         enum machine_mode mode, const_tree type,
                          bool named ATTRIBUTE_UNUSED)
 {
   if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && mode == TFmode)
@@ -5994,7 +6426,8 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   CUMULATIVE_ARGS next_cum;
   int reg_size = TARGET_32BIT ? 4 : 8;
   rtx save_area = NULL_RTX, mem;
-  int first_reg_offset, set;
+  int first_reg_offset;
+  alias_set_type set;
 
   /* Skip the last named argument.  */
   next_cum = *cum;
@@ -6196,7 +6629,7 @@ rs6000_build_builtin_va_list (void)
 
 /* Implement va_start.  */
 
-void
+static void
 rs6000_va_start (tree valist, rtx nextarg)
 {
   HOST_WIDE_INT words, n_gpr, n_fpr;
@@ -6346,6 +6779,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       && (TYPE_MODE (type) == SFmode
          || TYPE_MODE (type) == DFmode
          || TYPE_MODE (type) == TFmode
+         || TYPE_MODE (type) == SDmode
          || TYPE_MODE (type) == DDmode
          || TYPE_MODE (type) == TDmode))
     {
@@ -6354,7 +6788,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       n_reg = (size + 7) / 8;
       sav_ofs = 8*4;
       sav_scale = 8;
-      if (TYPE_MODE (type) != SFmode)
+      if (TYPE_MODE (type) != SFmode && TYPE_MODE (type) != SDmode)
        align = 8;
     }
   else
@@ -6390,7 +6824,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
        {
          regalign = 1;
          u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
-                    size_int (n_reg - 1));
+                    build_int_cst (TREE_TYPE (reg), n_reg - 1));
          u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
        }
       /* _Decimal128 is passed in even/odd fpr pairs; the stored
@@ -6398,7 +6832,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       else if (reg == fpr && TYPE_MODE (type) == TDmode)
        {
          regalign = 1;
-         t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg, size_int (1));
+         t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg,
+                     build_int_cst (TREE_TYPE (reg), 1));
          u = build2 (MODIFY_EXPR, void_type_node, reg, t);
        }
 
@@ -6412,11 +6847,17 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       if (sav_ofs)
        t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
 
-      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
+      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), 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);
 
+      /* _Decimal32 varargs are located in the second word of the 64-bit
+        FP register for 32-bit binaries.  */
+      if (!TARGET_POWERPC64 && TYPE_MODE (type) == SDmode)
+       t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+
       t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
       gimplify_and_add (t, pre_p);
 
@@ -6430,7 +6871,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
        {
          /* Ensure that we don't find any more args in regs.
             Alignment has taken care of for special cases.  */
-         t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (reg), reg, size_int (8));
+         t = build_gimple_modify_stmt (reg,
+                                       build_int_cst (TREE_TYPE (reg), 8));
          gimplify_and_add (t, pre_p);
        }
     }
@@ -6488,7 +6930,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 static void
 def_builtin (int mask, const char *name, tree type, int code)
 {
-  if (mask & target_flags)
+  if ((mask & target_flags) || TARGET_PAIRED_FLOAT)
     {
       if (rs6000_builtin_decls[code])
        abort ();
@@ -6542,6 +6984,16 @@ static const struct builtin_description bdesc_3arg[] =
   { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_nmsub", ALTIVEC_BUILTIN_VEC_NMSUB },
   { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_perm", ALTIVEC_BUILTIN_VEC_PERM },
   { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sel", ALTIVEC_BUILTIN_VEC_SEL },
+
+  { 0, CODE_FOR_paired_msub, "__builtin_paired_msub", PAIRED_BUILTIN_MSUB },
+  { 0, CODE_FOR_paired_madd, "__builtin_paired_madd", PAIRED_BUILTIN_MADD },
+  { 0, CODE_FOR_paired_madds0, "__builtin_paired_madds0", PAIRED_BUILTIN_MADDS0 },
+  { 0, CODE_FOR_paired_madds1, "__builtin_paired_madds1", PAIRED_BUILTIN_MADDS1 },
+  { 0, CODE_FOR_paired_nmsub, "__builtin_paired_nmsub", PAIRED_BUILTIN_NMSUB },
+  { 0, CODE_FOR_paired_nmadd, "__builtin_paired_nmadd", PAIRED_BUILTIN_NMADD },
+  { 0, CODE_FOR_paired_sum0, "__builtin_paired_sum0", PAIRED_BUILTIN_SUM0 },
+  { 0, CODE_FOR_paired_sum1, "__builtin_paired_sum1", PAIRED_BUILTIN_SUM1 },
+  { 0, CODE_FOR_selv2sf4, "__builtin_paired_selv2sf4", PAIRED_BUILTIN_SELV2SF4 },
 };
 
 /* DST operations: void foo (void *, const int, const char).  */
@@ -6641,9 +7093,9 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
+  { MASK_ALTIVEC, CODE_FOR_ashlv16qi3, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
+  { MASK_ALTIVEC, CODE_FOR_ashlv8hi3, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
+  { MASK_ALTIVEC, CODE_FOR_ashlv4si3, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
   { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
   { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
@@ -6803,6 +7255,17 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_sums", ALTIVEC_BUILTIN_VEC_SUMS },
   { MASK_ALTIVEC, CODE_FOR_nothing, "__builtin_vec_xor", ALTIVEC_BUILTIN_VEC_XOR },
 
+  { 0, CODE_FOR_divv2sf3, "__builtin_paired_divv2sf3", PAIRED_BUILTIN_DIVV2SF3 },
+  { 0, CODE_FOR_addv2sf3, "__builtin_paired_addv2sf3", PAIRED_BUILTIN_ADDV2SF3 },
+  { 0, CODE_FOR_subv2sf3, "__builtin_paired_subv2sf3", PAIRED_BUILTIN_SUBV2SF3 },
+  { 0, CODE_FOR_mulv2sf3, "__builtin_paired_mulv2sf3", PAIRED_BUILTIN_MULV2SF3 },
+  { 0, CODE_FOR_paired_muls0, "__builtin_paired_muls0", PAIRED_BUILTIN_MULS0 },
+  { 0, CODE_FOR_paired_muls1, "__builtin_paired_muls1", PAIRED_BUILTIN_MULS1 },
+  { 0, CODE_FOR_paired_merge00, "__builtin_paired_merge00", PAIRED_BUILTIN_MERGE00 },
+  { 0, CODE_FOR_paired_merge01, "__builtin_paired_merge01", PAIRED_BUILTIN_MERGE01 },
+  { 0, CODE_FOR_paired_merge10, "__builtin_paired_merge10", PAIRED_BUILTIN_MERGE10 },
+  { 0, CODE_FOR_paired_merge11, "__builtin_paired_merge11", PAIRED_BUILTIN_MERGE11 },
+
   /* Place holder, leave as first spe builtin.  */
   { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW },
   { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND },
@@ -7016,6 +7479,15 @@ static struct builtin_description bdesc_spe_evsel[] =
   { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
 };
 
+/* PAIRED predicates.  */
+static const struct builtin_description bdesc_paired_preds[] =
+{
+  /* Place-holder.  Leave as first.  */
+  { 0, CODE_FOR_paired_cmpu0, "__builtin_paired_cmpu0", PAIRED_BUILTIN_CMPU0 },
+  /* Place-holder.  Leave as last.  */
+  { 0, CODE_FOR_paired_cmpu1, "__builtin_paired_cmpu1", PAIRED_BUILTIN_CMPU1 },
+};
+
 /* ABS* operations.  */
 
 static const struct builtin_description bdesc_abs[] =
@@ -7104,7 +7576,13 @@ static struct builtin_description bdesc_1arg[] =
   { 0, CODE_FOR_spe_evsubfumiaaw, "__builtin_spe_evsubfumiaaw", SPE_BUILTIN_EVSUBFUMIAAW },
 
   /* Place-holder.  Leave as last unary SPE builtin.  */
-  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW }
+  { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW },
+
+  { 0, CODE_FOR_absv2sf2, "__builtin_paired_absv2sf2", PAIRED_BUILTIN_ABSV2SF2 },
+  { 0, CODE_FOR_nabsv2sf2, "__builtin_paired_nabsv2sf2", PAIRED_BUILTIN_NABSV2SF2 },
+  { 0, CODE_FOR_negv2sf2, "__builtin_paired_negv2sf2", PAIRED_BUILTIN_NEGV2SF2 },
+  { 0, CODE_FOR_sqrtv2sf2, "__builtin_paired_sqrtv2sf2", PAIRED_BUILTIN_SQRTV2SF2 },
+  { 0, CODE_FOR_resv2sf2, "__builtin_paired_resv2sf2", PAIRED_BUILTIN_RESV2SF2 }
 };
 
 static rtx
@@ -7339,6 +7817,52 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
 }
 
 static rtx
+paired_expand_lv_builtin (enum insn_code icode, tree exp, rtx target)
+{
+  rtx pat, addr;
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = Pmode;
+  enum machine_mode mode1 = Pmode;
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
+  /* If we got invalid arguments bail out before generating bad rtl.  */
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return const0_rtx;
+
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  op1 = copy_to_mode_reg (mode1, op1);
+
+  if (op0 == const0_rtx)
+    {
+      addr = gen_rtx_MEM (tmode, op1);
+    }
+  else
+    {
+      op0 = copy_to_mode_reg (mode0, op0);
+      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
+    }
+
+  pat = GEN_FCN (icode) (target, addr);
+
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+
+  return target;
+}
+
+static rtx
 altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, addr;
@@ -7418,6 +7942,47 @@ spe_expand_stv_builtin (enum insn_code icode, tree exp)
 }
 
 static rtx
+paired_expand_stv_builtin (enum insn_code icode, tree exp)
+{
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
+  rtx pat, addr;
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode1 = Pmode;
+  enum machine_mode mode2 = Pmode;
+
+  /* Invalid arguments.  Bail before doing anything stoopid!  */
+  if (arg0 == error_mark_node
+      || arg1 == error_mark_node
+      || arg2 == error_mark_node)
+    return const0_rtx;
+
+  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
+    op0 = copy_to_mode_reg (tmode, op0);
+
+  op2 = copy_to_mode_reg (mode2, op2);
+
+  if (op1 == const0_rtx)
+    {
+      addr = gen_rtx_MEM (tmode, op2);
+    }
+  else
+    {
+      op1 = copy_to_mode_reg (mode1, op1);
+      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
+    }
+
+  pat = GEN_FCN (icode) (addr, op0);
+  if (pat)
+    emit_insn (pat);
+  return NULL_RTX;
+}
+
+static rtx
 altivec_expand_stv_builtin (enum insn_code icode, tree exp)
 {
   tree arg0 = CALL_EXPR_ARG (exp, 0);
@@ -7510,7 +8075,10 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
   if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
     op2 = copy_to_mode_reg (mode2, op2);
 
-  pat = GEN_FCN (icode) (target, op0, op1, op2);
+  if (TARGET_PAIRED_FLOAT && icode == CODE_FOR_selv2sf4)
+    pat = GEN_FCN (icode) (target, op0, op1, op2, CONST0_RTX (SFmode));
+  else 
+    pat = GEN_FCN (icode) (target, op0, op1, op2);
   if (! pat)
     return 0;
   emit_insn (pat);
@@ -7631,13 +8199,13 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
   tree arg0, arg1, arg2;
   enum machine_mode mode0, mode1, mode2;
   rtx pat, op0, op1, op2;
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
 
   *expandedp = false;
 
   /* Handle DST variants.  */
-  d = (struct builtin_description *) bdesc_dst;
+  d = bdesc_dst;
   for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
     if (d->code == fcode)
       {
@@ -7790,8 +8358,8 @@ altivec_expand_vec_ext_builtin (tree exp, rtx target)
 static rtx
 altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
 {
-  struct builtin_description *d;
-  struct builtin_description_predicates *dp;
+  const struct builtin_description *d;
+  const struct builtin_description_predicates *dp;
   size_t i;
   enum insn_code icode;
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
@@ -7920,13 +8488,13 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     }
 
   /* Expand abs* operations.  */
-  d = (struct builtin_description *) bdesc_abs;
+  d = bdesc_abs;
   for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
     if (d->code == fcode)
       return altivec_expand_abs_builtin (d->icode, exp, target);
 
   /* Expand the AltiVec predicates.  */
-  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
+  dp = bdesc_altivec_preds;
   for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
     if (dp->code == fcode)
       return altivec_expand_predicate_builtin (dp->icode, dp->opcode,
@@ -7965,6 +8533,39 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   return NULL_RTX;
 }
 
+/* Expand the builtin in EXP and store the result in TARGET.  Store
+   true in *EXPANDEDP if we found a builtin to expand.  */
+static rtx
+paired_expand_builtin (tree exp, rtx target, bool * expandedp)
+{
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  const struct builtin_description *d;
+  size_t i;
+
+  *expandedp = true;
+
+  switch (fcode)
+    {
+    case PAIRED_BUILTIN_STX:
+      return paired_expand_stv_builtin (CODE_FOR_paired_stx, exp);
+    case PAIRED_BUILTIN_LX:
+      return paired_expand_lv_builtin (CODE_FOR_paired_lx, exp, target);
+    default:
+      break;
+      /* Fall through.  */
+    }
+
+  /* Expand the paired predicates.  */
+  d = bdesc_paired_preds;
+  for (i = 0; i < ARRAY_SIZE (bdesc_paired_preds); i++, d++)
+    if (d->code == fcode)
+      return paired_expand_predicate_builtin (d->icode, exp, target);
+
+  *expandedp = false;
+  return NULL_RTX;
+}
+
 /* Binops that need to be initialized manually, but can be expanded
    automagically by rs6000_expand_binop_builtin.  */
 static struct builtin_description bdesc_2arg_spe[] =
@@ -8131,6 +8732,78 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
 }
 
 static rtx
+paired_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target)
+{
+  rtx pat, scratch, tmp;
+  tree form = CALL_EXPR_ARG (exp, 0);
+  tree arg0 = CALL_EXPR_ARG (exp, 1);
+  tree arg1 = CALL_EXPR_ARG (exp, 2);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+  int form_int;
+  enum rtx_code code;
+
+  if (TREE_CODE (form) != INTEGER_CST)
+    {
+      error ("argument 1 of __builtin_paired_predicate must be a constant");
+      return const0_rtx;
+    }
+  else
+    form_int = TREE_INT_CST_LOW (form);
+
+  gcc_assert (mode0 == mode1);
+
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return const0_rtx;
+
+  if (target == 0
+      || GET_MODE (target) != SImode
+      || !(*insn_data[icode].operand[0].predicate) (target, SImode))
+    target = gen_reg_rtx (SImode);
+  if (!(*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (!(*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
+
+  scratch = gen_reg_rtx (CCFPmode);
+
+  pat = GEN_FCN (icode) (scratch, op0, op1);
+  if (!pat)
+    return const0_rtx;
+
+  emit_insn (pat);
+
+  switch (form_int)
+    {
+      /* LT bit.  */
+    case 0:
+      code = LT;
+      break;
+      /* GT bit.  */
+    case 1:
+      code = GT;
+      break;
+      /* EQ bit.  */
+    case 2:
+      code = EQ;
+      break;
+      /* UN bit.  */
+    case 3:
+      emit_insn (gen_move_from_CR_ov_bit (target, scratch));
+      return target;
+    default:
+      error ("argument 1 of __builtin_paired_predicate is out of range");
+      return const0_rtx;
+    }
+
+  tmp = gen_rtx_fmt_ee (code, SImode, scratch, const0_rtx);
+  emit_move_insn (target, tmp);
+  return target;
+}
+
+static rtx
 spe_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, scratch, tmp;
@@ -8301,11 +8974,20 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 {
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
   rtx ret;
   bool success;
 
+  if (fcode == RS6000_BUILTIN_RECIP)
+      return rs6000_expand_binop_builtin (CODE_FOR_recipdf3, exp, target);    
+
+  if (fcode == RS6000_BUILTIN_RECIPF)
+      return rs6000_expand_binop_builtin (CODE_FOR_recipsf3, exp, target);    
+
+  if (fcode == RS6000_BUILTIN_RSQRTF)
+      return rs6000_expand_unop_builtin (CODE_FOR_rsqrtsf2, exp, target);    
+
   if (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD
       || fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
     {
@@ -8369,9 +9051,16 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
       if (success)
        return ret;
-    }
+    }
+  if (TARGET_PAIRED_FLOAT)
+    {
+      ret = paired_expand_builtin (exp, target, &success);
+
+      if (success)
+       return ret;
+    }  
 
-  gcc_assert (TARGET_ALTIVEC || TARGET_SPE);
+  gcc_assert (TARGET_ALTIVEC || TARGET_SPE || TARGET_PAIRED_FLOAT);
 
   /* Handle simple unary operations.  */
   d = (struct builtin_description *) bdesc_1arg;
@@ -8386,7 +9075,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return rs6000_expand_binop_builtin (d->icode, exp, target);
 
   /* Handle simple ternary operations.  */
-  d = (struct builtin_description *) bdesc_3arg;
+  d = bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
     if (d->code == fcode)
       return rs6000_expand_ternop_builtin (d->icode, exp, target);
@@ -8497,18 +9186,49 @@ rs6000_init_builtins (void)
                                            get_identifier ("__vector __pixel"),
                                            pixel_V8HI_type_node));
 
+  if (TARGET_PAIRED_FLOAT)
+    paired_init_builtins ();
   if (TARGET_SPE)
     spe_init_builtins ();
   if (TARGET_ALTIVEC)
     altivec_init_builtins ();
-  if (TARGET_ALTIVEC || TARGET_SPE)
+  if (TARGET_ALTIVEC || TARGET_SPE || TARGET_PAIRED_FLOAT)
     rs6000_common_init_builtins ();
+  if (TARGET_PPC_GFXOPT)
+    {
+      tree ftype = build_function_type_list (float_type_node,
+                                            float_type_node,
+                                            float_type_node,
+                                            NULL_TREE);
+      def_builtin (MASK_PPC_GFXOPT, "__builtin_recipdivf", ftype,
+                  RS6000_BUILTIN_RECIPF);
+
+      ftype = build_function_type_list (float_type_node,
+                                       float_type_node,
+                                       NULL_TREE);
+      def_builtin (MASK_PPC_GFXOPT, "__builtin_rsqrtf", ftype,
+                  RS6000_BUILTIN_RSQRTF);
+    }
+  if (TARGET_POPCNTB)
+    {
+      tree ftype = build_function_type_list (double_type_node,
+                                            double_type_node,
+                                            double_type_node,
+                                            NULL_TREE);
+      def_builtin (MASK_POPCNTB, "__builtin_recipdiv", ftype,
+                  RS6000_BUILTIN_RECIP);
+
+    }
 
 #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");
 #endif
+
+#ifdef SUBTARGET_INIT_BUILTINS
+  SUBTARGET_INIT_BUILTINS;
+#endif
 }
 
 /* Search through a set of builtins and enable the mask bits.
@@ -8759,10 +9479,66 @@ spe_init_builtins (void)
 }
 
 static void
+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))));
+  tree pcfloat_type_node =
+    build_pointer_type (build_qualified_type
+                       (float_type_node, TYPE_QUAL_CONST));
+
+  tree v2sf_ftype_long_pcfloat = build_function_type_list (V2SF_type_node,
+                                                          long_integer_type_node,
+                                                          pcfloat_type_node,
+                                                          NULL_TREE);
+  tree void_ftype_v2sf_long_pcfloat =
+    build_function_type_list (void_type_node,
+                             V2SF_type_node,
+                             long_integer_type_node,
+                             pcfloat_type_node,
+                             NULL_TREE);
+
+
+  def_builtin (0, "__builtin_paired_lx", v2sf_ftype_long_pcfloat,
+              PAIRED_BUILTIN_LX);
+
+
+  def_builtin (0, "__builtin_paired_stx", void_ftype_v2sf_long_pcfloat,
+              PAIRED_BUILTIN_STX);
+
+  /* Predicates.  */
+  d = bdesc_paired_preds;
+  for (i = 0; i < ARRAY_SIZE (bdesc_paired_preds); ++i, d++)
+    {
+      tree type;
+
+      switch (insn_data[d->icode].operand[1].mode)
+       {
+       case V2SFmode:
+         type = int_ftype_int_v2sf_v2sf;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+
+      def_builtin (d->mask, d->name, type, d->code);
+    }
+}
+
+static void
 altivec_init_builtins (void)
 {
-  struct builtin_description *d;
-  struct builtin_description_predicates *dp;
+  const struct builtin_description *d;
+  const struct builtin_description_predicates *dp;
   size_t i;
   tree ftype;
 
@@ -8943,12 +9719,12 @@ altivec_init_builtins (void)
   def_builtin (MASK_ALTIVEC, "__builtin_vec_ctu", opaque_ftype_opaque_int, ALTIVEC_BUILTIN_VEC_CTU);
 
   /* Add the DST variants.  */
-  d = (struct builtin_description *) bdesc_dst;
+  d = bdesc_dst;
   for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
     def_builtin (d->mask, d->name, void_ftype_pcvoid_int_int, d->code);
 
   /* Initialize the predicates.  */
-  dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
+  dp = bdesc_altivec_preds;
   for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
     {
       enum machine_mode mode1;
@@ -8986,7 +9762,7 @@ altivec_init_builtins (void)
     }
 
   /* Initialize the abs* operators.  */
-  d = (struct builtin_description *) bdesc_abs;
+  d = bdesc_abs;
   for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
     {
       enum machine_mode mode0;
@@ -9117,9 +9893,14 @@ altivec_init_builtins (void)
 static void
 rs6000_common_init_builtins (void)
 {
-  struct builtin_description *d;
+  const struct builtin_description *d;
   size_t i;
 
+  tree v2sf_ftype_v2sf_v2sf_v2sf
+    = build_function_type_list (V2SF_type_node,
+                                V2SF_type_node, V2SF_type_node,
+                                V2SF_type_node, NULL_TREE);
+
   tree v4sf_ftype_v4sf_v4sf_v16qi
     = build_function_type_list (V4SF_type_node,
                                V4SF_type_node, V4SF_type_node,
@@ -9152,11 +9933,17 @@ rs6000_common_init_builtins (void)
                                opaque_V2SI_type_node,
                                opaque_V2SI_type_node, NULL_TREE);
 
-  tree v2sf_ftype_v2sf_v2sf
+  tree v2sf_ftype_v2sf_v2sf_spe
     = build_function_type_list (opaque_V2SF_type_node,
                                opaque_V2SF_type_node,
                                opaque_V2SF_type_node, NULL_TREE);
 
+  tree v2sf_ftype_v2sf_v2sf
+    = build_function_type_list (V2SF_type_node,
+                                V2SF_type_node,
+                                V2SF_type_node, NULL_TREE);
+
+
   tree v2si_ftype_int_int
     = build_function_type_list (opaque_V2SI_type_node,
                                integer_type_node, integer_type_node,
@@ -9170,10 +9957,14 @@ rs6000_common_init_builtins (void)
     = build_function_type_list (opaque_V2SI_type_node,
                                opaque_V2SI_type_node, NULL_TREE);
 
-  tree v2sf_ftype_v2sf
+  tree v2sf_ftype_v2sf_spe
     = build_function_type_list (opaque_V2SF_type_node,
                                opaque_V2SF_type_node, NULL_TREE);
 
+  tree v2sf_ftype_v2sf
+    = build_function_type_list (V2SF_type_node,
+                                V2SF_type_node, NULL_TREE);
+
   tree v2sf_ftype_v2si
     = build_function_type_list (opaque_V2SF_type_node,
                                opaque_V2SI_type_node, NULL_TREE);
@@ -9314,7 +10105,7 @@ rs6000_common_init_builtins (void)
                                V8HI_type_node, V8HI_type_node, NULL_TREE);
 
   /* Add the simple ternary operators.  */
-  d = (struct builtin_description *) bdesc_3arg;
+  d = bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_3arg); i++, d++)
     {
       enum machine_mode mode0, mode1, mode2, mode3;
@@ -9360,6 +10151,9 @@ rs6000_common_init_builtins (void)
            case V16QImode:
              type = v16qi_ftype_v16qi_v16qi_v16qi;
              break;
+            case V2SFmode:
+                type = v2sf_ftype_v2sf_v2sf_v2sf;
+              break;
            default:
              gcc_unreachable ();
            }
@@ -9468,8 +10262,11 @@ rs6000_common_init_builtins (void)
            case V2SImode:
              type = v2si_ftype_v2si_v2si;
              break;
-           case V2SFmode:
-             type = v2sf_ftype_v2sf_v2sf;
+            case V2SFmode:
+              if (TARGET_PAIRED_FLOAT)
+                type = v2sf_ftype_v2sf_v2sf;
+              else
+                type = v2sf_ftype_v2sf_v2sf_spe;
              break;
            case SImode:
              type = int_ftype_int_int;
@@ -9608,7 +10405,12 @@ rs6000_common_init_builtins (void)
       else if (mode0 == V2SImode && mode1 == V2SImode)
        type = v2si_ftype_v2si;
       else if (mode0 == V2SFmode && mode1 == V2SFmode)
-       type = v2sf_ftype_v2sf;
+        {
+          if (TARGET_PAIRED_FLOAT)
+            type = v2sf_ftype_v2sf;
+          else
+            type = v2sf_ftype_v2sf_spe;
+        }
       else if (mode0 == V2SFmode && mode1 == V2SImode)
        type = v2sf_ftype_v2si;
       else if (mode0 == V2SImode && mode1 == V2SFmode)
@@ -9746,6 +10548,8 @@ expand_block_clear (rtx operands[])
     clear_step = 16;
   else if (TARGET_POWERPC64 && align >= 32)
     clear_step = 8;
+  else if (TARGET_SPE && align >= 64)
+    clear_step = 8;
   else
     clear_step = 4;
 
@@ -9764,10 +10568,15 @@ expand_block_clear (rtx operands[])
          clear_bytes = 16;
          mode = V4SImode;
        }
+      else if (bytes >= 8 && TARGET_SPE && align >= 64)
+        {
+          clear_bytes = 8;
+          mode = V2SImode;
+        }
       else if (bytes >= 8 && TARGET_POWERPC64
-         /* 64-bit loads and stores require word-aligned
-            displacements.  */
-         && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
+              /* 64-bit loads and stores require word-aligned
+                 displacements.  */
+              && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
        {
          clear_bytes = 8;
          mode = DImode;
@@ -9857,6 +10666,12 @@ expand_block_move (rtx operands[])
          mode = V4SImode;
          gen_func.mov = gen_movv4si;
        }
+      else if (TARGET_SPE && bytes >= 8 && align >= 64)
+        {
+          move_bytes = 8;
+          mode = V2SImode;
+          gen_func.mov = gen_movv2si;
+        }
       else if (TARGET_STRING
          && bytes > 24         /* move up to 32 bytes at a time */
          && ! fixed_regs[5]
@@ -10379,6 +11194,106 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem2)
   return 1;
 }
 \f
+
+rtx
+rs6000_secondary_memory_needed_rtx (enum machine_mode mode)
+{
+  static bool eliminated = false;
+  if (mode != SDmode)
+    return assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
+  else
+    {
+      rtx mem = cfun->machine->sdmode_stack_slot;
+      gcc_assert (mem != NULL_RTX);
+
+      if (!eliminated)
+       {
+         mem = eliminate_regs (mem, VOIDmode, NULL_RTX);
+         cfun->machine->sdmode_stack_slot = mem;
+         eliminated = true;
+       }
+      return mem;
+    }
+}
+
+static tree
+rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+  /* Don't walk into types.  */
+  if (*tp == NULL_TREE || *tp == error_mark_node || TYPE_P (*tp))
+    {
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    }
+
+  switch (TREE_CODE (*tp))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+    case FIELD_DECL:
+    case RESULT_DECL:
+    case REAL_CST:
+      if (TYPE_MODE (TREE_TYPE (*tp)) == SDmode)
+       return *tp;
+      break;
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+
+/* Allocate a 64-bit stack slot to be used for copying SDmode
+   values through if this function has any SDmode references.  */
+
+static void
+rs6000_alloc_sdmode_stack_slot (void)
+{
+  tree t;
+  basic_block bb;
+  block_stmt_iterator bsi;
+
+  gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX);
+
+  FOR_EACH_BB (bb)
+    for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      {
+       tree ret = walk_tree_without_duplicates (bsi_stmt_ptr (bsi),
+                                                rs6000_check_sdmode, NULL);
+       if (ret)
+         {
+           rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0);
+           cfun->machine->sdmode_stack_slot = adjust_address_nv (stack,
+                                                                 SDmode, 0);
+           return;
+         }
+      }
+
+  /* Check for any SDmode parameters of the function.  */
+  for (t = DECL_ARGUMENTS (cfun->decl); t; t = TREE_CHAIN (t))
+    {
+      if (TREE_TYPE (t) == error_mark_node)
+       continue;
+
+      if (TYPE_MODE (TREE_TYPE (t)) == SDmode
+         || TYPE_MODE (DECL_ARG_TYPE (t)) == SDmode)
+       {
+         rtx stack = assign_stack_local (DDmode, GET_MODE_SIZE (DDmode), 0);
+         cfun->machine->sdmode_stack_slot = adjust_address_nv (stack,
+                                                               SDmode, 0);
+         return;
+       }
+    }
+}
+
+static void
+rs6000_instantiate_decls (void)
+{
+  if (cfun->machine->sdmode_stack_slot != NULL_RTX)
+    instantiate_decl_rtl (cfun->machine->sdmode_stack_slot);
+}
+
 /* Return the register class of a scratch register needed to copy IN into
    or out of a register in CLASS in MODE.  If it can be done directly,
    NO_REGS is returned.  */
@@ -10439,7 +11354,7 @@ rs6000_secondary_reload_class (enum reg_class class,
   /* Constants, memory, and FP registers can go into FP registers.  */
   if ((regno == -1 || FP_REGNO_P (regno))
       && (class == FLOAT_REGS || class == NON_SPECIAL_REGS))
-    return NO_REGS;
+    return (mode != SDmode) ? NO_REGS : GENERAL_REGS;
 
   /* Memory, and AltiVec registers can go into AltiVec registers.  */
   if ((regno == -1 || ALTIVEC_REGNO_P (regno))
@@ -12178,7 +13093,7 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
            eq_rtx = rs6000_emit_vector_compare (rev_code, op0, op1,
                                                 dest_mode);
 
-           nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
+           nor_code = optab_handler (one_cmpl_optab, (int)dest_mode)->insn_code;
            gcc_assert (nor_code != CODE_FOR_nothing);
            emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
 
@@ -12228,7 +13143,7 @@ rs6000_emit_vector_compare (enum rtx_code rcode,
            eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
                                                 dest_mode);
 
-           ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
+           ior_code = optab_handler (ior_optab, (int)dest_mode)->insn_code;
            gcc_assert (ior_code != CODE_FOR_nothing);
            emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
            if (dmode != dest_mode)
@@ -12638,14 +13553,16 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
            ishift = GET_MODE_BITSIZE (SImode) - GET_MODE_BITSIZE (mode);
 
          shift = GEN_INT (ishift);
+         used_m = change_address (used_m, SImode, 0);
        }
       else
        {
          rtx addrSI, aligned_addr;
          int shift_mask = mode == QImode ? 0x18 : 0x10;
 
-         addrSI = force_reg (SImode, gen_lowpart_common (SImode,
-                                                         XEXP (used_m, 0)));
+         addrSI = gen_lowpart_common (SImode,
+                                      force_reg (Pmode, XEXP (used_m, 0)));
+         addrSI = force_reg (SImode, addrSI);
          shift = gen_reg_rtx (SImode);
 
          emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
@@ -12658,14 +13575,14 @@ rs6000_emit_sync (enum rtx_code code, enum machine_mode mode,
                                       1, OPTAB_LIB_WIDEN);
          used_m = change_address (used_m, SImode, aligned_addr);
          set_mem_align (used_m, 32);
-         /* It's safe to keep the old alias set of USED_M, because
-            the operation is atomic and only affects the original
-            USED_M.  */
-         if (GET_CODE (m) == NOT)
-           m = gen_rtx_NOT (SImode, used_m);
-         else
-           m = used_m;
        }
+      /* It's safe to keep the old alias set of USED_M, because
+        the operation is atomic and only affects the original
+        USED_M.  */
+      if (GET_CODE (m) == NOT)
+       m = gen_rtx_NOT (SImode, used_m);
+      else
+       m = used_m;
 
       if (GET_CODE (op) == NOT)
        {
@@ -12989,6 +13906,9 @@ rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
   emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
                                                    oldval, newval, mem));
 
+  /* Shift the result back.  */
+  emit_insn (gen_lshrsi3 (wdst, wdst, shift));
+
   emit_move_insn (dst, gen_lowpart (mode, wdst));
 }
 
@@ -13060,8 +13980,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
     reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode : DFmode;
   else if (ALTIVEC_REGNO_P (reg))
     reg_mode = V16QImode;
-  else if (TARGET_E500_DOUBLE && mode == TFmode)
-    reg_mode = DFmode;
+  else if (TARGET_E500_DOUBLE && (mode == TFmode || mode == TDmode))
+    reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode : DFmode;
   else
     reg_mode = word_mode;
   reg_mode_size = GET_MODE_SIZE (reg_mode);
@@ -13463,6 +14383,7 @@ rs6000_stack_info (void)
   int reg_size = TARGET_32BIT ? 4 : 8;
   int ehrd_size;
   int save_align;
+  int first_gp;
   HOST_WIDE_INT non_fixed_size;
 
   memset (&info, 0, sizeof (info));
@@ -13482,14 +14403,19 @@ rs6000_stack_info (void)
   /* Calculate which registers need to be saved & save area size.  */
   info_ptr->first_gp_reg_save = first_reg_to_save ();
   /* Assume that we will have to save RS6000_PIC_OFFSET_TABLE_REGNUM,
-     even if it currently looks like we won't.  */
+     even if it currently looks like we won't.  Reload may need it to
+     get at a constant; if so, it will have already created a constant
+     pool entry for it.  */
   if (((TARGET_TOC && TARGET_MINIMAL_TOC)
        || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
        || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
+      && current_function_uses_const_pool
       && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
-    info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
+    first_gp = RS6000_PIC_OFFSET_TABLE_REGNUM;
   else
-    info_ptr->gp_size = reg_size * (32 - info_ptr->first_gp_reg_save);
+    first_gp = info_ptr->first_gp_reg_save;
+
+  info_ptr->gp_size = reg_size * (32 - first_gp);
 
   /* For the SPE, we have an additional upper 32-bits on each GPR.
      Ideally we should save the entire 64-bits only when the upper
@@ -13526,7 +14452,6 @@ rs6000_stack_info (void)
 #endif
       || (info_ptr->first_fp_reg_save != 64
          && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
-      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
       || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
       || info_ptr->calls_p
       || rs6000_ra_ever_killed ())
@@ -13577,7 +14502,7 @@ rs6000_stack_info (void)
            + info_ptr->parm_size);
 
   if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
-    info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
+    info_ptr->spe_gp_size = 8 * (32 - first_gp);
   else
     info_ptr->spe_gp_size = 0;
 
@@ -13794,7 +14719,8 @@ spe_func_has_64bit_regs_p (void)
 
              if (SPE_VECTOR_MODE (mode))
                return true;
-             if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode))
+             if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                        || mode == DDmode || mode == TDmode))
                return true;
            }
        }
@@ -14000,7 +14926,7 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
    PowerPC uses the COUNT register for branch on table instructions.  */
 
 static const char *
-rs6000_invalid_within_doloop (rtx insn)
+rs6000_invalid_within_doloop (const_rtx insn)
 {
   if (CALL_P (insn))
     return "Function call in the loop.";
@@ -14194,9 +15120,9 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
     emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), operands[0]);
 }
 
-static GTY(()) int set = -1;
+static GTY(()) alias_set_type set = -1;
 
-int
+alias_set_type
 get_TOC_alias_set (void)
 {
   if (set == -1)
@@ -14466,77 +15392,12 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
          }
     }
 
-  if (TARGET_SPE)
-    real = spe_synthesize_frame_save (real);
-
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
                                        real,
                                        REG_NOTES (insn));
 }
 
-/* Given an SPE frame note, return a PARALLEL of SETs with the
-   original note, plus a synthetic register save.  */
-
-static rtx
-spe_synthesize_frame_save (rtx real)
-{
-  rtx synth, offset, reg, real2;
-
-  if (GET_CODE (real) != SET
-      || GET_MODE (SET_SRC (real)) != V2SImode)
-    return real;
-
-  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
-     frame related note.  The parallel contains a set of the register
-     being saved, and another set to a synthetic register (n+1200).
-     This is so we can differentiate between 64-bit and 32-bit saves.
-     Words cannot describe this nastiness.  */
-
-  gcc_assert (GET_CODE (SET_DEST (real)) == MEM
-             && GET_CODE (XEXP (SET_DEST (real), 0)) == PLUS
-             && GET_CODE (SET_SRC (real)) == REG);
-
-  /* Transform:
-       (set (mem (plus (reg x) (const y)))
-            (reg z))
-     into:
-       (set (mem (plus (reg x) (const y+4)))
-            (reg z+1200))
-  */
-
-  real2 = copy_rtx (real);
-  PUT_MODE (SET_DEST (real2), SImode);
-  reg = SET_SRC (real2);
-  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
-  synth = copy_rtx (real2);
-
-  if (BYTES_BIG_ENDIAN)
-    {
-      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
-      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
-    }
-
-  reg = SET_SRC (synth);
-
-  synth = replace_rtx (synth, reg,
-                      gen_rtx_REG (SImode, REGNO (reg) + 1200));
-
-  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
-  synth = replace_rtx (synth, offset,
-                      GEN_INT (INTVAL (offset)
-                               + (BYTES_BIG_ENDIAN ? 0 : 4)));
-
-  RTX_FRAME_RELATED_P (synth) = 1;
-  RTX_FRAME_RELATED_P (real2) = 1;
-  if (BYTES_BIG_ENDIAN)
-    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
-  else
-    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
-
-  return real;
-}
-
 /* Returns an insn that has a vrsave set operation with the
    appropriate CLOBBERs.  */
 
@@ -14610,7 +15471,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_E500_DOUBLE && mode == DFmode)
+      || (TARGET_E500_DOUBLE && (mode == DFmode || mode == DDmode))
       || (TARGET_SPE_ABI
          && SPE_VECTOR_MODE (mode)
          && !SPE_CONST_OFFSET_OK (offset)))
@@ -14650,7 +15511,7 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
   int_rtx = GEN_INT (offset);
 
   if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
-      || (TARGET_E500_DOUBLE && mode == DFmode))
+      || (TARGET_E500_DOUBLE && (mode == DFmode || mode == DDmode)))
     {
       offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
       emit_move_insn (offset_rtx, int_rtx);
@@ -15007,7 +15868,7 @@ rs6000_emit_prologue (void)
  
        if (spe_regs_addressable_via_sp)
          {
-           spe_save_area_ptr = sp_reg_rtx;
+           spe_save_area_ptr = frame_reg_rtx;
            spe_offset = info->spe_gp_save_offset + sp_offset;
          }
        else
@@ -15028,7 +15889,7 @@ rs6000_emit_prologue (void)
              }
  
            spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
-           emit_insn (gen_addsi3 (spe_save_area_ptr, sp_reg_rtx,
+           emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx,
                                   GEN_INT (info->spe_gp_save_offset + sp_offset)));
  
            spe_offset = 0;
@@ -15498,8 +16359,8 @@ rs6000_emit_epilogue (int sibcall)
       return;
     }
 
-  /* Set sp_offset based on the stack push from the prologue.  */
-  if (info->total_size < 32767)
+  /* frame_reg_rtx + sp_offset points to the top of this stack frame.  */
+  if (info->push_p)
     sp_offset = info->total_size;
 
   /* Restore AltiVec registers if needed.  */
@@ -15526,23 +16387,6 @@ rs6000_emit_epilogue (int sibcall)
          }
     }
 
-  /* Restore VRSAVE if needed.  */
-  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && info->vrsave_mask != 0)
-    {
-      rtx addr, mem, reg;
-
-      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                          GEN_INT (info->vrsave_save_offset + sp_offset));
-      mem = gen_frame_mem (SImode, addr);
-      reg = gen_rtx_REG (SImode, 12);
-      emit_move_insn (reg, mem);
-
-      emit_insn (generate_set_vrsave (reg, info, 1));
-    }
-
-  sp_offset = 0;
-
   /* If we have a frame pointer, a call to alloca,  or a large stack
      frame, restore the old stack pointer using the backchain.  Otherwise,
      we know what size to update it with.  */
@@ -15555,20 +16399,33 @@ rs6000_emit_epilogue (int sibcall)
 
       emit_move_insn (frame_reg_rtx,
                      gen_rtx_MEM (Pmode, sp_reg_rtx));
+      sp_offset = 0;
     }
-  else if (info->push_p)
+  else if (info->push_p
+          && DEFAULT_ABI != ABI_V4
+          && !current_function_calls_eh_return)
     {
-      if (DEFAULT_ABI == ABI_V4
-         || current_function_calls_eh_return)
-       sp_offset = info->total_size;
-      else
-       {
-         emit_insn (TARGET_32BIT
-                    ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
-                                  GEN_INT (info->total_size))
-                    : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
-                                  GEN_INT (info->total_size)));
-       }
+      emit_insn (TARGET_32BIT
+                ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
+                              GEN_INT (info->total_size))
+                : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
+                              GEN_INT (info->total_size)));
+      sp_offset = 0;
+    }
+
+  /* Restore VRSAVE if needed.  */
+  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0)
+    {
+      rtx addr, mem, reg;
+
+      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                          GEN_INT (info->vrsave_save_offset + sp_offset));
+      mem = gen_frame_mem (SImode, addr);
+      reg = gen_rtx_REG (SImode, 12);
+      emit_move_insn (reg, mem);
+
+      emit_insn (generate_set_vrsave (reg, info, 1));
     }
 
   /* Get the old lr if we saved it.  */
@@ -15650,7 +16507,6 @@ rs6000_emit_epilogue (int sibcall)
            && info->spe_64bit_regs_used != 0
            && info->first_gp_reg_save != 32)
     {
-      rtx spe_save_area_ptr;
       /* Determine whether we can address all of the registers that need
          to be saved with an offset from the stack pointer that fits in
          the small const field for SPE memory instructions.  */
@@ -15660,20 +16516,21 @@ rs6000_emit_epilogue (int sibcall)
       int spe_offset;
 
       if (spe_regs_addressable_via_sp)
-        {
-          spe_save_area_ptr = frame_reg_rtx;
-          spe_offset = info->spe_gp_save_offset + sp_offset;
-        }
+       spe_offset = info->spe_gp_save_offset + sp_offset;
       else
         {
+         rtx old_frame_reg_rtx = frame_reg_rtx;
           /* Make r11 point to the start of the SPE save area.  We worried about
              not clobbering it when we were saving registers in the prologue.
              There's no need to worry here because the static chain is passed
              anew to every function.  */
-          spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
-
-          emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx,
+         if (frame_reg_rtx == sp_reg_rtx)
+           frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+          emit_insn (gen_addsi3 (frame_reg_rtx, old_frame_reg_rtx,
                                  GEN_INT (info->spe_gp_save_offset + sp_offset)));
+         /* Keep the invariant that frame_reg_rtx + sp_offset points
+            at the top of the stack frame.  */
+         sp_offset = -info->spe_gp_save_offset;
 
           spe_offset = 0;
         }
@@ -15688,7 +16545,7 @@ rs6000_emit_epilogue (int sibcall)
             gcc_assert (SPE_CONST_OFFSET_OK (spe_offset + reg_size * i));
 
             offset = GEN_INT (spe_offset + reg_size * i);
-            addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, offset);
             mem = gen_rtx_MEM (V2SImode, addr);
 
             emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
@@ -15780,11 +16637,9 @@ rs6000_emit_epilogue (int sibcall)
       /* This blockage is needed so that sched doesn't decide to move
         the sp change before the register restores.  */
       rs6000_emit_stack_tie ();
-      if (TARGET_SPE_ABI
-          && info->spe_64bit_regs_used != 0
-          && info->first_gp_reg_save != 32)
-        emit_insn (gen_addsi3 (sp_reg_rtx, gen_rtx_REG (Pmode, 11),
-                               GEN_INT (-(info->spe_gp_save_offset + sp_offset))));
+      if (sp_offset != 0)
+        emit_insn (gen_addsi3 (sp_reg_rtx, frame_reg_rtx,
+                              GEN_INT (sp_offset)));
       else
         emit_move_insn (sp_reg_rtx, frame_reg_rtx);
     }
@@ -16048,6 +16903,7 @@ rs6000_output_function_epilogue (FILE *file,
                      switch (mode)
                        {
                        case SFmode:
+                       case SDmode:
                          bits = 0x2;
                          break;
 
@@ -16270,6 +17126,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   final_start_function (insn, file, 1);
   final (insn, file, 1);
   final_end_function ();
+  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -17494,9 +18351,8 @@ adjacent_mem_locations (rtx insn1, rtx insn2)
          || (GET_CODE (XEXP (b, 0)) == PLUS
              && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
     {
-      HOST_WIDE_INT val0 = 0, val1 = 0;
+      HOST_WIDE_INT val0 = 0, val1 = 0, val_diff;
       rtx reg0, reg1;
-      int val_diff;
 
       if (GET_CODE (XEXP (a, 0)) == PLUS)
         {
@@ -17517,8 +18373,8 @@ adjacent_mem_locations (rtx insn1, rtx insn2)
       val_diff = val1 - val0;
 
       return ((REGNO (reg0) == REGNO (reg1))
-             && (val_diff == INTVAL (MEM_SIZE (a))
-                  || val_diff == -INTVAL (MEM_SIZE (b))));
+             && ((MEM_SIZE (a) && val_diff == INTVAL (MEM_SIZE (a)))
+                 || (MEM_SIZE (b) && val_diff == -INTVAL (MEM_SIZE (b)))));
     }
 
   return false;
@@ -17647,6 +18503,8 @@ rs6000_issue_rate (void)
   case CPU_PPC7400:
   case CPU_PPC8540:
   case CPU_CELL:
+  case CPU_PPCE300C2:
+  case CPU_PPCE300C3:
     return 2;
   case CPU_RIOS2:
   case CPU_PPC604:
@@ -17703,6 +18561,11 @@ is_mem_ref (rtx pat)
   int i, j;
   bool ret = false;
 
+  /* stack_tie does not produce any real memory traffic.  */
+  if (GET_CODE (pat) == UNSPEC
+      && XINT (pat, 1) == UNSPEC_TIE)
+    return false;
+
   if (GET_CODE (pat) == MEM)
     return true;
 
@@ -17851,7 +18714,7 @@ rs6000_is_costly_dependence (dep_t dep, int cost, int distance)
   if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
       && is_load_insn (next)
       && is_store_insn (insn)
-      && DEP_KIND (dep) == REG_DEP_TRUE)
+      && DEP_TYPE (dep) == REG_DEP_TRUE)
      /* Prevent load after store in the same group if it is a true
        dependence.  */
      return true;
@@ -18327,15 +19190,15 @@ is_costly_group (rtx *group_insns, rtx next_insn)
 
   for (i = 0; i < issue_rate; i++)
     {
-      dep_link_t link;
+      sd_iterator_def sd_it;
+      dep_t dep;
       rtx insn = group_insns[i];
 
       if (!insn)
        continue;
 
-      FOR_EACH_DEP_LINK (link, INSN_FORW_DEPS (insn))
+      FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
        {
-         dep_t dep = DEP_LINK_DEP (link);
          rtx next = DEP_CON (dep);
 
          if (next == next_insn
@@ -18884,8 +19747,14 @@ rs6000_handle_altivec_attribute (tree *node,
    elements; we must teach the compiler how to mangle them.  */
 
 static const char *
-rs6000_mangle_fundamental_type (tree type)
+rs6000_mangle_type (const_tree type)
 {
+  type = TYPE_MAIN_VARIANT (type);
+
+  if (TREE_CODE (type) != VOID_TYPE && TREE_CODE (type) != BOOLEAN_TYPE
+      && TREE_CODE (type) != INTEGER_TYPE && TREE_CODE (type) != REAL_TYPE)
+    return NULL;
+
   if (type == bool_char_type_node) return "U6__boolc";
   if (type == bool_short_type_node) return "U6__bools";
   if (type == pixel_type_node) return "u7__pixel";
@@ -19008,7 +19877,7 @@ rs6000_handle_struct_attribute (tree *node, tree name,
 }
 
 static bool
-rs6000_ms_bitfield_layout_p (tree record_type)
+rs6000_ms_bitfield_layout_p (const_tree record_type)
 {
   return (TARGET_USE_MS_BITFIELD_LAYOUT &&
           !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
@@ -19109,8 +19978,18 @@ rs6000_elf_encode_section_info (tree decl, rtx rtl, int first)
     }
 }
 
+static inline bool
+compare_section_name (const char *section, const char *template)
+{
+  int len;
+
+  len = strlen (template);
+  return (strncmp (section, template, len) == 0
+         && (section[len] == 0 || section[len] == '.'));
+}
+
 bool
-rs6000_elf_in_small_data_p (tree decl)
+rs6000_elf_in_small_data_p (const_tree decl)
 {
   if (rs6000_sdata == SDATA_NONE)
     return false;
@@ -19126,10 +20005,12 @@ rs6000_elf_in_small_data_p (tree decl)
   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
     {
       const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
-      if (strcmp (section, ".sdata") == 0
-         || strcmp (section, ".sdata2") == 0
-         || strcmp (section, ".sbss") == 0
-         || strcmp (section, ".sbss2") == 0
+      if (compare_section_name (section, ".sdata")
+         || compare_section_name (section, ".sdata2")
+         || compare_section_name (section, ".gnu.linkonce.s")
+         || compare_section_name (section, ".sbss")
+         || compare_section_name (section, ".sbss2")
+         || compare_section_name (section, ".gnu.linkonce.sb")
          || strcmp (section, ".PPC.EMB.sdata0") == 0
          || strcmp (section, ".PPC.EMB.sbss0") == 0)
        return true;
@@ -19154,7 +20035,7 @@ rs6000_elf_in_small_data_p (tree decl)
 /* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  */
 
 static bool
-rs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x)
+rs6000_use_blocks_for_constant_p (enum machine_mode mode, const_rtx x)
 {
   return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode);
 }
@@ -19740,8 +20621,9 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
 static void
 rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
 {
-  fprintf (asm_out_file, "\t.csect %s[RO],3\n",
-          *(const char *const *) directive);
+  fprintf (asm_out_file, "\t.csect %s[RO],%s\n",
+          *(const char *const *) directive,
+          XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* Likewise for read-write sections.  */
@@ -19749,8 +20631,9 @@ rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
 static void
 rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
 {
-  fprintf (asm_out_file, "\t.csect %s[RW],3\n",
-          *(const char *const *) directive);
+  fprintf (asm_out_file, "\t.csect %s[RW],%s\n",
+          *(const char *const *) directive,
+          XCOFF_CSECT_DEFAULT_ALIGNMENT_STR);
 }
 
 /* A get_unnamed_section callback, used for switching to toc_section.  */
@@ -20186,10 +21069,15 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
        *total += COSTS_N_INSNS (2);
       return false;
 
+    case CTZ:
     case FFS:
       *total = COSTS_N_INSNS (4);
       return false;
 
+    case POPCOUNT:
+      *total = COSTS_N_INSNS (6);
+      return false;
+
     case NOT:
       if (outer_code == AND || outer_code == IOR || outer_code == XOR)
        {
@@ -20199,6 +21087,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
       /* FALLTHRU */
 
     case AND:
+    case CLZ:
     case IOR:
     case XOR:
     case ZERO_EXTRACT:
@@ -20390,11 +21279,36 @@ rs6000_memory_move_cost (enum machine_mode mode, enum reg_class class,
     return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
 }
 
+/* Returns a code for a target-specific builtin that implements
+   reciprocal of the function, or NULL_TREE if not available.  */
+
+static tree
+rs6000_builtin_reciprocal (unsigned int fn, bool md_fn,
+                          bool sqrt ATTRIBUTE_UNUSED)
+{
+  if (! (TARGET_RECIP && TARGET_PPC_GFXOPT && !optimize_size
+        && flag_finite_math_only && !flag_trapping_math
+        && flag_unsafe_math_optimizations))
+    return NULL_TREE;
+
+  if (md_fn)
+    return NULL_TREE;
+  else
+    switch (fn)
+      {
+      case BUILT_IN_SQRTF:
+       return rs6000_builtin_decls[RS6000_BUILTIN_RSQRTF];
+
+      default:
+       return NULL_TREE;
+      }
+}
+
 /* Newton-Raphson approximation of single-precision floating point divide n/d.
    Assumes no trapping math and finite arguments.  */
 
 void
-rs6000_emit_swdivsf (rtx res, rtx n, rtx d)
+rs6000_emit_swdivsf (rtx dst, rtx n, rtx d)
 {
   rtx x0, e0, e1, y1, u0, v0, one;
 
@@ -20429,8 +21343,8 @@ rs6000_emit_swdivsf (rtx res, rtx n, rtx d)
   emit_insn (gen_rtx_SET (VOIDmode, v0,
                          gen_rtx_MINUS (SFmode, n,
                                         gen_rtx_MULT (SFmode, d, u0))));
-  /* res = u0 + v0 * y1 */
-  emit_insn (gen_rtx_SET (VOIDmode, res,
+  /* dst = u0 + v0 * y1 */
+  emit_insn (gen_rtx_SET (VOIDmode, dst,
                          gen_rtx_PLUS (SFmode,
                                        gen_rtx_MULT (SFmode, v0, y1), u0)));
 }
@@ -20439,7 +21353,7 @@ rs6000_emit_swdivsf (rtx res, rtx n, rtx d)
    Assumes no trapping math and finite arguments.  */
 
 void
-rs6000_emit_swdivdf (rtx res, rtx n, rtx d)
+rs6000_emit_swdivdf (rtx dst, rtx n, rtx d)
 {
   rtx x0, e0, e1, e2, y1, y2, y3, u0, v0, one;
 
@@ -20487,13 +21401,97 @@ rs6000_emit_swdivdf (rtx res, rtx n, rtx d)
   emit_insn (gen_rtx_SET (VOIDmode, v0,
                          gen_rtx_MINUS (DFmode, n,
                                         gen_rtx_MULT (DFmode, d, u0))));
-  /* res = u0 + v0 * y3 */
-  emit_insn (gen_rtx_SET (VOIDmode, res,
+  /* dst = u0 + v0 * y3 */
+  emit_insn (gen_rtx_SET (VOIDmode, dst,
                          gen_rtx_PLUS (DFmode,
                                        gen_rtx_MULT (DFmode, v0, y3), u0)));
 }
 
 
+/* Newton-Raphson approximation of single-precision floating point rsqrt.
+   Assumes no trapping math and finite arguments.  */
+
+void
+rs6000_emit_swrsqrtsf (rtx dst, rtx src)
+{
+  rtx x0, x1, x2, y1, u0, u1, u2, v0, v1, v2, t0,
+    half, one, halfthree, c1, cond, label;
+
+  x0 = gen_reg_rtx (SFmode);
+  x1 = gen_reg_rtx (SFmode);
+  x2 = gen_reg_rtx (SFmode);
+  y1 = gen_reg_rtx (SFmode);
+  u0 = gen_reg_rtx (SFmode);
+  u1 = gen_reg_rtx (SFmode);
+  u2 = gen_reg_rtx (SFmode);
+  v0 = gen_reg_rtx (SFmode);
+  v1 = gen_reg_rtx (SFmode);
+  v2 = gen_reg_rtx (SFmode);
+  t0 = gen_reg_rtx (SFmode);
+  halfthree = gen_reg_rtx (SFmode);
+  cond = gen_rtx_REG (CCFPmode, CR1_REGNO);
+  label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+
+  /* check 0.0, 1.0, NaN, Inf by testing src * src = src */
+  emit_insn (gen_rtx_SET (VOIDmode, t0,
+                         gen_rtx_MULT (SFmode, src, src)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, cond,
+                         gen_rtx_COMPARE (CCFPmode, t0, src)));
+  c1 = gen_rtx_EQ (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (c1, label);
+
+  half = force_reg (SFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconsthalf, SFmode));
+  one = force_reg (SFmode, CONST_DOUBLE_FROM_REAL_VALUE (dconst1, SFmode));
+
+  /* halfthree = 1.5 = 1.0 + 0.5 */
+  emit_insn (gen_rtx_SET (VOIDmode, halfthree,
+                         gen_rtx_PLUS (SFmode, one, half)));
+
+  /* x0 = rsqrt estimate */
+  emit_insn (gen_rtx_SET (VOIDmode, x0,
+                         gen_rtx_UNSPEC (SFmode, gen_rtvec (1, src),
+                                         UNSPEC_RSQRT)));
+
+  /* y1 = 0.5 * src = 1.5 * src - src -> fewer constants */
+  emit_insn (gen_rtx_SET (VOIDmode, y1,
+                         gen_rtx_MINUS (SFmode,
+                                        gen_rtx_MULT (SFmode, src, halfthree),
+                                        src)));
+
+  /* x1 = x0 * (1.5 - y1 * (x0 * x0)) */
+  emit_insn (gen_rtx_SET (VOIDmode, u0,
+                         gen_rtx_MULT (SFmode, x0, x0)));
+  emit_insn (gen_rtx_SET (VOIDmode, v0,
+                         gen_rtx_MINUS (SFmode,
+                                        halfthree,
+                                        gen_rtx_MULT (SFmode, y1, u0))));
+  emit_insn (gen_rtx_SET (VOIDmode, x1,
+                         gen_rtx_MULT (SFmode, x0, v0)));
+
+  /* x2 = x1 * (1.5 - y1 * (x1 * x1)) */
+  emit_insn (gen_rtx_SET (VOIDmode, u1,
+                         gen_rtx_MULT (SFmode, x1, x1)));
+  emit_insn (gen_rtx_SET (VOIDmode, v1,
+                         gen_rtx_MINUS (SFmode,
+                                        halfthree,
+                                        gen_rtx_MULT (SFmode, y1, u1))));
+  emit_insn (gen_rtx_SET (VOIDmode, x2,
+                         gen_rtx_MULT (SFmode, x1, v1)));
+
+  /* dst = x2 * (1.5 - y1 * (x2 * x2)) */
+  emit_insn (gen_rtx_SET (VOIDmode, u2,
+                         gen_rtx_MULT (SFmode, x2, x2)));
+  emit_insn (gen_rtx_SET (VOIDmode, v2,
+                         gen_rtx_MINUS (SFmode,
+                                        halfthree,
+                                        gen_rtx_MULT (SFmode, y1, u2))));
+  emit_insn (gen_rtx_SET (VOIDmode, dst,
+                         gen_rtx_MULT (SFmode, x2, v2)));
+
+  emit_label (XEXP (label, 0));
+}
+
 /* Emit popcount intrinsic on TARGET_POPCNTB targets.  DST is the
    target, and SRC is the argument operand.  */
 
@@ -20631,7 +21629,7 @@ rs6000_complex_function_value (enum machine_mode mode)
    fp1, unless -msoft-float.  */
 
 rtx
-rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
+rs6000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode;
   unsigned int regno;
@@ -20695,29 +21693,9 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
       || POINTER_TYPE_P (valtype))
     mode = TARGET_32BIT ? SImode : DImode;
 
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS)
-       {
-         switch (mode)
-           {
-           default:
-             gcc_unreachable ();
-           case SDmode:
-             regno = GP_ARG_RETURN;
-             break;
-           case DDmode:
-             regno = FP_ARG_RETURN;
-             break;
-           case TDmode:
-             /* Use f2:f3 specified by the ABI.  */
-             regno = FP_ARG_RETURN + 1;
-             break;
-           }
-       }
-      else
-       regno = GP_ARG_RETURN;
-    }
+  if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
+    /* _Decimal128 must use an even/odd register pair.  */
+    regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
   else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
   else if (TREE_CODE (valtype) == COMPLEX_TYPE
@@ -20728,8 +21706,8 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
           && ALTIVEC_VECTOR_MODE (mode))
     regno = ALTIVEC_ARG_RETURN;
   else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
-          && (mode == DFmode || mode == DCmode
-              || mode == TFmode || mode == TCmode))
+          && (mode == DFmode || mode == DDmode || mode == DCmode
+              || mode == TFmode || mode == TDmode || mode == TCmode))
     return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
@@ -20758,29 +21736,9 @@ rs6000_libcall_value (enum machine_mode mode)
                                      GEN_INT (4))));
     }
 
-  if (DECIMAL_FLOAT_MODE_P (mode))
-    {
-      if (TARGET_HARD_FLOAT && TARGET_FPRS)
-       {
-         switch (mode)
-           {
-           default:
-             gcc_unreachable ();
-           case SDmode:
-             regno = GP_ARG_RETURN;
-             break;
-           case DDmode:
-             regno = FP_ARG_RETURN;
-             break;
-           case TDmode:
-             /* Use f2:f3 specified by the ABI.  */
-             regno = FP_ARG_RETURN + 1;
-             break;
-           }
-       }
-      else
-       regno = GP_ARG_RETURN;
-    }
+  if (DECIMAL_FLOAT_MODE_P (mode) && TARGET_HARD_FLOAT && TARGET_FPRS)
+    /* _Decimal128 must use an even/odd register pair.  */
+    regno = (mode == TDmode) ? FP_ARG_RETURN + 1 : FP_ARG_RETURN;
   else if (SCALAR_FLOAT_MODE_P (mode)
           && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
@@ -20790,8 +21748,8 @@ rs6000_libcall_value (enum machine_mode mode)
   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
-          && (mode == DFmode || mode == DCmode
-              || mode == TFmode || mode == TCmode))
+          && (mode == DFmode || mode == DDmode || mode == DCmode
+              || mode == TFmode || mode == TDmode || mode == TCmode))
     return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
@@ -20834,7 +21792,7 @@ rs6000_initial_elimination_offset (int from, int to)
 /* Return true if TYPE is a SPE or AltiVec opaque type.  */
 
 static bool
-rs6000_is_opaque_type (tree type)
+rs6000_is_opaque_type (const_tree type)
 {
   return (type == opaque_V2SI_type_node
              || type == opaque_V2SF_type_node
@@ -20849,7 +21807,8 @@ rs6000_dwarf_register_span (rtx reg)
 
   if (TARGET_SPE
       && (SPE_VECTOR_MODE (GET_MODE (reg))
-         || (TARGET_E500_DOUBLE && GET_MODE (reg) == DFmode)))
+         || (TARGET_E500_DOUBLE
+             && (GET_MODE (reg) == DFmode || GET_MODE (reg) == DDmode))))
     ;
   else
     return NULL_RTX;
@@ -20949,6 +21908,9 @@ static bool
 rs6000_vector_mode_supported_p (enum machine_mode mode)
 {
 
+  if (TARGET_PAIRED_FLOAT && PAIRED_VECTOR_MODE (mode))
+    return true;
+
   if (TARGET_SPE && SPE_VECTOR_MODE (mode))
     return true;
 
@@ -20961,7 +21923,7 @@ rs6000_vector_mode_supported_p (enum machine_mode mode)
 
 /* Target hook for invalid_arg_for_unprototyped_fn. */
 static const char *
-invalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
+invalid_arg_for_unprototyped_fn (const_tree typelist, const_tree funcdecl, const_tree val)
 {
   return (!rs6000_darwin64_abi
          && typelist == 0