OSDN Git Service

* config/rs6000/rs6000.c (rs6000_emit_epilogue): Correct
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index d80d061..0415e44 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"
@@ -290,6 +289,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 +313,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 +332,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 +351,10 @@ struct processor_costs rios1_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (19),   /* ddiv */
+  128,
+  64,                  /* l1 cache */
+  512,                 /* l2 cache */
+  0,                   /* streams */
 };
 
 /* Instruction costs on RIOS2 processors.  */
@@ -354,6 +370,10 @@ struct processor_costs rios2_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  256,
+  256,                 /* l1 cache */
+  1024,                        /* l2 cache */
+  0,                   /* streams */
 };
 
 /* Instruction costs on RS64A processors.  */
@@ -369,6 +389,10 @@ struct processor_costs rs64a_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (31),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  128,
+  128,                 /* l1 cache */
+  2048,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on MPCCORE processors.  */
@@ -384,6 +408,10 @@ struct processor_costs mpccore_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (10),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  32,
+  4,                   /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC403 processors.  */
@@ -399,6 +427,10 @@ struct processor_costs ppc403_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
+  32,
+  4,                   /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC405 processors.  */
@@ -414,6 +446,10 @@ struct processor_costs ppc405_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
+  32,
+  16,                  /* l1 cache */
+  128,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC440 processors.  */
@@ -429,6 +465,10 @@ struct processor_costs ppc440_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC601 processors.  */
@@ -444,6 +484,10 @@ struct processor_costs ppc601_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC603 processors.  */
@@ -459,6 +503,10 @@ struct processor_costs ppc603_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
+  32,
+  8,                   /* l1 cache */
+  64,                  /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC604 processors.  */
@@ -474,6 +522,10 @@ struct processor_costs ppc604_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  32,
+  16,                  /* l1 cache */
+  512,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC604e processors.  */
@@ -489,6 +541,10 @@ struct processor_costs ppc604e_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC620 processors.  */
@@ -504,6 +560,10 @@ struct processor_costs ppc620_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
+  128,
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC630 processors.  */
@@ -519,6 +579,10 @@ struct processor_costs ppc630_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (21),   /* ddiv */
+  128,
+  64,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on Cell processor.  */
@@ -535,6 +599,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,
+  32,                  /* l1 cache */
+  512,                 /* l2 cache */
+  6,                   /* streams */
 };
 
 /* Instruction costs on PPC750 and PPC7400 processors.  */
@@ -550,6 +618,10 @@ struct processor_costs ppc750_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  512,                 /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC7450 processors.  */
@@ -565,6 +637,10 @@ struct processor_costs ppc7450_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (21),   /* sdiv */
   COSTS_N_INSNS (35),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  1,                   /* streams */
 };
 
 /* Instruction costs on PPC8540 processors.  */
@@ -580,6 +656,10 @@ struct processor_costs ppc8540_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (29),   /* sdiv */
   COSTS_N_INSNS (29),   /* ddiv */
+  32,
+  32,                  /* l1 cache */
+  256,                 /* l2 cache */
+  1,                   /* prefetch streams /*/
 };
 
 /* Instruction costs on POWER4 and POWER5 processors.  */
@@ -595,6 +675,10 @@ struct processor_costs power4_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
+  128,
+  32,                  /* l1 cache */
+  1024,                        /* l2 cache */
+  8,                   /* prefetch streams /*/
 };
 
 /* Instruction costs on POWER6 processors.  */
@@ -610,13 +694,16 @@ struct processor_costs power6_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (13),   /* sdiv */
   COSTS_N_INSNS (16),   /* ddiv */
+  128,
+  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_maybe_dead (rtx);
 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);
@@ -631,7 +718,6 @@ static int toc_hash_eq (const void *, const void *);
 static int constant_pool_expr_1 (rtx, int *, int *);
 static bool constant_pool_expr_p (rtx);
 static bool legitimate_small_data_p (enum machine_mode, rtx);
-static bool legitimate_indexed_address_p (rtx, int);
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
 static bool rs6000_assemble_integer (rtx, unsigned int, int);
@@ -642,18 +728,19 @@ 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);
 static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
                                    tree);
 static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
-static bool rs6000_return_in_memory (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);
@@ -666,7 +753,7 @@ 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);
 #if TARGET_XCOFF
 static void rs6000_xcoff_asm_output_anchor (rtx);
 static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
@@ -712,12 +799,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 (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 +816,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 +857,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 +878,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);
@@ -805,7 +900,7 @@ static void rs6000_darwin_file_start (void);
 
 static tree rs6000_build_builtin_va_list (void);
 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,
@@ -985,14 +1080,17 @@ static const char alt_reg_names[][8] =
 #undef TARGET_VECTORIZE_BUILTIN_CONVERSION
 #define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
 
+#undef TARGET_VECTOR_ALIGNMENT_REACHABLE
+#define TARGET_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable
+
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
 
 #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
@@ -1009,7 +1107,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
@@ -1034,9 +1132,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
@@ -1050,7 +1148,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
@@ -1116,6 +1214,9 @@ 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
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -1133,11 +1234,14 @@ 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))
@@ -1295,11 +1399,9 @@ rs6000_override_options (const char *default_cpu)
         {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"8540", PROCESSOR_PPC8540,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
+        {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         /* 8548 has a dummy entry for now.  */
-        {"8548", PROCESSOR_PPC8540,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
+        {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
          POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
@@ -1726,6 +1828,16 @@ 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);
 }
 
 /* Implement targetm.vectorize.builtin_mask_for_load.  */
@@ -1808,6 +1920,37 @@ rs6000_builtin_mul_widen_odd (tree type)
     }
 }
 
+
+/* Return true iff, data reference of TYPE can reach vector alignment (16)
+   after applying N number of iterations.  This routine does not determine
+   how may iterations are required to reach desired alignment.  */
+
+static bool
+rs6000_vector_alignment_reachable (const_tree type ATTRIBUTE_UNUSED, bool is_packed)
+{
+  if (is_packed)
+    return false;
+
+  if (TARGET_32BIT)
+    {
+      if (rs6000_alignment_flags == MASK_ALIGN_NATURAL)
+        return true;
+
+      if (rs6000_alignment_flags ==  MASK_ALIGN_POWER)
+        return true;
+
+      return false;
+    }
+  else
+    {
+      if (TARGET_MACHO)
+        return false;
+
+      /* Assuming that all other types are naturally aligned. CHECKME!  */
+      return true;
+    }
+}
+
 /* Handle generic options of the form -mfoo=yes/no.
    NAME is the option name.
    VALUE is the option value.
@@ -2207,6 +2350,18 @@ rs6000_file_start (void)
        putc ('\n', file);
     }
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+  if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
+    {
+      fprintf (file, "\t.gnu_attribute 4, %d\n",
+              (TARGET_HARD_FLOAT && TARGET_FPRS) ? 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))
     {
       switch_to_section (toc_section);
@@ -2561,6 +2716,59 @@ 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);
+}
+
 /* Initialize vector TARGET to VALS.  */
 
 void
@@ -3052,6 +3260,11 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     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.
+         Allow any offset when not strict before reload.  */
+      if (TARGET_PAIRED_FLOAT)
+        return !strict;
       /* SPE vector modes.  */
       return SPE_CONST_OFFSET_OK (offset);
 
@@ -3098,7 +3311,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
   return (offset < 0x10000) && (offset + extra < 0x10000);
 }
 
-static bool
+bool
 legitimate_indexed_address_p (rtx x, int strict)
 {
   rtx op0, op1;
@@ -3221,7 +3434,10 @@ 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)
+          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                     || mode == DImode))))
     {
       HOST_WIDE_INT high_int, low_int;
       rtx sum;
@@ -3444,25 +3660,22 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                rs6000_emit_move (got, gsym, Pmode);
              else
                {
-                 rtx tempLR, tmp3, mem;
+                 rtx tmp3, mem;
                  rtx first, last;
 
-                 tempLR = gen_reg_rtx (Pmode);
                  tmp1 = gen_reg_rtx (Pmode);
                  tmp2 = gen_reg_rtx (Pmode);
                  tmp3 = gen_reg_rtx (Pmode);
                  mem = gen_const_mem (Pmode, tmp1);
 
-                 first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
-                 emit_move_insn (tmp1, tempLR);
+                 first = emit_insn (gen_load_toc_v4_PIC_1b (gsym));
+                 emit_move_insn (tmp1,
+                                 gen_rtx_REG (Pmode, LR_REGNO));
                  emit_move_insn (tmp2, mem);
                  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
                  last = emit_move_insn (got, tmp3);
                  set_unique_reg_note (last, REG_EQUAL, gsym);
-                 REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
-                                                        REG_NOTES (first));
-                 REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
-                                                       REG_NOTES (last));
+                 maybe_encapsulate_block (first, last, gsym);
                }
            }
        }
@@ -3832,6 +4045,24 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && (TARGET_POWERPC64 || mode != DImode)
       && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
+  if (GET_CODE (x) == PRE_MODIFY
+      && mode != TImode
+      && mode != TFmode
+      && mode != TDmode
+      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+         || TARGET_POWERPC64
+         || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
+      && (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_UPDATE
+      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
+      && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), reg_ok_strict)
+         || legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict))
+      && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
+    return 1;
   if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
     return 1;
   return 0;
@@ -3864,7 +4095,10 @@ rs6000_mode_dependent_address (rtx addr)
     case LO_SUM:
       return true;
 
-    /* Auto-increment cases are now treated generically in recog.c.  */
+    case PRE_INC:
+    case PRE_DEC:
+    case PRE_MODIFY:
+      return TARGET_UPDATE;
 
     default:
       break;
@@ -3992,9 +4226,15 @@ rs6000_conditional_register_usage (void)
   if (TARGET_SPE)
     {
       global_regs[SPEFSCR_REGNO] = 1;
-      fixed_regs[FIXED_SCRATCH]
-       = call_used_regs[FIXED_SCRATCH]
-       = call_really_used_regs[FIXED_SCRATCH] = 1;
+      /* We used to use r14 as FIXED_SCRATCH to address SPE 64-bit
+         registers in prologues and epilogues.  We no longer use r14
+         for FIXED_SCRATCH, but we're keeping r14 out of the allocation
+         pool for link-compatibility with older versions of GCC.  Once
+         "old" code has died out, we can return r14 to the allocation
+         pool.  */
+      fixed_regs[14]
+       = call_used_regs[14]
+       = call_really_used_regs[14] = 1;
     }
 
   if (! TARGET_ALTIVEC)
@@ -4032,7 +4272,7 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
       return dest;
 
     case SImode:
-      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
+      result = !can_create_pseudo_p () ? dest : gen_reg_rtx (SImode);
 
       emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (result),
                              GEN_INT (INTVAL (source)
@@ -4251,7 +4491,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       return;
     }
 
-  if (!no_new_pseudos && GET_CODE (operands[0]) == MEM
+  if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM
       && !gpc_reg_operand (operands[1], mode))
     operands[1] = force_reg (mode, operands[1]);
 
@@ -4274,7 +4514,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
        {
          rtx newreg;
-         newreg = (no_new_pseudos ? copy_rtx (operands[1])
+         newreg = (!can_create_pseudo_p () ? copy_rtx (operands[1])
                    : gen_reg_rtx (mode));
          emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
          operands[1] = newreg;
@@ -4401,7 +4641,9 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
          && GET_CODE (operands[1]) != HIGH
          && GET_CODE (operands[1]) != CONST_INT)
        {
-         rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
+         rtx target = (!can_create_pseudo_p ()
+                       ? operands[0]
+                       : gen_reg_rtx (mode));
 
          /* If this is a function address on -mcall-aixdesc,
             convert it to the address of the descriptor.  */
@@ -4596,7 +4838,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.  */
@@ -4718,7 +4960,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);
@@ -4736,7 +4978,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
@@ -5046,8 +5288,9 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              || mode == DDmode || mode == TDmode
              || (mode == TFmode && !TARGET_IEEEQUAD)))
        {
-         /* _Decimal128 must use an even/odd register pair.  */
-         if (mode == TDmode && cum->fregno % 2)
+         /* _Decimal128 must use an even/odd register pair.  This assumes
+            that the register number is odd when fregno is odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
            cum->fregno++;
 
          if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
@@ -5110,7 +5353,14 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       if (SCALAR_FLOAT_MODE_P (mode)
          && mode != SDmode
          && TARGET_HARD_FLOAT && TARGET_FPRS)
-       cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+       {
+         /* _Decimal128 must be passed in an even/odd float register pair.
+            This assumes that the register number is odd when fregno is
+            odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
+           cum->fregno++;
+         cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+       }
 
       if (TARGET_DEBUG_ARG)
        {
@@ -5287,7 +5537,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)
 {
@@ -5357,7 +5607,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];
@@ -5602,8 +5852,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              || (mode == TFmode && !TARGET_IEEEQUAD)
              || mode == DDmode || mode == TDmode))
        {
-         /* _Decimal128 must use an even/odd register pair.  */
-         if (mode == TDmode && cum->fregno % 2)
+         /* _Decimal128 must use an even/odd register pair.  This assumes
+            that the register number is odd when fregno is odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
            cum->fregno++;
 
          if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
@@ -5637,6 +5888,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       int align_words = rs6000_parm_start (mode, type, cum->words);
 
+      /* _Decimal128 must be passed in an even/odd float register pair.
+        This assumes that the register number is odd when fregno is odd.  */
+      if (mode == TDmode && (cum->fregno % 2) == 1)
+       cum->fregno++;
+
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
          rtx rvec[GP_ARG_NUM_REG + 1];
@@ -5809,7 +6065,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)
@@ -5915,7 +6171,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;
@@ -6174,8 +6431,8 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the overflow area.  */
   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
   if (words != 0)
-    t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t,
-               build_int_cst (NULL_TREE, words * UNITS_PER_WORD));
+    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), t,
+               size_int (words * UNITS_PER_WORD));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovf), ovf, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6191,8 +6448,8 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the register save area.  */
   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
   if (cfun->machine->varargs_save_offset)
-    t = build2 (PLUS_EXPR, TREE_TYPE (sav), t,
-               build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset));
+    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (sav), t,
+               size_int (cfun->machine->varargs_save_offset));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (sav), sav, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6311,7 +6568,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
@@ -6331,12 +6588,13 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 
       t = sav;
       if (sav_ofs)
-       t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (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 = build1 (CONVERT_EXPR, integer_type_node, u);
-      u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
-      t = build2 (PLUS_EXPR, ptr_type_node, t, u);
+      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);
 
       t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
       gimplify_and_add (t, pre_p);
@@ -6362,16 +6620,18 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   t = ovf;
   if (align != 1)
     {
-      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+      t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+      t = fold_convert (sizetype, t);
       t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
-                 build_int_cst (NULL_TREE, -align));
+                 size_int (-align));
+      t = fold_convert (TREE_TYPE (ovf), t);
     }
   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
 
   u = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
   gimplify_and_add (u, pre_p);
 
-  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovf), ovf, t);
   gimplify_and_add (t, pre_p);
 
@@ -6407,7 +6667,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 ();
@@ -6461,6 +6721,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).  */
@@ -6722,6 +6992,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 },
@@ -6935,6 +7216,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[] =
@@ -7023,7 +7313,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
@@ -7258,6 +7554,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;
@@ -7337,6 +7679,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);
@@ -7429,7 +7812,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);
@@ -7550,13 +7936,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)
       {
@@ -7709,8 +8095,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);
@@ -7839,13 +8225,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,
@@ -7884,6 +8270,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[] =
@@ -8050,6 +8469,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;
@@ -8220,11 +8711,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)
     {
@@ -8289,8 +8789,15 @@ 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;
@@ -8305,7 +8812,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);
@@ -8416,12 +8923,39 @@ 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.  */
@@ -8678,10 +9212,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;
 
@@ -8862,12 +9452,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;
@@ -8905,7 +9495,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;
@@ -9036,9 +9626,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,
@@ -9071,11 +9666,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,
@@ -9089,10 +9690,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);
@@ -9233,7 +9838,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;
@@ -9279,6 +9884,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 ();
            }
@@ -9387,8 +9995,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;
@@ -9527,7 +10138,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)
@@ -9572,7 +10188,6 @@ rs6000_init_libfuncs (void)
            set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
            set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
            set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
-           set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
 
            set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
            set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
@@ -9583,6 +10198,9 @@ rs6000_init_libfuncs (void)
            set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
            set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
          }
+
+       if (!(TARGET_HARD_FLOAT && TARGET_FPRS))
+         set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
       }
     else
       {
@@ -9663,6 +10281,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;
 
@@ -9681,10 +10301,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;
@@ -9774,6 +10399,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]
@@ -10443,8 +11074,9 @@ rs6000_got_register (rtx value ATTRIBUTE_UNUSED)
   /* The second flow pass currently (June 1999) can't update
      regs_ever_live without disturbing other parts of the compiler, so
      update it here to make the prolog/epilogue code happy.  */
-  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
-    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
+  if (!can_create_pseudo_p ()
+      && !df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))
+    df_set_regs_ever_live (RS6000_PIC_OFFSET_TABLE_REGNUM, true);
 
   current_function_uses_pic_offset_table = 1;
 
@@ -10811,6 +11443,9 @@ print_operand (FILE *file, rtx x, int code)
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0),
                                           UNITS_PER_WORD));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0),
+                                          UNITS_PER_WORD));
          else
            output_address (XEXP (adjust_address_nv (x, SImode,
                                                     UNITS_PER_WORD),
@@ -10980,10 +11615,10 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'T':
       /* Print the symbolic name of a branch target register.  */
-      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
-                                 && REGNO (x) != COUNT_REGISTER_REGNUM))
+      if (GET_CODE (x) != REG || (REGNO (x) != LR_REGNO
+                                 && REGNO (x) != CTR_REGNO))
        output_operand_lossage ("invalid %%T value");
-      else if (REGNO (x) == LINK_REGISTER_REGNUM)
+      else if (REGNO (x) == LR_REGNO)
        fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
       else
        fputs ("ctr", file);
@@ -11011,7 +11646,8 @@ print_operand (FILE *file, rtx x, int code)
       /* Print `u' if this has an auto-increment or auto-decrement.  */
       if (GET_CODE (x) == MEM
          && (GET_CODE (XEXP (x, 0)) == PRE_INC
-             || GET_CODE (XEXP (x, 0)) == PRE_DEC))
+             || GET_CODE (XEXP (x, 0)) == PRE_DEC
+             || GET_CODE (XEXP (x, 0)) == PRE_MODIFY))
        putc ('u', file);
       return;
 
@@ -11098,7 +11734,9 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'X':
       if (GET_CODE (x) == MEM
-         && legitimate_indexed_address_p (XEXP (x, 0), 0))
+         && (legitimate_indexed_address_p (XEXP (x, 0), 0)
+             || (GET_CODE (XEXP (x, 0)) == PRE_MODIFY
+                 && legitimate_indexed_address_p (XEXP (XEXP (x, 0), 1), 0))))
        putc ('x', file);
       return;
 
@@ -11111,6 +11749,8 @@ print_operand (FILE *file, rtx x, int code)
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -11158,6 +11798,8 @@ print_operand (FILE *file, rtx x, int code)
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -11238,6 +11880,8 @@ print_operand (FILE *file, rtx x, int code)
          else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
            fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
                     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (XEXP (XEXP (x, 0), 1));
          else
            output_address (XEXP (x, 0));
        }
@@ -12082,7 +12726,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));
 
@@ -12132,7 +12776,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)
@@ -12542,14 +13186,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),
@@ -12562,14 +13208,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)
        {
@@ -13098,7 +13744,7 @@ first_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 13; first_reg <= 31; first_reg++)
-    if (regs_ever_live[first_reg]
+    if (df_regs_ever_live_p (first_reg)
        && (! call_used_regs[first_reg]
            || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
                && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
@@ -13125,7 +13771,7 @@ first_fp_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
-    if (regs_ever_live[first_reg])
+    if (df_regs_ever_live_p (first_reg))
       break;
 
   return first_reg;
@@ -13151,7 +13797,7 @@ first_altivec_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       break;
 
   return i;
@@ -13175,7 +13821,7 @@ compute_vrsave_mask (void)
 
   /* First, find out if we use _any_ altivec registers.  */
   for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       mask |= ALTIVEC_REG_BIT (i);
 
   if (mask == 0)
@@ -13367,6 +14013,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));
@@ -13386,14 +14033,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
@@ -13436,13 +14088,13 @@ rs6000_stack_info (void)
       || rs6000_ra_ever_killed ())
     {
       info_ptr->lr_save_p = 1;
-      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
+      df_set_regs_ever_live (LR_REGNO, true);
     }
 
   /* Determine if we need to save the condition code registers.  */
-  if (regs_ever_live[CR2_REGNO]
-      || regs_ever_live[CR3_REGNO]
-      || regs_ever_live[CR4_REGNO])
+  if (df_regs_ever_live_p (CR2_REGNO)
+      || df_regs_ever_live_p (CR3_REGNO)
+      || df_regs_ever_live_p (CR4_REGNO))
     {
       info_ptr->cr_save_p = 1;
       if (DEFAULT_ABI == ABI_V4)
@@ -13481,7 +14133,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;
 
@@ -13860,7 +14512,7 @@ rs6000_return_addr (int count, rtx frame)
     }
 
   cfun->machine->ra_need_lr = 1;
-  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
+  return get_hard_reg_initial_val (Pmode, LR_REGNO);
 }
 
 /* Say whether a function is a candidate for sibcall handling or not.
@@ -13886,7 +14538,8 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
            }
        }
       if (DEFAULT_ABI == ABI_DARWIN
-         || (*targetm.binds_local_p) (decl))
+         || ((*targetm.binds_local_p) (decl)
+             && (DEFAULT_ABI != ABI_AIX || !DECL_EXTERNAL (decl))))
        {
          tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
 
@@ -13903,7 +14556,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.";
@@ -13945,7 +14598,7 @@ rs6000_ra_ever_killed (void)
   push_topmost_sequence ();
   top = get_insns ();
   pop_topmost_sequence ();
-  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+  reg = gen_rtx_REG (Pmode, LR_REGNO);
 
   for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
     {
@@ -13956,7 +14609,7 @@ rs6000_ra_ever_killed (void)
              if (!SIBLING_CALL_P (insn))
                return 1;
            }
-         else if (find_regno_note (insn, REG_INC, LINK_REGISTER_REGNUM))
+         else if (find_regno_note (insn, REG_INC, LR_REGNO))
            return 1;
          else if (set_of (reg, insn) != NULL_RTX
                   && !prologue_epilogue_contains (insn))
@@ -13966,15 +14619,6 @@ rs6000_ra_ever_killed (void)
   return 0;
 }
 \f
-/* Add a REG_MAYBE_DEAD note to the insn.  */
-static void
-rs6000_maybe_dead (rtx insn)
-{
-  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                       const0_rtx,
-                                       REG_NOTES (insn));
-}
-
 /* Emit instructions needed to load the TOC register.
    This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
    a constant pool; or for SVR4 -fpic.  */
@@ -13982,13 +14626,13 @@ rs6000_maybe_dead (rtx insn)
 void
 rs6000_emit_load_toc_table (int fromprolog)
 {
-  rtx dest, insn;
+  rtx dest;
   dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
 
   if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
     {
       char buf[30];
-      rtx lab, tmp1, tmp2, got, tempLR;
+      rtx lab, tmp1, tmp2, got;
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
       lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
@@ -14002,41 +14646,20 @@ rs6000_emit_load_toc_table (int fromprolog)
          tmp1 = gen_reg_rtx (Pmode);
          tmp2 = gen_reg_rtx (Pmode);
        }
-      tempLR = (fromprolog
-               ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-               : gen_reg_rtx (Pmode));
-      insn = emit_insn (gen_load_toc_v4_PIC_1 (tempLR, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_move_insn (tmp1, tempLR);
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_load_toc_v4_PIC_1 (lab));
+      emit_move_insn (tmp1,
+                            gen_rtx_REG (Pmode, LR_REGNO));
+      emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
+      emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
     }
   else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
     {
-      rtx tempLR = (fromprolog
-                   ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                   : gen_reg_rtx (Pmode));
-
-      insn = emit_insn (gen_load_toc_v4_pic_si (tempLR));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_move_insn (dest, tempLR);
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_load_toc_v4_pic_si ());
+      emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
     }
   else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
     {
       char buf[30];
-      rtx tempLR = (fromprolog
-                   ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                   : gen_reg_rtx (Pmode));
       rtx temp0 = (fromprolog
                   ? gen_rtx_REG (Pmode, 0)
                   : gen_reg_rtx (Pmode));
@@ -14051,25 +14674,22 @@ rs6000_emit_load_toc_table (int fromprolog)
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
          symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
 
-         rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
-                                                              symF)));
-         rs6000_maybe_dead (emit_move_insn (dest, tempLR));
-         rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
-                                                              symL,
-                                                              symF)));
+         emit_insn (gen_load_toc_v4_PIC_1 (symF));
+         emit_move_insn (dest,
+                         gen_rtx_REG (Pmode, LR_REGNO));
+         emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest, symL, symF));
        }
       else
        {
          rtx tocsym;
 
          tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
-         emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
-         emit_move_insn (dest, tempLR);
+         emit_insn (gen_load_toc_v4_PIC_1b (tocsym));
+         emit_move_insn (dest,
+                         gen_rtx_REG (Pmode, LR_REGNO));
          emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
        }
-      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_addsi3 (dest, temp0, dest));
     }
   else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
     {
@@ -14079,23 +14699,17 @@ rs6000_emit_load_toc_table (int fromprolog)
       ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
       realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
 
-      insn = emit_insn (gen_elf_high (dest, realsym));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_elf_low (dest, dest, realsym));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_elf_high (dest, realsym));
+      emit_insn (gen_elf_low (dest, dest, realsym));
     }
   else
     {
       gcc_assert (DEFAULT_ABI == ABI_AIX);
 
       if (TARGET_32BIT)
-       insn = emit_insn (gen_load_toc_aix_si (dest));
+       emit_insn (gen_load_toc_aix_si (dest));
       else
-       insn = emit_insn (gen_load_toc_aix_di (dest));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+       emit_insn (gen_load_toc_aix_di (dest));
     }
 }
 
@@ -14133,12 +14747,12 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
       emit_move_insn (tmp, operands[0]);
     }
   else
-    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
+    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)
@@ -14181,8 +14795,8 @@ uses_TOC (void)
 rtx
 create_TOC_reference (rtx symbol)
 {
-  if (no_new_pseudos)
-    regs_ever_live[TOC_REGISTER] = 1;
+  if (!can_create_pseudo_p ())
+    df_set_regs_ever_live (TOC_REGISTER, true);
   return gen_rtx_PLUS (Pmode,
           gen_rtx_REG (Pmode, TOC_REGISTER),
             gen_rtx_CONST (Pmode,
@@ -14620,6 +15234,20 @@ no_global_regs_above (int first_greg)
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
 
+/* Determine whether the gp REG is really used.  */
+
+static bool
+rs6000_reg_live_or_pic_offset_p (int reg)
+{
+  return ((df_regs_ever_live_p (reg)
+           && (!call_used_regs[reg]
+               || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+                   && TARGET_TOC && TARGET_MINIMAL_TOC)))
+          || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+              && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
+                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
+}
+
 /* Emit function prologue as insns.  */
 
 void
@@ -14701,7 +15329,7 @@ rs6000_emit_prologue (void)
       if (info->lr_save_p)
        {
          insn = emit_move_insn (reg0,
-                                gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+                                gen_rtx_REG (Pmode, LR_REGNO));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
 
@@ -14733,8 +15361,8 @@ rs6000_emit_prologue (void)
       p = rtvec_alloc (sz);
       j = 0;
       RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
-                                           gen_rtx_REG (Pmode,
-                                                        LINK_REGISTER_REGNUM));
+                                           gen_rtx_REG (SImode,
+                                                        LR_REGNO));
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
                                        gen_rtx_SYMBOL_REF (Pmode,
                                                            "*save_world"));
@@ -14803,83 +15431,25 @@ rs6000_emit_prologue (void)
       sp_offset = info->total_size;
     }
 
-  /* Save AltiVec registers if needed.  */
-  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
-    {
-      int i;
-
-      /* There should be a non inline version of this, for when we
-        are saving lots of vector registers.  */
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-         {
-           rtx areg, savereg, mem;
-           int offset;
-
-           offset = info->altivec_save_offset + sp_offset
-             + 16 * (i - info->first_altivec_reg_save);
-
-           savereg = gen_rtx_REG (V4SImode, i);
-
-           areg = gen_rtx_REG (Pmode, 0);
-           emit_move_insn (areg, GEN_INT (offset));
-
-           /* AltiVec addressing mode is [reg+reg].  */
-           mem = gen_frame_mem (V4SImode,
-                                gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
-
-           insn = emit_move_insn (mem, savereg);
-
-           rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                 areg, GEN_INT (offset));
-         }
-    }
-
-  /* VRSAVE is a bit vector representing which AltiVec registers
-     are used.  The OS uses this to determine which vector
-     registers to save on a context switch.  We need to save
-     VRSAVE on the stack frame, add whatever AltiVec registers we
-     used in this function, and do the corresponding magic in the
-     epilogue.  */
-
-  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && info->vrsave_mask != 0)
-    {
-      rtx reg, mem, vrsave;
-      int offset;
-
-      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
-        as frame_reg_rtx and r11 as the static chain pointer for
-        nested functions.  */
-      reg = gen_rtx_REG (SImode, 0);
-      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
-      if (TARGET_MACHO)
-       emit_insn (gen_get_vrsave_internal (reg));
-      else
-       emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
-
-      if (!WORLD_SAVE_P (info))
-       {
-          /* Save VRSAVE.  */
-          offset = info->vrsave_save_offset + sp_offset;
-          mem = gen_frame_mem (SImode,
-                              gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                            GEN_INT (offset)));
-          insn = emit_move_insn (mem, reg);
-       }
-
-      /* Include the registers in the mask.  */
-      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
-
-      insn = emit_insn (generate_set_vrsave (reg, info, 0));
-    }
-
   /* If we use the link register, get it into r0.  */
   if (!WORLD_SAVE_P (info) && info->lr_save_p)
     {
+      rtx addr, reg, mem;
+
       insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
-                            gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+                            gen_rtx_REG (Pmode, LR_REGNO));
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                              GEN_INT (info->lr_save_offset + sp_offset));
+      reg = gen_rtx_REG (Pmode, 0);
+      mem = gen_rtx_MEM (Pmode, addr);
+      /* This should not be of rs6000_sr_alias_set, because of
+        __builtin_return_address.  */
+
+      insn = emit_move_insn (mem, reg);
+      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                           NULL_RTX, NULL_RTX);
     }
 
   /* If we need to save CR, put it into r12.  */
@@ -14909,7 +15479,7 @@ rs6000_emit_prologue (void)
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-       if ((regs_ever_live[info->first_fp_reg_save+i]
+       if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
             && ! call_used_regs[info->first_fp_reg_save+i]))
          emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
                           info->first_fp_reg_save + i,
@@ -14926,7 +15496,7 @@ rs6000_emit_prologue (void)
 
       RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
                                          gen_rtx_REG (Pmode,
-                                                      LINK_REGISTER_REGNUM));
+                                                      LR_REGNO));
       sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
               info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
       alloc_rname = ggc_strdup (rname);
@@ -14972,59 +15542,99 @@ rs6000_emit_prologue (void)
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
+   else if (!WORLD_SAVE_P (info)
+            && TARGET_SPE_ABI
+            && info->spe_64bit_regs_used != 0
+            && info->first_gp_reg_save != 32)
+     {
+       int i;
+       rtx spe_save_area_ptr;
+       int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
+                                   && df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
+                                   && !call_used_regs[STATIC_CHAIN_REGNUM]);
+       /* Determine whether we can address all of the registers that need
+          to be saved with an offset from the stack pointer that fits in
+          the small const field for SPE memory instructions.  */
+       int spe_regs_addressable_via_sp
+         = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                               + (32 - info->first_gp_reg_save - 1) * reg_size);
+       int spe_offset;
+       if (spe_regs_addressable_via_sp)
+         {
+           spe_save_area_ptr = sp_reg_rtx;
+           spe_offset = info->spe_gp_save_offset + sp_offset;
+         }
+       else
+         {
+           /* Make r11 point to the start of the SPE save area.  We need
+              to be careful here if r11 is holding the static chain.  If
+              it is, then temporarily save it in r0.  We would use r0 as
+              our base register here, but using r0 as a base register in
+              loads and stores means something different from what we
+              would like.  */
+           if (using_static_chain_p)
+             {
+               rtx r0 = gen_rtx_REG (Pmode, 0);
+               gcc_assert (info->first_gp_reg_save > 11);
+               emit_move_insn (r0, gen_rtx_REG (Pmode, 11));
+             }
+           spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+           emit_insn (gen_addsi3 (spe_save_area_ptr, sp_reg_rtx,
+                                  GEN_INT (info->spe_gp_save_offset + sp_offset)));
+           spe_offset = 0;
+         }
+       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+         if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+           {
+             rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+             rtx offset, addr, mem;
+             /* We're doing all this to ensure that the offset fits into
+                the immediate offset of 'evstdd'.  */
+             gcc_assert (SPE_CONST_OFFSET_OK (reg_size * i + spe_offset));
+             offset = GEN_INT (reg_size * i + spe_offset);
+             addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+             mem = gen_rtx_MEM (V2SImode, addr);
+             insn = emit_move_insn (mem, reg);
+           
+             rs6000_frame_related (insn, spe_save_area_ptr,
+                                   info->spe_gp_save_offset
+                                   + sp_offset + reg_size * i,
+                                   offset, const0_rtx);
+           }
+       /* Move the static chain pointer back.  */
+       if (using_static_chain_p && !spe_regs_addressable_via_sp)
+         emit_move_insn (gen_rtx_REG (Pmode, 11), gen_rtx_REG (Pmode, 0));
+     }
   else if (!WORLD_SAVE_P (info))
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       if ((regs_ever_live[info->first_gp_reg_save + i]
-            && (!call_used_regs[info->first_gp_reg_save + i]
-                || (i + info->first_gp_reg_save
-                    == RS6000_PIC_OFFSET_TABLE_REGNUM
-                    && TARGET_TOC && TARGET_MINIMAL_TOC)))
-           || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
-         {
-           rtx addr, reg, mem;
-           reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-
-           if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-             {
-               int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-               rtx b;
-
-               if (!SPE_CONST_OFFSET_OK (offset))
-                 {
-                   b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                   emit_move_insn (b, GEN_INT (offset));
-                 }
-               else
-                 b = GEN_INT (offset);
-
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-               mem = gen_frame_mem (V2SImode, addr);
-               insn = emit_move_insn (mem, reg);
-
-               if (GET_CODE (b) == CONST_INT)
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       NULL_RTX, NULL_RTX);
-               else
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       b, GEN_INT (offset));
-             }
-           else
-             {
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                    GEN_INT (info->gp_save_offset
-                                             + sp_offset
-                                             + reg_size * i));
-               mem = gen_frame_mem (reg_mode, addr);
-
-               insn = emit_move_insn (mem, reg);
-               rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                     NULL_RTX, NULL_RTX);
-             }
-         }
+       if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx addr, reg, mem;
+            reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+
+            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                 GEN_INT (info->gp_save_offset
+                                          + sp_offset
+                                          + reg_size * i));
+            mem = gen_frame_mem (reg_mode, addr);
+
+            insn = emit_move_insn (mem, reg);
+            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                  NULL_RTX, NULL_RTX);
+          }
     }
 
   /* ??? There's no need to emit actual instructions here, but it's the
@@ -15062,21 +15672,6 @@ rs6000_emit_prologue (void)
        }
     }
 
-  /* Save lr if we used it.  */
-  if (!WORLD_SAVE_P (info) && info->lr_save_p)
-    {
-      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->lr_save_offset + sp_offset));
-      rtx reg = gen_rtx_REG (Pmode, 0);
-      rtx mem = gen_rtx_MEM (Pmode, addr);
-      /* This should not be of frame_alias_set, because of
-        __builtin_return_address.  */
-
-      insn = emit_move_insn (mem, reg);
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                           NULL_RTX, NULL_RTX);
-    }
-
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {
@@ -15111,7 +15706,19 @@ rs6000_emit_prologue (void)
      for which it was done previously.  */
   if (!WORLD_SAVE_P (info) && info->push_p
       && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
-    rs6000_emit_allocate_stack (info->total_size, FALSE);
+    {
+      if (info->total_size < 32767)
+      sp_offset = info->total_size;
+      else
+       frame_reg_rtx = frame_ptr_rtx;
+      rs6000_emit_allocate_stack (info->total_size,
+                                 (frame_reg_rtx != sp_reg_rtx
+                                  && ((info->altivec_size != 0)
+                                      || (info->vrsave_mask != 0)
+                                      )));
+      if (frame_reg_rtx != sp_reg_rtx)
+       rs6000_emit_stack_tie ();
+    }
 
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
@@ -15121,11 +15728,83 @@ rs6000_emit_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  /* Save AltiVec registers if needed.  Save here because the red zone does
+     not include AltiVec registers.  */
+  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+    {
+      int i;
+
+      /* There should be a non inline version of this, for when we
+         are saving lots of vector registers.  */
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+          {
+            rtx areg, savereg, mem;
+            int offset;
+
+            offset = info->altivec_save_offset + sp_offset
+              + 16 * (i - info->first_altivec_reg_save);
+
+            savereg = gen_rtx_REG (V4SImode, i);
+
+            areg = gen_rtx_REG (Pmode, 0);
+            emit_move_insn (areg, GEN_INT (offset));
+
+            /* AltiVec addressing mode is [reg+reg].  */
+            mem = gen_frame_mem (V4SImode,
+                                 gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+
+            insn = emit_move_insn (mem, savereg);
+
+            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                  areg, GEN_INT (offset));
+          }
+    }
+
+  /* VRSAVE is a bit vector representing which AltiVec registers
+     are used.  The OS uses this to determine which vector
+     registers to save on a context switch.  We need to save
+     VRSAVE on the stack frame, add whatever AltiVec registers we
+     used in this function, and do the corresponding magic in the
+     epilogue.  */
+
+  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0)
+    {
+      rtx reg, mem, vrsave;
+      int offset;
+
+      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
+         as frame_reg_rtx and r11 as the static chain pointer for
+         nested functions.  */
+      reg = gen_rtx_REG (SImode, 0);
+      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
+      if (TARGET_MACHO)
+        emit_insn (gen_get_vrsave_internal (reg));
+      else
+        emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
+
+      if (!WORLD_SAVE_P (info))
+        {
+          /* Save VRSAVE.  */
+          offset = info->vrsave_save_offset + sp_offset;
+          mem = gen_frame_mem (SImode,
+                               gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                             GEN_INT (offset)));
+          insn = emit_move_insn (mem, reg);
+        }
+
+      /* Include the registers in the mask.  */
+      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
+
+      insn = emit_insn (generate_set_vrsave (reg, info, 0));
+    }
+
   /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
   if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
       || (DEFAULT_ABI == ABI_V4
          && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
-         && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
+         && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM)))
     {
       /* If emit_load_toc_table will use the link register, we need to save
         it.  We use R12 for this purpose because emit_load_toc_table
@@ -15138,16 +15817,14 @@ rs6000_emit_prologue (void)
                                      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
       if (save_LR_around_toc_setup)
        {
-         rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+         rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
 
          insn = emit_move_insn (frame_ptr_rtx, lr);
-         rs6000_maybe_dead (insn);
          RTX_FRAME_RELATED_P (insn) = 1;
 
          rs6000_emit_load_toc_table (TRUE);
 
          insn = emit_move_insn (lr, frame_ptr_rtx);
-         rs6000_maybe_dead (insn);
          RTX_FRAME_RELATED_P (insn) = 1;
        }
       else
@@ -15158,22 +15835,21 @@ rs6000_emit_prologue (void)
   if (DEFAULT_ABI == ABI_DARWIN
       && flag_pic && current_function_uses_pic_offset_table)
     {
-      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+      rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
       rtx src = machopic_function_base_sym ();
 
       /* Save and restore LR locally around this call (in R0).  */
       if (!info->lr_save_p)
-       rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), lr));
+       emit_move_insn (gen_rtx_REG (Pmode, 0), lr);
 
-      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
+      emit_insn (gen_load_macho_picbase (src));
 
-      insn = emit_move_insn (gen_rtx_REG (Pmode,
-                                         RS6000_PIC_OFFSET_TABLE_REGNUM),
-                            lr);
-      rs6000_maybe_dead (insn);
+      emit_move_insn (gen_rtx_REG (Pmode,
+                                  RS6000_PIC_OFFSET_TABLE_REGNUM),
+                     lr);
 
       if (!info->lr_save_p)
-       rs6000_maybe_dead (emit_move_insn (lr, gen_rtx_REG (Pmode, 0)));
+       emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
     }
 #endif
 }
@@ -15315,7 +15991,7 @@ rs6000_emit_epilogue (int sibcall)
       RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
                                        gen_rtx_REG (Pmode,
-                                                    LINK_REGISTER_REGNUM));
+                                                    LR_REGNO));
       RTVEC_ELT (p, j++)
        = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
       /* The instruction pattern requires a clobber here;
@@ -15378,33 +16054,9 @@ rs6000_emit_epilogue (int sibcall)
       return;
     }
 
-  /* 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.  */
-  if (use_backchain_to_restore_sp)
-    {
-      /* Under V.4, don't reset the stack pointer until after we're done
-        loading the saved registers.  */
-      if (DEFAULT_ABI == ABI_V4)
-       frame_reg_rtx = gen_rtx_REG (Pmode, 11);
-
-      emit_move_insn (frame_reg_rtx,
-                     gen_rtx_MEM (Pmode, sp_reg_rtx));
-    }
-  else if (info->push_p)
-    {
-      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)));
-       }
-    }
+  /* 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.  */
   if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
@@ -15445,6 +16097,32 @@ rs6000_emit_epilogue (int sibcall)
       emit_insn (generate_set_vrsave (reg, info, 1));
     }
 
+  /* 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.  */
+  if (use_backchain_to_restore_sp)
+    {
+      /* Under V.4, don't reset the stack pointer until after we're done
+        loading the saved registers.  */
+      if (DEFAULT_ABI == ABI_V4)
+       frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+
+      emit_move_insn (frame_reg_rtx,
+                     gen_rtx_MEM (Pmode, sp_reg_rtx));
+      sp_offset = 0;
+    }
+  else if (info->push_p
+          && DEFAULT_ABI != ABI_V4
+          && !current_function_calls_eh_return)
+    {
+      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;
+    }
+
   /* Get the old lr if we saved it.  */
   if (info->lr_save_p)
     {
@@ -15466,7 +16144,7 @@ rs6000_emit_epilogue (int sibcall)
 
   /* Set LR here to try to overlap restores below.  */
   if (info->lr_save_p)
-    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
+    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
                    gen_rtx_REG (Pmode, 0));
 
   /* Load exception handler data registers, if needed.  */
@@ -15520,15 +16198,58 @@ rs6000_emit_epilogue (int sibcall)
        }
       emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
+  else if (TARGET_SPE_ABI
+           && info->spe_64bit_regs_used != 0
+           && info->first_gp_reg_save != 32)
+    {
+      /* Determine whether we can address all of the registers that need
+         to be saved with an offset from the stack pointer that fits in
+         the small const field for SPE memory instructions.  */
+      int spe_regs_addressable_via_sp
+        = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                              + (32 - info->first_gp_reg_save - 1) * reg_size);
+      int spe_offset;
+
+      if (spe_regs_addressable_via_sp)
+       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.  */
+         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;
+        }
+
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+        if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx offset, addr, mem;
+
+            /* We're doing all this to ensure that the immediate offset
+               fits into the immediate field of 'evldd'.  */
+            gcc_assert (SPE_CONST_OFFSET_OK (spe_offset + reg_size * i));
+
+            offset = GEN_INT (spe_offset + reg_size * i);
+            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),
+                            mem);
+          }
+    }
   else
     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-      if ((regs_ever_live[info->first_gp_reg_save + i]
-          && (!call_used_regs[info->first_gp_reg_save + i]
-              || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-                  && TARGET_TOC && TARGET_MINIMAL_TOC)))
-         || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-             && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                 || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
+      if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
        {
          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                                   GEN_INT (info->gp_save_offset
@@ -15536,24 +16257,6 @@ rs6000_emit_epilogue (int sibcall)
                                            + reg_size * i));
          rtx mem = gen_frame_mem (reg_mode, addr);
 
-         /* Restore 64-bit quantities for SPE.  */
-         if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-           {
-             int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-             rtx b;
-
-             if (!SPE_CONST_OFFSET_OK (offset))
-               {
-                 b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                 emit_move_insn (b, GEN_INT (offset));
-               }
-             else
-               b = GEN_INT (offset);
-
-             addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-             mem = gen_frame_mem (V2SImode, addr);
-           }
-
          emit_move_insn (gen_rtx_REG (reg_mode,
                                       info->first_gp_reg_save + i), mem);
        }
@@ -15561,7 +16264,7 @@ rs6000_emit_epilogue (int sibcall)
   /* Restore fpr's if we need to do it without calling a function.  */
   if (restoring_FPRs_inline)
     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-      if ((regs_ever_live[info->first_fp_reg_save+i]
+      if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
           && ! call_used_regs[info->first_fp_reg_save+i]))
        {
          rtx addr, mem;
@@ -15585,7 +16288,7 @@ rs6000_emit_epilogue (int sibcall)
       if (using_mtcr_multiple)
        {
          for (i = 0; i < 8; i++)
-           if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+           if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
              count++;
          gcc_assert (count);
        }
@@ -15599,7 +16302,7 @@ rs6000_emit_epilogue (int sibcall)
 
          ndx = 0;
          for (i = 0; i < 8; i++)
-           if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+           if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
              {
                rtvec r = rtvec_alloc (2);
                RTVEC_ELT (r, 0) = r12_rtx;
@@ -15614,7 +16317,7 @@ rs6000_emit_epilogue (int sibcall)
        }
       else
        for (i = 0; i < 8; i++)
-         if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+         if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
            {
              emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
                                                           CR0_REGNO+i),
@@ -15629,7 +16332,11 @@ 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 ();
-      emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+      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);
     }
   else if (sp_offset != 0)
     emit_insn (TARGET_32BIT
@@ -15657,7 +16364,7 @@ rs6000_emit_epilogue (int sibcall)
       RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
       RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
                                      gen_rtx_REG (Pmode,
-                                                  LINK_REGISTER_REGNUM));
+                                                  LR_REGNO));
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
@@ -15743,12 +16450,12 @@ rs6000_output_function_epilogue (FILE *file,
     rtx insn = get_last_insn ();
     while (insn
           && NOTE_P (insn)
-          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
+          && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL)
       insn = PREV_INSN (insn);
     if (insn
        && (LABEL_P (insn)
            || (NOTE_P (insn)
-               && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
+               && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)))
       fputs ("\tnop\n", file);
   }
 #endif
@@ -16029,8 +16736,6 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 1;
   epilogue_completed = 1;
-  no_new_pseudos = 1;
-  reset_block_changes ();
 
   /* Mark the end of the (empty) prologue.  */
   emit_note (NOTE_INSN_PROLOGUE_END);
@@ -16100,7 +16805,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                        gen_rtx_USE (VOIDmode, const0_rtx),
                        gen_rtx_USE (VOIDmode,
                                     gen_rtx_REG (SImode,
-                                                 LINK_REGISTER_REGNUM)),
+                                                 LR_REGNO)),
                        gen_rtx_RETURN (VOIDmode))));
   SIBLING_CALL_P (insn) = 1;
   emit_barrier ();
@@ -16110,7 +16815,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1);
@@ -16118,7 +16823,6 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 0;
   epilogue_completed = 0;
-  no_new_pseudos = 0;
 }
 \f
 /* A quick summary of the various types of 'constant-pool tables'
@@ -16750,7 +17454,7 @@ output_profile_hook (int labelno ATTRIBUTE_UNUSED)
   else if (DEFAULT_ABI == ABI_DARWIN)
     {
       const char *mcount_name = RS6000_MCOUNT;
-      int caller_addr_regno = LINK_REGISTER_REGNUM;
+      int caller_addr_regno = LR_REGNO;
 
       /* Be conservative and always set this, at least for now.  */
       current_function_uses_pic_offset_table = 1;
@@ -17697,7 +18401,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;
@@ -18173,15 +18877,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
@@ -18730,8 +19434,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";
@@ -18854,7 +19564,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)))
@@ -18955,8 +19665,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;
@@ -18972,10 +19692,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;
@@ -19000,7 +19722,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);
 }
@@ -19196,17 +19918,13 @@ output_call (rtx insn, rtx *operands, int dest_operand_number,
 
       if (no_previous_def (funname))
        {
-         int line_number = 0;
          rtx label_rtx = gen_label_rtx ();
          char *label_buf, temp_buf[256];
          ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
                                       CODE_LABEL_NUMBER (label_rtx));
          label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
          labelname = get_identifier (label_buf);
-         for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
-         if (insn)
-           line_number = NOTE_LINE_NUMBER (insn);
-         add_compiler_branch_island (labelname, funname, line_number);
+         add_compiler_branch_island (labelname, funname, insn_line (insn));
        }
       else
        labelname = get_prev_label (funname);
@@ -19323,7 +20041,7 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
 
       /* Use a different reg for the intermediate value, as
         it will be marked UNCHANGING.  */
-      reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+      reg_temp = !can_create_pseudo_p () ? reg : gen_reg_rtx (Pmode);
       base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
                                                     Pmode, reg_temp);
       offset =
@@ -19590,8 +20308,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.  */
@@ -19599,8 +20318,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.  */
@@ -20036,10 +20756,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)
        {
@@ -20049,6 +20774,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:
@@ -20240,11 +20966,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;
 
@@ -20279,8 +21030,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)));
 }
@@ -20289,7 +21040,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;
 
@@ -20337,13 +21088,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.  */
 
@@ -20481,7 +21316,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;
@@ -20684,7 +21519,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
@@ -20753,9 +21588,9 @@ rs6000_dbx_register_number (unsigned int regno)
     return regno;
   if (regno == MQ_REGNO)
     return 100;
-  if (regno == LINK_REGISTER_REGNUM)
+  if (regno == LR_REGNO)
     return 108;
-  if (regno == COUNT_REGISTER_REGNUM)
+  if (regno == CTR_REGNO)
     return 109;
   if (CR_REGNO_P (regno))
     return regno - CR0_REGNO + 86;
@@ -20799,6 +21634,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;
 
@@ -20811,7 +21649,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