OSDN Git Service

* expr.c (move_block_from_reg): Remove "size" parm. Localize vars.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 5974d3b..c5cfa14 100644 (file)
@@ -1,27 +1,29 @@
 /* Subroutines used for code generation on IBM RS/6000.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 
-   2000, 2001, 2002 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
-This file is part of GNU CC.
+   This file is part of GCC.
 
-GNU CC 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 option)
-any later version.
+   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
+   option) any later version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to the
+   Free Software Foundation, 59 Temple Place - Suite 330, Boston,
+   MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -53,6 +55,13 @@ Boston, MA 02111-1307, USA.  */
 #define TARGET_NO_PROTOTYPE 0
 #endif
 
+#define EASY_VECTOR_15(n, x, y) ((n) >= -16 && (n) <= 15 \
+                                && easy_vector_same (x, y))
+
+#define EASY_VECTOR_15_ADD_SELF(n, x, y) ((n) >= 0x10 && (n) <= 0x1e \
+                                          && !((n) & 1)              \
+                                         && easy_vector_same (x, y))
+
 #define min(A,B)       ((A) < (B) ? (A) : (B))
 #define max(A,B)       ((A) > (B) ? (A) : (B))
 
@@ -86,17 +95,23 @@ int rs6000_spe_abi;
 /* Whether isel instructions should be generated.  */
 int rs6000_isel;
 
-/* Nonzero if we have FPRs.  */
-int rs6000_fprs = 1;
+/* Whether SPE simd instructions should be generated.  */
+int rs6000_spe;
+
+/* Nonzero if floating point operations are done in the GPRs.  */
+int rs6000_float_gprs = 0;
+
+/* String from -mfloat-gprs=.  */
+const char *rs6000_float_gprs_string;
 
 /* String from -misel=.  */
 const char *rs6000_isel_string;
 
-/* Set to non-zero once AIX common-mode calls have been defined.  */
-static int common_mode_defined;
+/* String from -mspe=.  */
+const char *rs6000_spe_string;
 
-/* Private copy of original value of flag_pic for ABI_AIX.  */
-static int rs6000_flag_pic;
+/* Set to nonzero once AIX common-mode calls have been defined.  */
+static GTY(()) int common_mode_defined;
 
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
@@ -132,6 +147,11 @@ const char *rs6000_debug_name;
 int rs6000_debug_stack;                /* debug stack applications */
 int rs6000_debug_arg;          /* debug argument handling */
 
+/* Opaque types.  */
+static GTY(()) tree opaque_V2SI_type_node;
+static GTY(()) tree opaque_V2SF_type_node;
+static GTY(()) tree opaque_p_V2SI_type_node;
+
 const char *rs6000_traceback_name;
 static enum {
   traceback_default = 0,
@@ -165,15 +185,16 @@ struct builtin_description
   const enum rs6000_builtins code;
 };
 
-static void rs6000_add_gc_roots PARAMS ((void));
+static bool rs6000_function_ok_for_sibcall PARAMS ((tree, tree));
 static int num_insns_constant_wide PARAMS ((HOST_WIDE_INT));
-static rtx expand_block_move_mem PARAMS ((enum machine_mode, rtx, rtx));
 static void validate_condition_mode 
   PARAMS ((enum rtx_code, enum machine_mode));
 static rtx rs6000_generate_compare PARAMS ((enum rtx_code));
 static void rs6000_maybe_dead PARAMS ((rtx));
 static void rs6000_emit_stack_tie PARAMS ((void));
 static void rs6000_frame_related PARAMS ((rtx, rtx, HOST_WIDE_INT, rtx, rtx));
+static rtx spe_synthesize_frame_save PARAMS ((rtx));
+static bool spe_func_has_64bit_regs_p PARAMS ((void));
 static void emit_frame_save PARAMS ((rtx, rtx, enum machine_mode,
                                     unsigned int, int, int));
 static rtx gen_frame_mem_offset PARAMS ((enum machine_mode, rtx, int));
@@ -181,20 +202,27 @@ static void rs6000_emit_allocate_stack PARAMS ((HOST_WIDE_INT, int));
 static unsigned rs6000_hash_constant PARAMS ((rtx));
 static unsigned toc_hash_function PARAMS ((const void *));
 static int toc_hash_eq PARAMS ((const void *, const void *));
-static int toc_hash_mark_entry PARAMS ((void **, void *));
-static void toc_hash_mark_table PARAMS ((void *));
 static int constant_pool_expr_1 PARAMS ((rtx, int *, int *));
+static bool constant_pool_expr_p PARAMS ((rtx));
+static bool toc_relative_expr_p PARAMS ((rtx));
+static bool legitimate_small_data_p PARAMS ((enum machine_mode, rtx));
+static bool legitimate_offset_address_p PARAMS ((enum machine_mode, rtx, int));
+static bool legitimate_indexed_address_p PARAMS ((rtx, int));
+static bool legitimate_indirect_address_p PARAMS ((rtx, int));
+static bool legitimate_lo_sum_address_p PARAMS ((enum machine_mode, rtx, int));
 static struct machine_function * rs6000_init_machine_status PARAMS ((void));
 static bool rs6000_assemble_integer PARAMS ((rtx, unsigned int, int));
 #ifdef HAVE_GAS_HIDDEN
-static void rs6000_assemble_visibility PARAMS ((tree, const char *));
+static void rs6000_assemble_visibility PARAMS ((tree, int));
 #endif
 static int rs6000_ra_ever_killed PARAMS ((void));
 static tree rs6000_handle_longcall_attribute PARAMS ((tree *, tree, tree, int, bool *));
-const struct attribute_spec rs6000_attribute_table[];
+extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes PARAMS ((tree));
 static void rs6000_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
 static void rs6000_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static void rs6000_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
+                                           HOST_WIDE_INT, tree));
 static rtx rs6000_emit_set_long_const PARAMS ((rtx,
   HOST_WIDE_INT, HOST_WIDE_INT));
 #if TARGET_ELF
@@ -203,13 +231,12 @@ static unsigned int rs6000_elf_section_type_flags PARAMS ((tree, const char *,
 static void rs6000_elf_asm_out_constructor PARAMS ((rtx, int));
 static void rs6000_elf_asm_out_destructor PARAMS ((rtx, int));
 static void rs6000_elf_select_section PARAMS ((tree, int,
-                                                unsigned HOST_WIDE_INT));
+                                              unsigned HOST_WIDE_INT));
 static void rs6000_elf_unique_section PARAMS ((tree, int));
 static void rs6000_elf_select_rtx_section PARAMS ((enum machine_mode, rtx,
                                                   unsigned HOST_WIDE_INT));
-static void rs6000_elf_encode_section_info PARAMS ((tree, int))
+static void rs6000_elf_encode_section_info PARAMS ((tree, rtx, int))
      ATTRIBUTE_UNUSED;
-static const char *rs6000_elf_strip_name_encoding PARAMS ((const char *));
 static bool rs6000_elf_in_small_data_p PARAMS ((tree));
 #endif
 #if TARGET_XCOFF
@@ -223,12 +250,16 @@ static void rs6000_xcoff_select_rtx_section PARAMS ((enum machine_mode, rtx,
 static const char * rs6000_xcoff_strip_name_encoding PARAMS ((const char *));
 static unsigned int rs6000_xcoff_section_type_flags PARAMS ((tree, const char *, int));
 #endif
-static void rs6000_xcoff_encode_section_info PARAMS ((tree, int))
-     ATTRIBUTE_UNUSED;
+#if TARGET_MACHO
 static bool rs6000_binds_local_p PARAMS ((tree));
+#endif
+static int rs6000_use_dfa_pipeline_interface PARAMS ((void));
+static int rs6000_variable_issue PARAMS ((FILE *, int, rtx, int));
+static bool rs6000_rtx_costs PARAMS ((rtx, int, int, int *));
 static int rs6000_adjust_cost PARAMS ((rtx, rtx, rtx, int));
 static int rs6000_adjust_priority PARAMS ((rtx, int));
 static int rs6000_issue_rate PARAMS ((void));
+static int rs6000_use_sched_lookahead PARAMS ((void));
 
 static void rs6000_init_builtins PARAMS ((void));
 static rtx rs6000_expand_unop_builtin PARAMS ((enum insn_code, tree, rtx));
@@ -255,14 +286,28 @@ static rtx altivec_expand_abs_builtin PARAMS ((enum insn_code, tree, rtx));
 static rtx altivec_expand_predicate_builtin PARAMS ((enum insn_code, const char *, tree, rtx));
 static rtx altivec_expand_stv_builtin PARAMS ((enum insn_code, tree));
 static void rs6000_parse_abi_options PARAMS ((void));
-static void rs6000_parse_vrsave_option PARAMS ((void));
-static void rs6000_parse_isel_option PARAMS ((void));
+static void rs6000_parse_yes_no_option (const char *, const char *, int *);
 static int first_altivec_reg_to_save PARAMS ((void));
 static unsigned int compute_vrsave_mask PARAMS ((void));
 static void is_altivec_return_reg PARAMS ((rtx, void *));
 static rtx generate_set_vrsave PARAMS ((rtx, rs6000_stack_t *, int));
-static void altivec_frame_fixup PARAMS ((rtx, rtx, HOST_WIDE_INT));
-static int easy_vector_constant PARAMS ((rtx));
+int easy_vector_constant PARAMS ((rtx, enum machine_mode));
+static int easy_vector_same PARAMS ((rtx, enum machine_mode));
+static bool is_ev64_opaque_type PARAMS ((tree));
+static rtx rs6000_dwarf_register_span PARAMS ((rtx));
+
+/* Hash table stuff for keeping track of TOC entries.  */
+
+struct toc_hash_struct GTY(())
+{
+  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
+     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
+  rtx key;
+  enum machine_mode key_mode;
+  int labelno;
+};
+
+static GTY ((param_is (struct toc_hash_struct))) htab_t toc_hash_table;
 \f
 /* Default register names.  */
 char rs6000_reg_names[][8] =
@@ -283,7 +328,9 @@ char rs6000_reg_names[][8] =
       "8",  "9",  "10", "11", "12", "13", "14", "15",
       "16", "17", "18", "19", "20", "21", "22", "23",
       "24", "25", "26", "27", "28", "29", "30", "31",
-      "vrsave"
+      "vrsave", "vscr",
+      /* SPE registers.  */
+      "spe_acc", "spefscr"
 };
 
 #ifdef TARGET_REGNAMES
@@ -300,18 +347,26 @@ static const char alt_reg_names[][8] =
     "mq",    "lr",  "ctr",   "ap",
   "%cr0",  "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7",
    "xer",
-   /* AltiVec registers.  */
+  /* AltiVec registers.  */
    "%v0",  "%v1",  "%v2",  "%v3",  "%v4",  "%v5",  "%v6", "%v7",
-   "%v8",  "%v9",  "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
-   "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
-   "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
-   "vrsave"
+   "%v8",  "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15",
+  "%v16", "%v17", "%v18", "%v19", "%v20", "%v21", "%v22", "%v23",
+  "%v24", "%v25", "%v26", "%v27", "%v28", "%v29", "%v30", "%v31",
+  "vrsave", "vscr",
+  /* SPE registers.  */
+  "spe_acc", "spefscr"
 };
 #endif
 \f
 #ifndef MASK_STRICT_ALIGN
 #define MASK_STRICT_ALIGN 0
 #endif
+#ifndef TARGET_PROFILE_KERNEL
+#define TARGET_PROFILE_KERNEL 0
+#endif
+
+/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
+#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -358,6 +413,11 @@ static const char alt_reg_names[][8] =
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
 
+#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE rs6000_use_dfa_pipeline_interface
+#undef  TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
+
 #undef TARGET_SCHED_ISSUE_RATE
 #define TARGET_SCHED_ISSUE_RATE rs6000_issue_rate
 #undef TARGET_SCHED_ADJUST_COST
@@ -365,17 +425,39 @@ static const char alt_reg_names[][8] =
 #undef TARGET_SCHED_ADJUST_PRIORITY
 #define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
 
+#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
+#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
+
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
 
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
 
+#if TARGET_MACHO
 #undef TARGET_BINDS_LOCAL_P
 #define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
+#endif
 
-/* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
-#define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#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
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL rs6000_function_ok_for_sibcall
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS rs6000_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_0
+
+#undef TARGET_VECTOR_OPAQUE_P
+#define TARGET_VECTOR_OPAQUE_P is_ev64_opaque_type
+
+#undef TARGET_DWARF_REGISTER_SPAN
+#define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
@@ -414,10 +496,10 @@ rs6000_override_options (default_cpu)
            POWERPC_MASKS | MASK_NEW_MNEMONICS},
         {"power3", PROCESSOR_PPC630,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT},
+           POWER_MASKS},
         {"power4", PROCESSOR_POWER4,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT},
+            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
+            POWER_MASKS},
         {"powerpc", PROCESSOR_POWERPC,
            MASK_POWERPC | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -451,6 +533,15 @@ rs6000_override_options (default_cpu)
         {"405", PROCESSOR_PPC405,
            MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+        {"405fp", PROCESSOR_PPC405,
+           MASK_POWERPC | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+        {"440", PROCESSOR_PPC440,
+           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+        {"440fp", PROCESSOR_PPC440,
+           MASK_POWERPC | MASK_NEW_MNEMONICS,
+           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
         {"505", PROCESSOR_MPCCORE,
            MASK_POWERPC | MASK_NEW_MNEMONICS,
            POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
@@ -477,10 +568,10 @@ rs6000_override_options (default_cpu)
            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
         {"620", PROCESSOR_PPC620,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT},
+           POWER_MASKS},
         {"630", PROCESSOR_PPC630,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT},
+           POWER_MASKS},
         {"740", PROCESSOR_PPC750,
            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
@@ -544,22 +635,22 @@ rs6000_override_options (default_cpu)
        }
     }
 
-  if (rs6000_cpu == PROCESSOR_PPC8540)
+  if (TARGET_E500)
     rs6000_isel = 1;
 
-  /* If we are optimizing big endian systems for space, use the store
-     multiple instructions.  */
+  /* If we are optimizing big endian systems for space, use the load/store
+     multiple and string instructions.  */
   if (BYTES_BIG_ENDIAN && optimize_size)
-    target_flags |= MASK_MULTIPLE;
+    target_flags |= MASK_MULTIPLE | MASK_STRING;
 
   /* If -mmultiple or -mno-multiple was explicitly used, don't
      override with the processor default */
-  if (TARGET_MULTIPLE_SET)
+  if ((target_flags_explicit & MASK_MULTIPLE) != 0)
     target_flags = (target_flags & ~MASK_MULTIPLE) | multiple;
 
   /* If -mstring or -mno-string was explicitly used, don't override
      with the processor default.  */
-  if (TARGET_STRING_SET)
+  if ((target_flags_explicit & MASK_STRING) != 0)
     target_flags = (target_flags & ~MASK_STRING) | string;
 
   /* Don't allow -mmultiple or -mstring on little endian systems
@@ -568,48 +659,23 @@ rs6000_override_options (default_cpu)
      trap.  The 750 does not cause an alignment trap (except when the
      target is unaligned).  */
 
-  if (! BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
+  if (!BYTES_BIG_ENDIAN && rs6000_cpu != PROCESSOR_PPC750)
     {
       if (TARGET_MULTIPLE)
        {
          target_flags &= ~MASK_MULTIPLE;
-         if (TARGET_MULTIPLE_SET)
+         if ((target_flags_explicit & MASK_MULTIPLE) != 0)
            warning ("-mmultiple is not supported on little endian systems");
        }
 
       if (TARGET_STRING)
        {
          target_flags &= ~MASK_STRING;
-         if (TARGET_STRING_SET)
+         if ((target_flags_explicit & MASK_STRING) != 0)
            warning ("-mstring is not supported on little endian systems");
        }
     }
 
-  if (flag_pic != 0 && DEFAULT_ABI == ABI_AIX)
-    {
-      rs6000_flag_pic = flag_pic;
-      flag_pic = 0;
-    }
-
-#ifdef XCOFF_DEBUGGING_INFO
-  if (flag_function_sections && (write_symbols != NO_DEBUG)
-      && DEFAULT_ABI == ABI_AIX)
-    {
-      warning ("-ffunction-sections disabled on AIX when debugging");
-      flag_function_sections = 0;
-    }
-
-  if (flag_data_sections && (DEFAULT_ABI == ABI_AIX))
-    {
-      warning ("-fdata-sections not supported on AIX");
-      flag_data_sections = 0;
-    }
-#endif
-
-  /* For Darwin, always silently make -fpic and -fPIC identical.  */
-  if (flag_pic == 1 && DEFAULT_ABI == ABI_DARWIN)
-    flag_pic = 2;
-
   /* Set debug flags */
   if (rs6000_debug_name)
     {
@@ -652,11 +718,14 @@ rs6000_override_options (default_cpu)
   /* Handle -mabi= options.  */
   rs6000_parse_abi_options ();
 
-  /* Handle -mvrsave= option.  */
-  rs6000_parse_vrsave_option ();
-
-  /* Handle -misel= option.  */
-  rs6000_parse_isel_option ();
+  /* Handle generic -mFOO=YES/NO options.  */
+  rs6000_parse_yes_no_option ("vrsave", rs6000_altivec_vrsave_string,
+                             &rs6000_altivec_vrsave);
+  rs6000_parse_yes_no_option ("isel", rs6000_isel_string,
+                             &rs6000_isel);
+  rs6000_parse_yes_no_option ("spe", rs6000_spe_string, &rs6000_spe);
+  rs6000_parse_yes_no_option ("float-gprs", rs6000_float_gprs_string,
+                             &rs6000_float_gprs);
 
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
@@ -665,6 +734,35 @@ rs6000_override_options (default_cpu)
   SUBSUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  if (TARGET_E500)
+    {
+      /* The e500 does not have string instructions, and we set
+        MASK_STRING above when optimizing for size.  */
+      if ((target_flags & MASK_STRING) != 0)
+       target_flags = target_flags & ~MASK_STRING;
+
+      /* No SPE means 64-bit long doubles, even if an E500.  */
+      if (rs6000_spe_string != 0
+          && !strcmp (rs6000_spe_string, "no"))
+       rs6000_long_double_type_size = 64;
+    }
+  else if (rs6000_select[1].string != NULL)
+    {
+      /* For the powerpc-eabispe configuration, we set all these by
+        default, so let's unset them if we manually set another
+        CPU that is not the E500.  */
+      if (rs6000_abi_string == 0)
+       rs6000_spe_abi = 0;
+      if (rs6000_spe_string == 0)
+       rs6000_spe = 0;
+      if (rs6000_float_gprs_string == 0)
+       rs6000_float_gprs = 0;
+      if (rs6000_isel_string == 0)
+       rs6000_isel = 0;
+      if (rs6000_long_double_size_string == 0)
+       rs6000_long_double_type_size = 64;
+    }
+
   /* Handle -m(no-)longcall option.  This is a bit of a cheap hack,
      using TARGET_OPTIONS to handle a toggle switch, but we're out of
      bits in target_flags so TARGET_SWITCHES cannot be used.
@@ -691,7 +789,7 @@ rs6000_override_options (default_cpu)
   /* Set TARGET_AIX_STRUCT_RET last, after the ABI is determined.
      If -maix-struct-return or -msvr4-struct-return was explicitly
      used, don't override with the ABI default.  */
-  if (!(target_flags & MASK_AIX_STRUCT_RET_SET))
+  if ((target_flags_explicit & MASK_AIX_STRUCT_RET) == 0)
     {
       if (DEFAULT_ABI == ABI_V4 && !DRAFT_V4_STRUCT_RET)
        target_flags = (target_flags & ~MASK_AIX_STRUCT_RET);
@@ -699,8 +797,9 @@ rs6000_override_options (default_cpu)
        target_flags |= MASK_AIX_STRUCT_RET;
     }
 
-  /* Register global variables with the garbage collector.  */
-  rs6000_add_gc_roots ();
+  if (TARGET_LONG_DOUBLE_128
+      && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
+    real_format_for_mode[TFmode - QFmode] = &ibm_extended_format;
 
   /* Allocate an alias set for register saves & restores from stack.  */
   rs6000_sr_alias_set = new_alias_set ();
@@ -716,38 +815,30 @@ rs6000_override_options (default_cpu)
       targetm.asm_out.unaligned_op.di = NULL;
     }
 
+  /* Set maximum branch target alignment at two instructions, eight bytes.  */
+  align_jumps_max_skip = 8;
+  align_loops_max_skip = 8;
+
   /* Arrange to save and restore machine status around nested functions.  */
   init_machine_status = rs6000_init_machine_status;
 }
 
-/* Handle -misel= option.  */
+/* Handle generic options of the form -mfoo=yes/no.
+   NAME is the option name.
+   VALUE is the option value.
+   FLAG is the pointer to the flag where to store a 1 or 0, depending on
+   whether the option value is 'yes' or 'no' respectively.  */
 static void
-rs6000_parse_isel_option ()
+rs6000_parse_yes_no_option (const char *name, const char *value, int *flag)
 {
-  if (rs6000_isel_string == 0)
+  if (value == 0)
     return;
-  else if (! strcmp (rs6000_isel_string, "yes"))
-    rs6000_isel = 1;
-  else if (! strcmp (rs6000_isel_string, "no"))
-    rs6000_isel = 0;
+  else if (!strcmp (value, "yes"))
+    *flag = 1;
+  else if (!strcmp (value, "no"))
+    *flag = 0;
   else
-    error ("unknown -misel= option specified: '%s'",
-         rs6000_isel_string);
-}
-
-/* Handle -mvrsave= options.  */
-static void
-rs6000_parse_vrsave_option ()
-{
-  /* Generate VRSAVE instructions by default.  */
-  if (rs6000_altivec_vrsave_string == 0
-      || ! strcmp (rs6000_altivec_vrsave_string, "yes"))
-    rs6000_altivec_vrsave = 1;
-  else if (! strcmp (rs6000_altivec_vrsave_string, "no"))
-    rs6000_altivec_vrsave = 0;
-  else
-    error ("unknown -mvrsave= option specified: '%s'",
-          rs6000_altivec_vrsave_string);
+    error ("unknown -m%s= option specified: '%s'", name, value);
 }
 
 /* Handle -mabi= options.  */
@@ -761,7 +852,12 @@ rs6000_parse_abi_options ()
   else if (! strcmp (rs6000_abi_string, "no-altivec"))
     rs6000_altivec_abi = 0;
   else if (! strcmp (rs6000_abi_string, "spe"))
-    rs6000_spe_abi = 1;
+    {
+      rs6000_spe_abi = 1;
+      if (!TARGET_SPE_ABI)
+       error ("not configured for ABI: '%s'", rs6000_abi_string);
+    }
+  
   else if (! strcmp (rs6000_abi_string, "no-spe"))
     rs6000_spe_abi = 0;
   else
@@ -823,7 +919,7 @@ rs6000_file_start (file, default_cpu)
     }
 }
 \f
-/* Return non-zero if this function is known to have a null epilogue.  */
+/* Return nonzero if this function is known to have a null epilogue.  */
 
 int
 direct_return ()
@@ -1322,7 +1418,21 @@ easy_fp_constant (op, mode)
     return 0;
 #endif
 
-  if (mode == DFmode)
+  if (mode == TFmode)
+    {
+      long k[4];
+      REAL_VALUE_TYPE rv;
+
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
+             && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1
+             && num_insns_constant_wide ((HOST_WIDE_INT) k[2]) == 1
+             && num_insns_constant_wide ((HOST_WIDE_INT) k[3]) == 1);
+    }
+
+  else if (mode == DFmode)
     {
       long k[2];
       REAL_VALUE_TYPE rv;
@@ -1356,48 +1466,152 @@ easy_fp_constant (op, mode)
     abort ();
 }
 
-/* Return 1 if the operand is a CONST_INT and can be put into a
-   register with one instruction.  */
+/* Return non zero if all elements of a vector have the same value.  */
 
 static int
-easy_vector_constant (op)
+easy_vector_same (op, mode)
      rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  int units, i, cst;
+
+  units = CONST_VECTOR_NUNITS (op);
+
+  cst = INTVAL (CONST_VECTOR_ELT (op, 0));
+  for (i = 1; i < units; ++i)
+    if (INTVAL (CONST_VECTOR_ELT (op, i)) != cst)
+      break;
+  if (i == units)
+    return 1;
+  return 0;
+}
+
+/* Return 1 if the operand is a CONST_INT and can be put into a
+   register without using memory.  */
+
+int
+easy_vector_constant (op, mode)
+     rtx op;
+     enum machine_mode mode;
 {
-  rtx elt;
-  int units, i;
+  int cst, cst2;
 
-  if (GET_CODE (op) != CONST_VECTOR)
+  if (GET_CODE (op) != CONST_VECTOR
+      || (!TARGET_ALTIVEC
+         && !TARGET_SPE))
     return 0;
 
-  units = CONST_VECTOR_NUNITS (op);
+  if (zero_constant (op, mode)
+      && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
+         || (TARGET_SPE && SPE_VECTOR_MODE (mode))))
+    return 1;
 
-  /* We can generate 0 easily.  Look for that.  */
-  for (i = 0; i < units; ++i)
-    {
-      elt = CONST_VECTOR_ELT (op, i);
+  if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
+    return 0;
+
+  if (TARGET_SPE && mode == V1DImode)
+    return 0;
+
+  cst  = INTVAL (CONST_VECTOR_ELT (op, 0));
+  cst2 = INTVAL (CONST_VECTOR_ELT (op, 1));
+
+  /* Limit SPE vectors to 15 bits signed.  These we can generate with:
+       li r0, CONSTANT1
+       evmergelo r0, r0, r0
+       li r0, CONSTANT2
+
+     I don't know how efficient it would be to allow bigger constants,
+     considering we'll have an extra 'ori' for every 'li'.  I doubt 5
+     instructions is better than a 64-bit memory load, but I don't
+     have the e500 timing specs.  */
+  if (TARGET_SPE && mode == V2SImode
+      && cst  >= -0x7fff && cst <= 0x7fff
+      && cst2 >= -0x7fff && cst2 <= 0x7fff)
+    return 1;
+
+  if (TARGET_ALTIVEC && EASY_VECTOR_15 (cst, op, mode))
+    return 1;
+
+  if (TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode))
+    return 1;
+
+  return 0;
+}
+
+/* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF.  */
+
+int
+easy_vector_constant_add_self (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  int cst;
+
+  if (!easy_vector_constant (op, mode))
+    return 0;
+
+  cst = INTVAL (CONST_VECTOR_ELT (op, 0));
+
+  return TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode);
+}
+
+const char *
+output_vec_const_move (operands)
+     rtx *operands;
+{
+  int cst, cst2;
+  enum machine_mode mode;
+  rtx dest, vec;
+
+  dest = operands[0];
+  vec = operands[1];
 
-      /* We could probably simplify this by just checking for equality
-        with CONST0_RTX for the current mode, but let's be safe
-        instead.  */
+  cst = INTVAL (CONST_VECTOR_ELT (vec, 0));
+  cst2 = INTVAL (CONST_VECTOR_ELT (vec, 1));
+  mode = GET_MODE (dest);
 
-      switch (GET_CODE (elt))
+  if (TARGET_ALTIVEC)
+    {
+      if (zero_constant (vec, mode))
+       return "vxor %0,%0,%0";
+      else if (EASY_VECTOR_15 (cst, vec, mode))
        {
-       case CONST_INT:
-         if (INTVAL (elt) != 0)
-           return 0;
-         break;
-       case CONST_DOUBLE:
-         if (CONST_DOUBLE_LOW (elt) != 0 || CONST_DOUBLE_HIGH (elt) != 0)
-           return 0;
-         break;
-       default:
-         return 0;
+         operands[1] = GEN_INT (cst);
+         switch (mode)
+           {
+           case V4SImode:
+             return "vspltisw %0,%1";
+           case V8HImode:
+             return "vspltish %0,%1";
+           case V16QImode:
+             return "vspltisb %0,%1";
+           default:
+             abort ();
+           }
        }
+      else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
+       return "#";
+      else
+       abort ();
     }
 
-  /* We could probably generate a few other constants trivially, but
-     gcc doesn't generate them yet.  FIXME later.  */
-  return 1;
+  if (TARGET_SPE)
+    {
+      /* Vector constant 0 is handled as a splitter of V2SI, and in the
+        pattern of V1DI, V4HI, and V2SF.
+
+        FIXME: We should probabl return # and add post reload
+        splitters for these, but this way is so easy ;-).
+      */
+      operands[1] = GEN_INT (cst);
+      operands[2] = GEN_INT (cst2);
+      if (cst == cst2)
+       return "li %0,%1\n\tevmergelo %0,%0,%0";
+      else
+       return "li %0,%1\n\tevmergelo %0,%0,%0\n\tli %0,%2";
+    }
+
+  abort ();
 }
 
 /* Return 1 if the operand is the constant 0.  This works for scalars
@@ -1651,6 +1865,8 @@ mask64_operand (op, mode)
 
       /* Find the transition, and check that all bits above are 1's.  */
       lsb = c & -c;
+
+      /* Match if all the bits above are 1's (or c is zero).  */
       return c == -lsb;
     }
   return 0;
@@ -1773,6 +1989,8 @@ build_mask64_2_operands (in, out)
   out[2] = GEN_INT (shift);
   out[3] = GEN_INT (m2);
 #else
+  (void)in;
+  (void)out;
   abort ();
 #endif
 }
@@ -1864,7 +2082,8 @@ symbol_ref_operand (op, mode)
   if (mode != VOIDmode && GET_MODE (op) != mode)
     return 0;
 
-  return (GET_CODE (op) == SYMBOL_REF);
+  return (GET_CODE (op) == SYMBOL_REF
+         && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op)));
 }
 
 /* Return 1 if the operand, used inside a MEM, is a valid first argument
@@ -1886,7 +2105,7 @@ call_operand (op, mode)
 }
 
 /* Return 1 if the operand is a SYMBOL_REF for a function known to be in
-   this file and the function is not weakly defined.  */
+   this file.  */
 
 int
 current_file_function_operand (op, mode)
@@ -1894,9 +2113,9 @@ current_file_function_operand (op, mode)
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return (GET_CODE (op) == SYMBOL_REF
-         && (SYMBOL_REF_FLAG (op)
-             || (op == XEXP (DECL_RTL (current_function_decl), 0)
-                 && ! DECL_WEAK (current_function_decl))));
+         && (DEFAULT_ABI != ABI_AIX || SYMBOL_REF_FUNCTION_P (op))
+         && (SYMBOL_REF_LOCAL_P (op)
+             || (op == XEXP (DECL_RTL (current_function_decl), 0))));
 }
 
 /* Return 1 if this operand is a valid input for a move insn.  */
@@ -1926,6 +2145,11 @@ input_operand (op, mode)
          || GET_CODE (op) == CONST_DOUBLE))
     return 1;
 
+  /* Allow easy vector constants.  */
+  if (GET_CODE (op) == CONST_VECTOR
+      && easy_vector_constant (op, mode))
+    return 1;
+
   /* For floating-point or multi-word mode, the only remaining valid type
      is a register.  */
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
@@ -1939,11 +2163,11 @@ input_operand (op, mode)
     return 1;
 
   /* A SYMBOL_REF referring to the TOC is valid.  */
-  if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op))
+  if (legitimate_constant_pool_address_p (op))
     return 1;
 
   /* A constant pool expression (relative to the TOC) is valid */
-  if (TOC_RELATIVE_EXPR_P (op))
+  if (toc_relative_expr_p (op))
     return 1;
 
   /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region
@@ -1995,16 +2219,14 @@ small_data_operand (op, mode)
       sym_ref = XEXP (sum, 0);
     }
 
-  if (*XSTR (sym_ref, 0) != '@')
-    return 0;
-
-  return 1;
-
+  return SYMBOL_REF_SMALL_P (sym_ref);
 #else
   return 0;
 #endif
 }
 \f
+/* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address.  */
+
 static int 
 constant_pool_expr_1 (op, have_sym, have_toc) 
     rtx op;
@@ -2044,7 +2266,7 @@ constant_pool_expr_1 (op, have_sym, have_toc)
     }
 }
 
-int
+static bool
 constant_pool_expr_p (op)
     rtx op;
 {
@@ -2053,15 +2275,164 @@ constant_pool_expr_p (op)
   return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
 }
 
-int
+static bool
 toc_relative_expr_p (op)
     rtx op;
 {
-    int have_sym = 0;
-    int have_toc = 0;
-    return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
+  int have_sym = 0;
+  int have_toc = 0;
+  return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
+}
+
+/* SPE offset addressing is limited to 5-bits worth of double words.  */
+#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
+
+bool
+legitimate_constant_pool_address_p (x)
+     rtx x;
+{
+  return (TARGET_TOC
+         && GET_CODE (x) == PLUS
+         && GET_CODE (XEXP (x, 0)) == REG
+         && (TARGET_MINIMAL_TOC || REGNO (XEXP (x, 0)) == TOC_REGISTER)
+         && constant_pool_expr_p (XEXP (x, 1)));
+}
+
+static bool
+legitimate_small_data_p (mode, x)
+     enum machine_mode mode;
+     rtx x;
+{
+  return (DEFAULT_ABI == ABI_V4
+         && !flag_pic && !TARGET_TOC
+         && (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == CONST)
+         && small_data_operand (x, mode));
+}
+
+static bool
+legitimate_offset_address_p (mode, x, strict)
+     enum machine_mode mode;
+     rtx x;
+     int strict;
+{
+  unsigned HOST_WIDE_INT offset, extra;
+
+  if (GET_CODE (x) != PLUS)
+    return false;
+  if (GET_CODE (XEXP (x, 0)) != REG)
+    return false;
+  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
+    return false;
+  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+    return false;
+
+  offset = INTVAL (XEXP (x, 1));
+  extra = 0;
+  switch (mode)
+    {
+    case V16QImode:
+    case V8HImode:
+    case V4SFmode:
+    case V4SImode:
+      /* AltiVec vector modes.  Only reg+reg addressing is valid here,
+        which leaves the only valid constant offset of zero, which by
+        canonicalization rules is also invalid.  */
+      return false;
+
+    case V4HImode:
+    case V2SImode:
+    case V1DImode:
+    case V2SFmode:
+      /* SPE vector modes.  */
+      return SPE_CONST_OFFSET_OK (offset);
+
+    case DFmode:
+    case DImode:
+      if (TARGET_32BIT)
+       extra = 4;
+      else if (offset & 3)
+       return false;
+      break;
+
+    case TFmode:
+    case TImode:
+      if (TARGET_32BIT)
+       extra = 12;
+      else if (offset & 3)
+       return false;
+      else
+       extra = 8;
+      break;
+
+    default:
+      break;
+    }
+
+  return (offset + extra >= offset) && (offset + extra + 0x8000 < 0x10000);
+}
+
+static bool
+legitimate_indexed_address_p (x, strict)
+     rtx x;
+     int strict;
+{
+  rtx op0, op1;
+
+  if (GET_CODE (x) != PLUS)
+    return false;
+  op0 = XEXP (x, 0);
+  op1 = XEXP (x, 1);
+
+  if (!REG_P (op0) || !REG_P (op1))
+    return false;
+
+  return ((INT_REG_OK_FOR_BASE_P (op0, strict)
+          && INT_REG_OK_FOR_INDEX_P (op1, strict))
+         || (INT_REG_OK_FOR_BASE_P (op1, strict)
+             && INT_REG_OK_FOR_INDEX_P (op0, strict)));
+}
+
+static inline bool
+legitimate_indirect_address_p (x, strict)
+     rtx x;
+     int strict;
+{
+  return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
+}
+
+static bool
+legitimate_lo_sum_address_p (mode, x, strict)
+     enum machine_mode mode;
+     rtx x;
+     int strict;
+{
+  if (GET_CODE (x) != LO_SUM)
+    return false;
+  if (GET_CODE (XEXP (x, 0)) != REG)
+    return false;
+  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
+    return false;
+  x = XEXP (x, 1);
+
+  if (TARGET_ELF)
+    {
+      if (DEFAULT_ABI != ABI_AIX && flag_pic)
+       return false;
+      if (TARGET_TOC)
+       return false;
+      if (GET_MODE_NUNITS (mode) != 1)
+       return false;
+      if (GET_MODE_BITSIZE (mode) > 32
+         && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
+       return false;
+
+      return CONSTANT_P (x);
+    }
+
+  return false;
 }
 
+
 /* Try machine-dependent ways of modifying an illegitimate address
    to be legitimate.  If we find one, return the new, valid address.
    This is used from only one place: `memory_address' in explow.c.
@@ -2084,6 +2455,7 @@ toc_relative_expr_p (op)
 
    Then check for the sum of a register and something not constant, try to
    load the other things into a register and return the sum.  */
+
 rtx
 rs6000_legitimize_address (x, oldx, mode)
      rtx x;
@@ -2109,7 +2481,7 @@ rs6000_legitimize_address (x, oldx, mode)
           && GET_MODE_NUNITS (mode) == 1
           && ((TARGET_HARD_FLOAT && TARGET_FPRS)
               || TARGET_POWERPC64
-              || mode != DFmode)
+              || (mode != DFmode && mode != TFmode))
           && (TARGET_POWERPC64 || mode != DImode)
           && mode != TImode)
     {
@@ -2149,7 +2521,10 @@ rs6000_legitimize_address (x, oldx, mode)
 
       return force_reg (Pmode, x);
     }
-  else if (TARGET_ELF && TARGET_32BIT && TARGET_NO_TOC && ! flag_pic
+  else if (TARGET_ELF
+          && TARGET_32BIT
+          && TARGET_NO_TOC
+          && ! flag_pic
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE 
           && CONSTANT_P (x)
@@ -2163,6 +2538,9 @@ rs6000_legitimize_address (x, oldx, mode)
     }
   else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
           && ! flag_pic
+#if TARGET_MACHO
+          && ! MACHO_DYNAMIC_NO_PIC_P
+#endif
           && GET_CODE (x) != CONST_INT
           && GET_CODE (x) != CONST_DOUBLE 
           && CONSTANT_P (x)
@@ -2175,7 +2553,7 @@ rs6000_legitimize_address (x, oldx, mode)
       return gen_rtx_LO_SUM (Pmode, reg, (x));
     }
   else if (TARGET_TOC 
-          && CONSTANT_POOL_EXPR_P (x)
+          && constant_pool_expr_p (x)
           && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), Pmode))
     {
       return create_TOC_reference (x);
@@ -2302,9 +2680,23 @@ rs6000_legitimize_reload_address (x, mode, opnum, type, ind_levels, win)
       *win = 1;
       return x;
     }
+   if (GET_CODE (x) == SYMBOL_REF
+       && DEFAULT_ABI == ABI_DARWIN
+       && !ALTIVEC_VECTOR_MODE (mode)
+       && MACHO_DYNAMIC_NO_PIC_P)
+     {
+       /* Darwin load of floating point constant.  */
+       x = gen_rtx (LO_SUM, GET_MODE (x),
+               gen_rtx (HIGH, Pmode, x), x);
+       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+               BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+               opnum, (enum reload_type)type);
+       *win = 1;
+       return x;
+     }
 #endif
   if (TARGET_TOC
-      && CONSTANT_POOL_EXPR_P (x)
+      && constant_pool_expr_p (x)
       && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
     {
       (x) = create_TOC_reference (x);
@@ -2324,7 +2716,7 @@ rs6000_legitimize_reload_address (x, mode, opnum, type, ind_levels, win)
    refers to a constant pool entry of an address (or the sum of it
    plus a constant), a short (16-bit signed) constant plus a register,
    the sum of two registers, or a register indirect, possibly with an
-   auto-increment.  For DFmode and DImode with an constant plus register,
+   auto-increment.  For DFmode and DImode with a constant plus register,
    we must ensure that both words are addressable or PowerPC64 with offset
    word aligned.
 
@@ -2338,17 +2730,17 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
     rtx x;
     int reg_ok_strict;
 {
-  if (LEGITIMATE_INDIRECT_ADDRESS_P (x, reg_ok_strict))
+  if (legitimate_indirect_address_p (x, reg_ok_strict))
     return 1;
   if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
       && !ALTIVEC_VECTOR_MODE (mode)
       && !SPE_VECTOR_MODE (mode)
       && TARGET_UPDATE
-      && LEGITIMATE_INDIRECT_ADDRESS_P (XEXP (x, 0), reg_ok_strict))
+      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
-  if (LEGITIMATE_SMALL_DATA_P (mode, x))
+  if (legitimate_small_data_p (mode, x))
     return 1;
-  if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (x))
+  if (legitimate_constant_pool_address_p (x))
     return 1;
   /* If not REG_OK_STRICT (before reload) let pass any stack offset.  */
   if (! reg_ok_strict
@@ -2357,24 +2749,63 @@ rs6000_legitimate_address (mode, x, reg_ok_strict)
       && XEXP (x, 0) == virtual_stack_vars_rtx
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     return 1;
-  if (LEGITIMATE_OFFSET_ADDRESS_P (mode, x, reg_ok_strict))
+  if (legitimate_offset_address_p (mode, x, reg_ok_strict))
     return 1;
   if (mode != TImode
       && ((TARGET_HARD_FLOAT && TARGET_FPRS)
          || TARGET_POWERPC64
-         || mode != DFmode)
+         || (mode != DFmode && mode != TFmode))
       && (TARGET_POWERPC64 || mode != DImode)
-      && LEGITIMATE_INDEXED_ADDRESS_P (x, reg_ok_strict))
+      && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
-  if (LEGITIMATE_LO_SUM_ADDRESS_P (mode, x, reg_ok_strict))
+  if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
     return 1;
   return 0;
 }
-\f
-/* Try to output insns to set TARGET equal to the constant C if it can
-   be done in less than N insns.  Do all computations in MODE.
-   Returns the place where the output has been placed if it can be
-   done and the insns have been emitted.  If it would take more than N
+
+/* Go to LABEL if ADDR (a legitimate address expression)
+   has an effect that depends on the machine mode it is used for.
+
+   On the RS/6000 this is true of all integral offsets (since AltiVec
+   modes don't allow them) or is a pre-increment or decrement.
+
+   ??? Except that due to conceptual problems in offsettable_address_p
+   we can't really report the problems of integral offsets.  So leave
+   this assuming that the adjustable offset must be valid for the 
+   sub-words of a TFmode operand, which is what we had before.  */
+
+bool
+rs6000_mode_dependent_address (addr)
+     rtx addr;
+{
+  switch (GET_CODE (addr))
+    {
+    case PLUS:
+      if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
+       {
+         unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
+         return val + 12 + 0x8000 >= 0x10000;
+       }
+      break;
+
+    case LO_SUM:
+      return true;
+
+    case PRE_INC:
+    case PRE_DEC:
+      return TARGET_UPDATE;
+
+    default:
+      break;
+    }
+
+  return false;
+}
+\f
+/* Try to output insns to set TARGET equal to the constant C if it can
+   be done in less than N insns.  Do all computations in MODE.
+   Returns the place where the output has been placed if it can be
+   done and the insns have been emitted.  If it would take more than N
    insns, zero is returned and no insns and emitted.  */
 
 rtx
@@ -2578,8 +3009,22 @@ rs6000_emit_move (dest, source, mode)
       return;
     }
   
-  if (! no_new_pseudos && GET_CODE (operands[0]) != REG)
-    operands[1] = force_reg (mode, operands[1]);
+  if (!no_new_pseudos)
+    {
+      if (GET_CODE (operands[1]) == MEM && optimize > 0
+         && (mode == QImode || mode == HImode || mode == SImode)
+         && GET_MODE_SIZE (mode) < GET_MODE_SIZE (word_mode))
+       {
+         rtx reg = gen_reg_rtx (word_mode);
+
+         emit_insn (gen_rtx_SET (word_mode, reg,
+                                 gen_rtx_ZERO_EXTEND (word_mode,
+                                                      operands[1])));
+         operands[1] = gen_lowpart (mode, reg);
+       }
+      if (GET_CODE (operands[0]) != REG)
+       operands[1] = force_reg (mode, operands[1]);
+    }
 
   if (mode == SFmode && ! TARGET_POWERPC
       && TARGET_HARD_FLOAT && TARGET_FPRS
@@ -2606,16 +3051,15 @@ rs6000_emit_move (dest, source, mode)
        }
     }
 
-  /* Handle the case where reload calls us with an invalid address;
-     and the case of CONSTANT_P_RTX.  */
-  if (!ALTIVEC_VECTOR_MODE (mode)
+  /* Handle the case where reload calls us with an invalid address.  */
+  if (reload_in_progress && mode == Pmode
       && (! general_operand (operands[1], mode)
-         || ! nonimmediate_operand (operands[0], mode)
-         || GET_CODE (operands[1]) == CONSTANT_P_RTX))
-    {
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
-      return;
-    }
+         || ! nonimmediate_operand (operands[0], mode)))
+    goto emit_set;
+
+  /* Handle the case of CONSTANT_P_RTX.  */
+  if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
+    goto emit_set;
   
   /* FIXME:  In the long term, this switch statement should go away
      and be replaced by a sequence of tests based on things like
@@ -2644,8 +3088,9 @@ rs6000_emit_move (dest, source, mode)
     case V4HImode:
     case V2SFmode:
     case V2SImode:
+    case V1DImode:
       if (CONSTANT_P (operands[1])
-         && !easy_vector_constant (operands[1]))
+         && !easy_vector_constant (operands[1], mode))
        operands[1] = force_const_mem (mode, operands[1]);
       break;
       
@@ -2672,7 +3117,8 @@ rs6000_emit_move (dest, source, mode)
        }
 
       if ((TARGET_ELF || DEFAULT_ABI == ABI_DARWIN)
-         && TARGET_NO_TOC && ! flag_pic
+         && TARGET_NO_TOC
+         && ! flag_pic
          && mode == Pmode
          && CONSTANT_P (operands[1])
          && GET_CODE (operands[1]) != HIGH
@@ -2693,13 +3139,26 @@ rs6000_emit_move (dest, source, mode)
              new_ref = gen_rtx_SYMBOL_REF (Pmode, name);
              CONSTANT_POOL_ADDRESS_P (new_ref)
                = CONSTANT_POOL_ADDRESS_P (operands[1]);
-             SYMBOL_REF_FLAG (new_ref) = SYMBOL_REF_FLAG (operands[1]);
+             SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
              SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
+             SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]);
              operands[1] = new_ref;
            }
 
          if (DEFAULT_ABI == ABI_DARWIN)
            {
+#if TARGET_MACHO
+             if (MACHO_DYNAMIC_NO_PIC_P)
+               {
+                 /* Take care of any required data indirection.  */
+                 operands[1] = rs6000_machopic_legitimize_pic_address (
+                                 operands[1], mode, operands[0]);
+                 if (operands[0] != operands[1])
+                   emit_insn (gen_rtx_SET (VOIDmode,
+                                           operands[0], operands[1]));
+                 return;
+               }
+#endif
              emit_insn (gen_macho_high (target, operands[1]));
              emit_insn (gen_macho_low (operands[0], target, operands[1]));
              return;
@@ -2715,7 +3174,7 @@ rs6000_emit_move (dest, source, mode)
         reference to it.  */
       if (TARGET_TOC
          && GET_CODE (operands[1]) == SYMBOL_REF
-         && CONSTANT_POOL_EXPR_P (operands[1])
+         && constant_pool_expr_p (operands[1])
          && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (operands[1]),
                                              get_pool_mode (operands[1])))
        {
@@ -2730,8 +3189,8 @@ rs6000_emit_move (dest, source, mode)
                   || (GET_CODE (operands[0]) == REG
                       && FP_REGNO_P (REGNO (operands[0]))))
               && GET_CODE (operands[1]) != HIGH
-              && ! LEGITIMATE_CONSTANT_POOL_ADDRESS_P (operands[1])
-              && ! TOC_RELATIVE_EXPR_P (operands[1]))
+              && ! legitimate_constant_pool_address_p (operands[1])
+              && ! toc_relative_expr_p (operands[1]))
        {
          /* Emit a USE operation so that the constant isn't deleted if
             expensive optimizations are turned on because nobody
@@ -2744,7 +3203,7 @@ rs6000_emit_move (dest, source, mode)
 
 #if TARGET_MACHO
          /* Darwin uses a special PIC legitimizer.  */
-         if (DEFAULT_ABI == ABI_DARWIN && flag_pic)
+         if (DEFAULT_ABI == ABI_DARWIN && MACHOPIC_INDIRECT)
            {
              operands[1] =
                rs6000_machopic_legitimize_pic_address (operands[1], mode,
@@ -2782,7 +3241,7 @@ rs6000_emit_move (dest, source, mode)
          operands[1] = force_const_mem (mode, operands[1]);
 
          if (TARGET_TOC 
-             && CONSTANT_POOL_EXPR_P (XEXP (operands[1], 0))
+             && constant_pool_expr_p (XEXP (operands[1], 0))
              && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (
                        get_pool_constant (XEXP (operands[1], 0)),
                        get_pool_mode (XEXP (operands[1], 0))))
@@ -2810,6 +3269,16 @@ rs6000_emit_move (dest, source, mode)
        operands[1]
          = replace_equiv_address (operands[1],
                                   copy_addr_to_reg (XEXP (operands[1], 0)));
+      if (TARGET_POWER)
+       {
+         emit_insn (gen_rtx_PARALLEL (VOIDmode,
+                      gen_rtvec (2,
+                                 gen_rtx_SET (VOIDmode,
+                                              operands[0], operands[1]),
+                                 gen_rtx_CLOBBER (VOIDmode,
+                                                  gen_rtx_SCRATCH (SImode)))));
+         return;
+       }
       break;
 
     default:
@@ -2819,13 +3288,11 @@ rs6000_emit_move (dest, source, mode)
   /* Above, we may have called force_const_mem which may have returned
      an invalid address.  If we can, fix this up; otherwise, reload will
      have to deal with it.  */
-  if (GET_CODE (operands[1]) == MEM
-      && ! memory_address_p (mode, XEXP (operands[1], 0))
-      && ! reload_in_progress)
-    operands[1] = adjust_address (operands[1], mode, 0);
+  if (GET_CODE (operands[1]) == MEM && ! reload_in_progress)
+    operands[1] = validize_mem (operands[1]);
 
+ emit_set:
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
-  return;
 }
 \f
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -2908,12 +3375,12 @@ function_arg_padding (mode, type)
 
   /* This is the default definition.  */
   return (! BYTES_BIG_ENDIAN
-          ? upward
-          : ((mode == BLKmode
-              ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-                 && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
-              : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
-             ? downward : upward));
+         ? upward
+         : ((mode == BLKmode
+             ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
+                && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
+             : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
+            ? downward : upward));
 }
 
 /* If defined, a C expression that gives the alignment boundary, in bits,
@@ -3025,7 +3492,7 @@ function_arg_advance (cum, mode, type, named)
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT
          && TARGET_HARD_FLOAT && TARGET_FPRS)
-       cum->fregno++;
+       cum->fregno += (mode == TFmode ? 2 : 1);
 
       if (TARGET_DEBUG_ARG)
        {
@@ -3142,7 +3609,7 @@ function_arg (cum, mode, type, named)
                  && SPE_VECTOR_MODE (mode) && !named)
                {
                  rtx r1, r2;
-                 enum machine_mode m = GET_MODE_INNER (mode);
+                 enum machine_mode m = SImode;
 
                  r1 = gen_rtx_REG (m, gregno);
                  r1 = gen_rtx_EXPR_LIST (m, r1, const0_rtx);
@@ -3244,7 +3711,10 @@ function_arg_partial_nregs (cum, mode, type, named)
    the argument itself.  The pointer is passed in whatever way is
    appropriate for passing a pointer to that type.
 
-   Under V.4, structures and unions are passed by reference.  */
+   Under V.4, structures and unions are passed by reference.
+
+   As an extension to all ABIs, variable sized types are passed by
+   reference.  */
 
 int
 function_arg_pass_by_reference (cum, mode, type, named)
@@ -3262,8 +3732,7 @@ function_arg_pass_by_reference (cum, mode, type, named)
 
       return 1;
     }
-
-  return 0;
+  return type && int_size_in_bytes (type) <= 0;
 }
 \f
 /* Perform any needed actions needed for a function that is receiving a
@@ -3285,7 +3754,7 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
      CUMULATIVE_ARGS *cum;
      enum machine_mode mode;
      tree type;
-     int *pretend_size;
+     int *pretend_size ATTRIBUTE_UNUSED;
      int no_rtl;
 
 {
@@ -3336,13 +3805,8 @@ setup_incoming_varargs (cum, mode, type, pretend_size, no_rtl)
       set_mem_alias_set (mem, set);
       set_mem_align (mem, BITS_PER_WORD);
 
-      move_block_from_reg
-       (GP_ARG_MIN_REG + first_reg_offset, mem,
-        GP_ARG_NUM_REG - first_reg_offset,
-        (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD);
-
-      /* ??? Does ABI_V4 need this at all?  */
-      *pretend_size = (GP_ARG_NUM_REG - first_reg_offset) * UNITS_PER_WORD;
+      move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
+                          GP_ARG_NUM_REG - first_reg_offset);
     }
 
   /* Save FP registers if needed.  */
@@ -3502,7 +3966,28 @@ rs6000_va_arg (valist, type)
   rtx lab_false, lab_over, addr_rtx, r;
 
   if (DEFAULT_ABI != ABI_V4)
-    return std_expand_builtin_va_arg (valist, type);
+    {
+      /* Variable sized types are passed by reference.  */
+      if (int_size_in_bytes (type) <= 0)
+       {
+         u = build_pointer_type (type);
+
+         /* Args grow upward.  */
+         t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
+                    build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
+         TREE_SIDE_EFFECTS (t) = 1;
+
+         t = build1 (NOP_EXPR, build_pointer_type (u), t);
+         TREE_SIDE_EFFECTS (t) = 1;
+
+         t = build1 (INDIRECT_REF, u, t);
+         TREE_SIDE_EFFECTS (t) = 1;
+
+         return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
+       }
+      else
+       return std_expand_builtin_va_arg (valist, type);
+    }
 
   f_gpr = TYPE_FIELDS (TREE_TYPE (va_list_type_node));
   f_fpr = TREE_CHAIN (f_gpr);
@@ -3897,16 +4382,8 @@ static struct builtin_description bdesc_2arg[] =
   { 0, CODE_FOR_spe_evmwhssfa, "__builtin_spe_evmwhssfa", SPE_BUILTIN_EVMWHSSFA },
   { 0, CODE_FOR_spe_evmwhumi, "__builtin_spe_evmwhumi", SPE_BUILTIN_EVMWHUMI },
   { 0, CODE_FOR_spe_evmwhumia, "__builtin_spe_evmwhumia", SPE_BUILTIN_EVMWHUMIA },
-  { 0, CODE_FOR_spe_evmwlsmf, "__builtin_spe_evmwlsmf", SPE_BUILTIN_EVMWLSMF },
-  { 0, CODE_FOR_spe_evmwlsmfa, "__builtin_spe_evmwlsmfa", SPE_BUILTIN_EVMWLSMFA },
-  { 0, CODE_FOR_spe_evmwlsmfaaw, "__builtin_spe_evmwlsmfaaw", SPE_BUILTIN_EVMWLSMFAAW },
-  { 0, CODE_FOR_spe_evmwlsmfanw, "__builtin_spe_evmwlsmfanw", SPE_BUILTIN_EVMWLSMFANW },
   { 0, CODE_FOR_spe_evmwlsmiaaw, "__builtin_spe_evmwlsmiaaw", SPE_BUILTIN_EVMWLSMIAAW },
   { 0, CODE_FOR_spe_evmwlsmianw, "__builtin_spe_evmwlsmianw", SPE_BUILTIN_EVMWLSMIANW },
-  { 0, CODE_FOR_spe_evmwlssf, "__builtin_spe_evmwlssf", SPE_BUILTIN_EVMWLSSF },
-  { 0, CODE_FOR_spe_evmwlssfa, "__builtin_spe_evmwlssfa", SPE_BUILTIN_EVMWLSSFA },
-  { 0, CODE_FOR_spe_evmwlssfaaw, "__builtin_spe_evmwlssfaaw", SPE_BUILTIN_EVMWLSSFAAW },
-  { 0, CODE_FOR_spe_evmwlssfanw, "__builtin_spe_evmwlssfanw", SPE_BUILTIN_EVMWLSSFANW },
   { 0, CODE_FOR_spe_evmwlssiaaw, "__builtin_spe_evmwlssiaaw", SPE_BUILTIN_EVMWLSSIAAW },
   { 0, CODE_FOR_spe_evmwlssianw, "__builtin_spe_evmwlssianw", SPE_BUILTIN_EVMWLSSIANW },
   { 0, CODE_FOR_spe_evmwlumi, "__builtin_spe_evmwlumi", SPE_BUILTIN_EVMWLUMI },
@@ -3972,7 +4449,7 @@ static struct builtin_description bdesc_2arg[] =
   { 0, CODE_FOR_spe_brinc, "__builtin_spe_brinc", SPE_BUILTIN_BRINC },
 
   /* Place-holder.  Leave as last binary SPE builtin.  */
-  { 0, CODE_FOR_spe_evxor, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
+  { 0, CODE_FOR_xorv2si3, "__builtin_spe_evxor", SPE_BUILTIN_EVXOR },
 };
 
 /* AltiVec predicates.  */
@@ -4039,7 +4516,7 @@ static struct builtin_description bdesc_spe_evsel[] =
   { 0, CODE_FOR_spe_evfststeq, "__builtin_spe_evsel_fststeq", SPE_BUILTIN_EVSEL_FSTSTEQ },
 };
 
-/* ABS* opreations.  */
+/* ABS* operations.  */
 
 static const struct builtin_description bdesc_abs[] =
 {
@@ -4244,6 +4721,7 @@ rs6000_expand_binop_builtin (icode, arglist, target)
       || icode == CODE_FOR_spe_evrlwi
       || icode == CODE_FOR_spe_evslwi
       || icode == CODE_FOR_spe_evsrwis
+      || icode == CODE_FOR_spe_evsubifw
       || icode == CODE_FOR_spe_evsrwiu)
     {
       /* Only allow 5-bit unsigned literals.  */
@@ -5162,6 +5640,10 @@ rs6000_expand_builtin (exp, target, subtarget, mode, ignore)
 static void
 rs6000_init_builtins ()
 {
+  opaque_V2SI_type_node = copy_node (V2SI_type_node);
+  opaque_V2SF_type_node = copy_node (V2SF_type_node);
+  opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
+
   if (TARGET_SPE)
     spe_init_builtins ();
   if (TARGET_ALTIVEC)
@@ -5172,7 +5654,7 @@ rs6000_init_builtins ()
 
 /* Search through a set of builtins and enable the mask bits.
    DESC is an array of builtins.
-   SIZE is the totaly number of builtins.
+   SIZE is the total number of builtins.
    START is the builtin enum at which to start.
    END is the builtin enum at which to end.  */
 static void
@@ -5205,47 +5687,46 @@ spe_init_builtins ()
   tree endlink = void_list_node;
   tree puint_type_node = build_pointer_type (unsigned_type_node);
   tree pushort_type_node = build_pointer_type (short_unsigned_type_node);
-  tree pv2si_type_node = build_pointer_type (V2SI_type_node);
   struct builtin_description *d;
   size_t i;
 
   tree v2si_ftype_4_v2si
     = build_function_type
-    (V2SI_type_node,
-     tree_cons (NULL_TREE, V2SI_type_node,
-               tree_cons (NULL_TREE, V2SI_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
-                                     tree_cons (NULL_TREE, V2SI_type_node,
+    (opaque_V2SI_type_node,
+     tree_cons (NULL_TREE, opaque_V2SI_type_node,
+               tree_cons (NULL_TREE, opaque_V2SI_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
+                                     tree_cons (NULL_TREE, opaque_V2SI_type_node,
                                                 endlink)))));
 
   tree v2sf_ftype_4_v2sf
     = build_function_type
-    (V2SF_type_node,
-     tree_cons (NULL_TREE, V2SF_type_node,
-               tree_cons (NULL_TREE, V2SF_type_node,
-                          tree_cons (NULL_TREE, V2SF_type_node,
-                                     tree_cons (NULL_TREE, V2SF_type_node,
+    (opaque_V2SF_type_node,
+     tree_cons (NULL_TREE, opaque_V2SF_type_node,
+               tree_cons (NULL_TREE, opaque_V2SF_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SF_type_node,
+                                     tree_cons (NULL_TREE, opaque_V2SF_type_node,
                                                 endlink)))));
 
   tree int_ftype_int_v2si_v2si
     = build_function_type
     (integer_type_node,
      tree_cons (NULL_TREE, integer_type_node,
-               tree_cons (NULL_TREE, V2SI_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
+               tree_cons (NULL_TREE, opaque_V2SI_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
                                      endlink))));
 
   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,
+               tree_cons (NULL_TREE, opaque_V2SF_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SF_type_node,
                                      endlink))));
 
   tree void_ftype_v2si_puint_int
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
                                      tree_cons (NULL_TREE, puint_type_node,
                                                 tree_cons (NULL_TREE,
                                                            integer_type_node,
@@ -5253,7 +5734,7 @@ spe_init_builtins ()
 
   tree void_ftype_v2si_puint_char
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
                                      tree_cons (NULL_TREE, puint_type_node,
                                                 tree_cons (NULL_TREE,
                                                            char_type_node,
@@ -5261,16 +5742,16 @@ spe_init_builtins ()
 
   tree void_ftype_v2si_pv2si_int
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
-                                     tree_cons (NULL_TREE, pv2si_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
+                                     tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
                                                 tree_cons (NULL_TREE,
                                                            integer_type_node,
                                                            endlink))));
 
   tree void_ftype_v2si_pv2si_char
     = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, V2SI_type_node,
-                                     tree_cons (NULL_TREE, pv2si_type_node,
+                          tree_cons (NULL_TREE, opaque_V2SI_type_node,
+                                     tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
                                                 tree_cons (NULL_TREE,
                                                            char_type_node,
                                                            endlink))));
@@ -5284,19 +5765,19 @@ spe_init_builtins ()
                           tree_cons (NULL_TREE, void_type_node, endlink));
 
   tree v2si_ftype_pv2si_int
-    = build_function_type (V2SI_type_node,
-                          tree_cons (NULL_TREE, pv2si_type_node,
+    = build_function_type (opaque_V2SI_type_node,
+                          tree_cons (NULL_TREE, opaque_p_V2SI_type_node,
                                      tree_cons (NULL_TREE, integer_type_node,
                                                 endlink)));
 
   tree v2si_ftype_puint_int
-    = build_function_type (V2SI_type_node,
+    = build_function_type (opaque_V2SI_type_node,
                           tree_cons (NULL_TREE, puint_type_node,
                                      tree_cons (NULL_TREE, integer_type_node,
                                                 endlink)));
 
   tree v2si_ftype_pushort_int
-    = build_function_type (V2SI_type_node,
+    = build_function_type (opaque_V2SI_type_node,
                           tree_cons (NULL_TREE, pushort_type_node,
                                      tree_cons (NULL_TREE, integer_type_node,
                                                 endlink)));
@@ -5422,26 +5903,34 @@ altivec_init_builtins ()
 
   tree pvoid_type_node = build_pointer_type (void_type_node);
 
+  tree pcfloat_type_node = build_pointer_type (build_qualified_type (float_type_node, TYPE_QUAL_CONST));
+  tree pcint_type_node = build_pointer_type (build_qualified_type (integer_type_node, TYPE_QUAL_CONST));
+  tree pcshort_type_node = build_pointer_type (build_qualified_type (short_integer_type_node, TYPE_QUAL_CONST));
+  tree pcchar_type_node = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST));
+
+  tree pcvoid_type_node = build_pointer_type (build_qualified_type (void_type_node, TYPE_QUAL_CONST));
+
   tree int_ftype_int_v4si_v4si
     = build_function_type_list (integer_type_node,
                                integer_type_node, V4SI_type_node,
                                V4SI_type_node, NULL_TREE);
-  tree v4sf_ftype_pfloat
-    = build_function_type_list (V4SF_type_node, pfloat_type_node, NULL_TREE);
+  tree v4sf_ftype_pcfloat
+    = build_function_type_list (V4SF_type_node, pcfloat_type_node, NULL_TREE);
   tree void_ftype_pfloat_v4sf
     = build_function_type_list (void_type_node,
                                pfloat_type_node, V4SF_type_node, NULL_TREE);
-  tree v4si_ftype_pint
-    = build_function_type_list (V4SI_type_node, pint_type_node, NULL_TREE);  tree void_ftype_pint_v4si
+  tree v4si_ftype_pcint
+    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
+  tree void_ftype_pint_v4si
     = build_function_type_list (void_type_node,
                                pint_type_node, V4SI_type_node, NULL_TREE);
-  tree v8hi_ftype_pshort
-    = build_function_type_list (V8HI_type_node, pshort_type_node, NULL_TREE);
+  tree v8hi_ftype_pcshort
+    = build_function_type_list (V8HI_type_node, pcshort_type_node, NULL_TREE);
   tree void_ftype_pshort_v8hi
     = build_function_type_list (void_type_node,
                                pshort_type_node, V8HI_type_node, NULL_TREE);
-  tree v16qi_ftype_pchar
-    = build_function_type_list (V16QI_type_node, pchar_type_node, NULL_TREE);
+  tree v16qi_ftype_pcchar
+    = build_function_type_list (V16QI_type_node, pcchar_type_node, NULL_TREE);
   tree void_ftype_pchar_v16qi
     = build_function_type_list (void_type_node,
                                pchar_type_node, V16QI_type_node, NULL_TREE);
@@ -5453,15 +5942,17 @@ altivec_init_builtins ()
     = build_function_type (void_type_node, void_list_node);
   tree void_ftype_qi
     = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
-  tree v16qi_ftype_int_pvoid
+
+  tree v16qi_ftype_int_pcvoid
     = build_function_type_list (V16QI_type_node,
-                               integer_type_node, pvoid_type_node, NULL_TREE);
-  tree v8hi_ftype_int_pvoid
+                               integer_type_node, pcvoid_type_node, NULL_TREE);
+  tree v8hi_ftype_int_pcvoid
     = build_function_type_list (V8HI_type_node,
-                               integer_type_node, pvoid_type_node, NULL_TREE);
-  tree v4si_ftype_int_pvoid
+                               integer_type_node, pcvoid_type_node, NULL_TREE);
+  tree v4si_ftype_int_pcvoid
     = build_function_type_list (V4SI_type_node,
-                               integer_type_node, pvoid_type_node, NULL_TREE);
+                               integer_type_node, pcvoid_type_node, NULL_TREE);
+
   tree void_ftype_v4si_int_pvoid
     = build_function_type_list (void_type_node,
                                V4SI_type_node, integer_type_node,
@@ -5494,30 +5985,38 @@ altivec_init_builtins ()
     = build_function_type_list (V16QI_type_node, V16QI_type_node, NULL_TREE);
   tree v4sf_ftype_v4sf
     = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
-  tree void_ftype_pvoid_int_char
+  tree void_ftype_pcvoid_int_char
     = build_function_type_list (void_type_node,
-                               pvoid_type_node, integer_type_node,
+                               pcvoid_type_node, integer_type_node,
                                char_type_node, NULL_TREE);
-
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pfloat, ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf, ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pint, ALTIVEC_BUILTIN_LD_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si, ALTIVEC_BUILTIN_ST_INTERNAL_4si);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pshort, ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi, ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pchar, ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi, ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
+  
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4sf", v4sf_ftype_pcfloat,
+              ALTIVEC_BUILTIN_LD_INTERNAL_4sf);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4sf", void_ftype_pfloat_v4sf,
+              ALTIVEC_BUILTIN_ST_INTERNAL_4sf);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_4si", v4si_ftype_pcint,
+              ALTIVEC_BUILTIN_LD_INTERNAL_4si);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_4si", void_ftype_pint_v4si,
+              ALTIVEC_BUILTIN_ST_INTERNAL_4si);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_8hi", v8hi_ftype_pcshort,
+              ALTIVEC_BUILTIN_LD_INTERNAL_8hi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_8hi", void_ftype_pshort_v8hi,
+              ALTIVEC_BUILTIN_ST_INTERNAL_8hi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_ld_internal_16qi", v16qi_ftype_pcchar,
+              ALTIVEC_BUILTIN_LD_INTERNAL_16qi);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_st_internal_16qi", void_ftype_pchar_v16qi,
+              ALTIVEC_BUILTIN_ST_INTERNAL_16qi);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVSR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEHX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVXL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pvoid, ALTIVEC_BUILTIN_LVX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSR);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEHX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVXL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVX);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
@@ -5527,7 +6026,7 @@ altivec_init_builtins ()
   /* Add the DST variants.  */
   d = (struct builtin_description *) bdesc_dst;
   for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
-    def_builtin (d->mask, d->name, void_ftype_pvoid_int_char, d->code);
+    def_builtin (d->mask, d->name, void_ftype_pcvoid_int_char, d->code);
 
   /* Initialize the predicates.  */
   dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
@@ -5624,43 +6123,48 @@ rs6000_common_init_builtins ()
     = build_function_type_list (V4SF_type_node, V4SF_type_node, NULL_TREE);
 
   tree v2si_ftype_v2si_v2si
-    = build_function_type_list (V2SI_type_node,
-                               V2SI_type_node, V2SI_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SI_type_node,
+                               opaque_V2SI_type_node,
+                               opaque_V2SI_type_node, NULL_TREE);
 
   tree v2sf_ftype_v2sf_v2sf
-    = build_function_type_list (V2SF_type_node,
-                               V2SF_type_node, V2SF_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SF_type_node,
+                               opaque_V2SF_type_node,
+                               opaque_V2SF_type_node, NULL_TREE);
 
   tree v2si_ftype_int_int
-    = build_function_type_list (V2SI_type_node,
+    = build_function_type_list (opaque_V2SI_type_node,
                                integer_type_node, integer_type_node,
                                NULL_TREE);
 
   tree v2si_ftype_v2si
-    = build_function_type_list (V2SI_type_node, V2SI_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SI_type_node,
+                               opaque_V2SI_type_node, NULL_TREE);
 
   tree v2sf_ftype_v2sf
-    = build_function_type_list (V2SF_type_node,
-                               V2SF_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SF_type_node,
+                               opaque_V2SF_type_node, NULL_TREE);
   
   tree v2sf_ftype_v2si
-    = build_function_type_list (V2SF_type_node,
-                               V2SI_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SF_type_node,
+                               opaque_V2SI_type_node, NULL_TREE);
 
   tree v2si_ftype_v2sf
-    = build_function_type_list (V2SI_type_node,
-                               V2SF_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SI_type_node,
+                               opaque_V2SF_type_node, NULL_TREE);
 
   tree v2si_ftype_v2si_char
-    = build_function_type_list (V2SI_type_node,
-                               V2SI_type_node, char_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SI_type_node,
+                               opaque_V2SI_type_node,
+                               char_type_node, NULL_TREE);
 
   tree v2si_ftype_int_char
-    = build_function_type_list (V2SI_type_node,
+    = build_function_type_list (opaque_V2SI_type_node,
                                integer_type_node, char_type_node, NULL_TREE);
 
   tree v2si_ftype_char
-    = build_function_type_list (V2SI_type_node, char_type_node, NULL_TREE);
+    = build_function_type_list (opaque_V2SI_type_node,
+                               char_type_node, NULL_TREE);
 
   tree int_ftype_int_int
     = build_function_type_list (integer_type_node,
@@ -6044,21 +6548,7 @@ rs6000_common_init_builtins ()
     }
 }
 
-/* Generate a memory reference for expand_block_move, copying volatile,
-   and other bits from an original memory reference.  */
-
-static rtx
-expand_block_move_mem (mode, addr, orig_mem)
-     enum machine_mode mode;
-     rtx addr;
-     rtx orig_mem;
-{
-  rtx mem = gen_rtx_MEM (mode, addr);
-
-  MEM_COPY_ATTRIBUTES (mem, orig_mem);
-  return mem;
-}
-
+\f
 /* Expand a block move operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
 
@@ -6081,14 +6571,6 @@ expand_block_move (operands)
   int align;
   int bytes;
   int offset;
-  int num_reg;
-  int i;
-  rtx src_reg;
-  rtx dest_reg;
-  rtx src_addr;
-  rtx dest_addr;
-  rtx tmp_reg;
-  rtx stores[MAX_MOVE_REG];
   int move_bytes;
 
   /* If this is not a fixed size move, just call memcpy */
@@ -6110,14 +6592,17 @@ expand_block_move (operands)
   if (bytes > (TARGET_POWERPC64 ? 64 : 32))
     return 0;
 
-  /* Move the address into scratch registers.  */
-  dest_reg = copy_addr_to_reg (XEXP (orig_dest, 0));
-  src_reg  = copy_addr_to_reg (XEXP (orig_src,  0));
-
   if (TARGET_STRING)   /* string instructions are available */
     {
-      for ( ; bytes > 0; bytes -= move_bytes)
+      for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
        {
+         union {
+           rtx (*movstrsi) PARAMS ((rtx, rtx, rtx, rtx));
+           rtx (*mov) PARAMS ((rtx, rtx));
+         } gen_func;
+         enum machine_mode mode = BLKmode;
+         rtx src, dest;
+
          if (bytes > 24                /* move up to 32 bytes at a time */
              && ! fixed_regs[5]
              && ! fixed_regs[6]
@@ -6129,15 +6614,7 @@ expand_block_move (operands)
              && ! fixed_regs[12])
            {
              move_bytes = (bytes > 32) ? 32 : bytes;
-             emit_insn (gen_movstrsi_8reg (expand_block_move_mem (BLKmode,
-                                                                  dest_reg,
-                                                                  orig_dest),
-                                           expand_block_move_mem (BLKmode,
-                                                                  src_reg,
-                                                                  orig_src),
-                                           GEN_INT ((move_bytes == 32)
-                                                    ? 0 : move_bytes),
-                                           align_rtx));
+             gen_func.movstrsi = gen_movstrsi_8reg;
            }
          else if (bytes > 16   /* move up to 24 bytes at a time */
                   && ! fixed_regs[5]
@@ -6148,14 +6625,7 @@ expand_block_move (operands)
                   && ! fixed_regs[10])
            {
              move_bytes = (bytes > 24) ? 24 : bytes;
-             emit_insn (gen_movstrsi_6reg (expand_block_move_mem (BLKmode,
-                                                                  dest_reg,
-                                                                  orig_dest),
-                                           expand_block_move_mem (BLKmode,
-                                                                  src_reg,
-                                                                  orig_src),
-                                           GEN_INT (move_bytes),
-                                           align_rtx));
+             gen_func.movstrsi = gen_movstrsi_6reg;
            }
          else if (bytes > 8    /* move up to 16 bytes at a time */
                   && ! fixed_regs[5]
@@ -6164,14 +6634,7 @@ expand_block_move (operands)
                   && ! fixed_regs[8])
            {
              move_bytes = (bytes > 16) ? 16 : bytes;
-             emit_insn (gen_movstrsi_4reg (expand_block_move_mem (BLKmode,
-                                                                  dest_reg,
-                                                                  orig_dest),
-                                           expand_block_move_mem (BLKmode,
-                                                                  src_reg,
-                                                                  orig_src),
-                                           GEN_INT (move_bytes),
-                                           align_rtx));
+             gen_func.movstrsi = gen_movstrsi_4reg;
            }
          else if (bytes >= 8 && TARGET_POWERPC64
                   /* 64-bit loads and stores require word-aligned
@@ -6179,108 +6642,84 @@ expand_block_move (operands)
                   && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
            {
              move_bytes = 8;
-             tmp_reg = gen_reg_rtx (DImode);
-             emit_move_insn (tmp_reg,
-                             expand_block_move_mem (DImode,
-                                                    src_reg, orig_src));
-             emit_move_insn (expand_block_move_mem (DImode,
-                                                    dest_reg, orig_dest),
-                             tmp_reg);
+             mode = DImode;
+             gen_func.mov = gen_movdi;
            }
          else if (bytes > 4 && !TARGET_POWERPC64)
            {                   /* move up to 8 bytes at a time */
              move_bytes = (bytes > 8) ? 8 : bytes;
-             emit_insn (gen_movstrsi_2reg (expand_block_move_mem (BLKmode,
-                                                                  dest_reg,
-                                                                  orig_dest),
-                                           expand_block_move_mem (BLKmode,
-                                                                  src_reg,
-                                                                  orig_src),
-                                           GEN_INT (move_bytes),
-                                           align_rtx));
+             gen_func.movstrsi = gen_movstrsi_2reg;
            }
          else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
            {                   /* move 4 bytes */
              move_bytes = 4;
-             tmp_reg = gen_reg_rtx (SImode);
-             emit_move_insn (tmp_reg,
-                             expand_block_move_mem (SImode,
-                                                    src_reg, orig_src));
-             emit_move_insn (expand_block_move_mem (SImode,
-                                                    dest_reg, orig_dest),
-                             tmp_reg);
+             mode = SImode;
+             gen_func.mov = gen_movsi;
            }
          else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
            {                   /* move 2 bytes */
              move_bytes = 2;
-             tmp_reg = gen_reg_rtx (HImode);
-             emit_move_insn (tmp_reg,
-                             expand_block_move_mem (HImode,
-                                                    src_reg, orig_src));
-             emit_move_insn (expand_block_move_mem (HImode,
-                                                    dest_reg, orig_dest),
-                             tmp_reg);
+             mode = HImode;
+             gen_func.mov = gen_movhi;
            }
          else if (bytes == 1)  /* move 1 byte */
            {
              move_bytes = 1;
-             tmp_reg = gen_reg_rtx (QImode);
-             emit_move_insn (tmp_reg,
-                             expand_block_move_mem (QImode,
-                                                    src_reg, orig_src));
-             emit_move_insn (expand_block_move_mem (QImode,
-                                                    dest_reg, orig_dest),
-                             tmp_reg);
+             mode = QImode;
+             gen_func.mov = gen_movqi;
            }
          else
            {                   /* move up to 4 bytes at a time */
              move_bytes = (bytes > 4) ? 4 : bytes;
-             emit_insn (gen_movstrsi_1reg (expand_block_move_mem (BLKmode,
-                                                                  dest_reg,
-                                                                  orig_dest),
-                                           expand_block_move_mem (BLKmode,
-                                                                  src_reg,
-                                                                  orig_src),
-                                           GEN_INT (move_bytes),
-                                           align_rtx));
+             gen_func.movstrsi = gen_movstrsi_1reg;
            }
 
-         if (bytes > move_bytes)
+         src = adjust_address (orig_src, mode, offset);
+         dest = adjust_address (orig_dest, mode, offset);
+
+         if (mode == BLKmode)
            {
-             if (! TARGET_POWERPC64)
+             /* Move the address into scratch registers.  The movstrsi
+                patterns require zero offset.  */
+             if (!REG_P (XEXP (src, 0)))
                {
-                 emit_insn (gen_addsi3 (src_reg, src_reg,
-                                        GEN_INT (move_bytes)));
-                 emit_insn (gen_addsi3 (dest_reg, dest_reg,
-                                        GEN_INT (move_bytes)));
+                 rtx src_reg = copy_addr_to_reg (XEXP (src, 0));
+                 src = replace_equiv_address (src, src_reg);
                }
-             else
+             set_mem_size (src, GEN_INT (move_bytes));
+
+             if (!REG_P (XEXP (dest, 0)))
                {
-                 emit_insn (gen_adddi3 (src_reg, src_reg,
-                                        GEN_INT (move_bytes)));
-                 emit_insn (gen_adddi3 (dest_reg, dest_reg,
-                                        GEN_INT (move_bytes)));
+                 rtx dest_reg = copy_addr_to_reg (XEXP (dest, 0));
+                 dest = replace_equiv_address (dest, dest_reg);
                }
+             set_mem_size (dest, GEN_INT (move_bytes));
+
+             emit_insn ((*gen_func.movstrsi) (dest, src,
+                                              GEN_INT (move_bytes & 31),
+                                              align_rtx));
+           }
+         else
+           {
+             rtx tmp_reg = gen_reg_rtx (mode);
+
+             emit_insn ((*gen_func.mov) (tmp_reg, src));
+             emit_insn ((*gen_func.mov) (dest, tmp_reg));
            }
        }
     }
 
   else                 /* string instructions not available */
     {
-      num_reg = offset = 0;
-      for ( ; bytes > 0; (bytes -= move_bytes), (offset += move_bytes))
+      rtx stores[MAX_MOVE_REG];
+      int num_reg = 0;
+      int i;
+
+      for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
        {
-         /* Calculate the correct offset for src/dest */
-         if (offset == 0)
-           {
-             src_addr  = src_reg;
-             dest_addr = dest_reg;
-           }
-         else
-           {
-             src_addr = plus_constant (src_reg, offset);
-             dest_addr = plus_constant (dest_reg, offset);
-           }
+         rtx (*gen_mov_func) PARAMS ((rtx, rtx));
+         enum machine_mode mode;
+         rtx src, dest, tmp_reg;
 
          /* Generate the appropriate load and store, saving the stores
             for later.  */
@@ -6290,56 +6729,35 @@ expand_block_move (operands)
              && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
            {
              move_bytes = 8;
-             tmp_reg = gen_reg_rtx (DImode);
-             emit_insn (gen_movdi (tmp_reg,
-                                   expand_block_move_mem (DImode,
-                                                          src_addr,
-                                                          orig_src)));
-             stores[num_reg++] = gen_movdi (expand_block_move_mem (DImode,
-                                                                   dest_addr,
-                                                                   orig_dest),
-                                            tmp_reg);
+             mode = DImode;
+             gen_mov_func = gen_movdi;
            }
          else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
            {
              move_bytes = 4;
-             tmp_reg = gen_reg_rtx (SImode);
-             emit_insn (gen_movsi (tmp_reg,
-                                   expand_block_move_mem (SImode,
-                                                          src_addr,
-                                                          orig_src)));
-             stores[num_reg++] = gen_movsi (expand_block_move_mem (SImode,
-                                                                   dest_addr,
-                                                                   orig_dest),
-                                            tmp_reg);
+             mode = SImode;
+             gen_mov_func = gen_movsi;
            }
          else if (bytes >= 2 && (align >= 2 || ! STRICT_ALIGNMENT))
            {
              move_bytes = 2;
-             tmp_reg = gen_reg_rtx (HImode);
-             emit_insn (gen_movhi (tmp_reg,
-                                   expand_block_move_mem (HImode,
-                                                          src_addr,
-                                                          orig_src)));
-             stores[num_reg++] = gen_movhi (expand_block_move_mem (HImode,
-                                                                   dest_addr,
-                                                                   orig_dest),
-                                            tmp_reg);
+             mode = HImode;
+             gen_mov_func = gen_movhi;
            }
          else
            {
              move_bytes = 1;
-             tmp_reg = gen_reg_rtx (QImode);
-             emit_insn (gen_movqi (tmp_reg,
-                                   expand_block_move_mem (QImode,
-                                                          src_addr,
-                                                          orig_src)));
-             stores[num_reg++] = gen_movqi (expand_block_move_mem (QImode,
-                                                                   dest_addr,
-                                                                   orig_dest),
-                                            tmp_reg);
+             mode = QImode;
+             gen_mov_func = gen_movqi;
            }
 
+         src = adjust_address (orig_src, mode, offset);
+         dest = adjust_address (orig_dest, mode, offset);
+         tmp_reg = gen_reg_rtx (mode);
+
+         emit_insn ((*gen_mov_func) (tmp_reg, src));
+         stores[num_reg++] = (*gen_mov_func) (dest, tmp_reg);
+
          if (num_reg >= MAX_MOVE_REG)
            {
              for (i = 0; i < num_reg; i++)
@@ -6442,6 +6860,64 @@ store_multiple_operation (op, mode)
   return 1;
 }
 
+/* Return a string to perform a load_multiple operation.
+   operands[0] is the vector.
+   operands[1] is the source address.
+   operands[2] is the first destination register.  */
+
+const char *
+rs6000_output_load_multiple (operands)
+     rtx operands[3];
+{
+  /* We have to handle the case where the pseudo used to contain the address
+     is assigned to one of the output registers.  */
+  int i, j;
+  int words = XVECLEN (operands[0], 0);
+  rtx xop[10];
+
+  if (XVECLEN (operands[0], 0) == 1)
+    return "{l|lwz} %2,0(%1)";
+
+  for (i = 0; i < words; i++)
+    if (refers_to_regno_p (REGNO (operands[2]) + i,
+                          REGNO (operands[2]) + i + 1, operands[1], 0))
+      {
+       if (i == words-1)
+         {
+           xop[0] = GEN_INT (4 * (words-1));
+           xop[1] = operands[1];
+           xop[2] = operands[2];
+           output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
+           return "";
+         }
+       else if (i == 0)
+         {
+           xop[0] = GEN_INT (4 * (words-1));
+           xop[1] = operands[1];
+           xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
+           output_asm_insn ("{cal %1,4(%1)|addi %1,%1,4}\n\t{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,-4(%1)", xop);
+           return "";
+         }
+       else
+         {
+           for (j = 0; j < words; j++)
+             if (j != i)
+               {
+                 xop[0] = GEN_INT (j * 4);
+                 xop[1] = operands[1];
+                 xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
+                 output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
+               }
+           xop[0] = GEN_INT (i * 4);
+           xop[1] = operands[1];
+           output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
+           return "";
+         }
+      }
+
+  return "{lsi|lswi} %2,%1,%N0";
+}
+
 /* Return 1 for a parallel vrsave operation.  */
 
 int
@@ -6517,7 +6993,7 @@ mtcrf_operation (op, mode)
       maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
       
       if (GET_CODE (unspec) != UNSPEC
-         || XINT (unspec, 1) != 20
+         || XINT (unspec, 1) != UNSPEC_MOVESI_TO_CR
          || XVECLEN (unspec, 0) != 2
          || XVECEXP (unspec, 0, 0) != src_reg
          || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
@@ -6555,14 +7031,14 @@ lmw_operation (op, mode)
       || count != 32 - (int) dest_regno)
     return 0;
 
-  if (LEGITIMATE_INDIRECT_ADDRESS_P (src_addr, 0))
+  if (legitimate_indirect_address_p (src_addr, 0))
     {
       offset = 0;
       base_regno = REGNO (src_addr);
       if (base_regno == 0)
        return 0;
     }
-  else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, src_addr, 0))
+  else if (legitimate_offset_address_p (SImode, src_addr, 0))
     {
       offset = INTVAL (XEXP (src_addr, 1));
       base_regno = REGNO (XEXP (src_addr, 0));
@@ -6585,12 +7061,12 @@ lmw_operation (op, mode)
          || GET_MODE (SET_SRC (elt)) != SImode)
        return 0;
       newaddr = XEXP (SET_SRC (elt), 0);
-      if (LEGITIMATE_INDIRECT_ADDRESS_P (newaddr, 0))
+      if (legitimate_indirect_address_p (newaddr, 0))
        {
          newoffset = 0;
          addr_reg = newaddr;
        }
-      else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, newaddr, 0))
+      else if (legitimate_offset_address_p (SImode, newaddr, 0))
        {
          addr_reg = XEXP (newaddr, 0);
          newoffset = INTVAL (XEXP (newaddr, 1));
@@ -6633,14 +7109,14 @@ stmw_operation (op, mode)
       || count != 32 - (int) src_regno)
     return 0;
 
-  if (LEGITIMATE_INDIRECT_ADDRESS_P (dest_addr, 0))
+  if (legitimate_indirect_address_p (dest_addr, 0))
     {
       offset = 0;
       base_regno = REGNO (dest_addr);
       if (base_regno == 0)
        return 0;
     }
-  else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, dest_addr, 0))
+  else if (legitimate_offset_address_p (SImode, dest_addr, 0))
     {
       offset = INTVAL (XEXP (dest_addr, 1));
       base_regno = REGNO (XEXP (dest_addr, 0));
@@ -6663,12 +7139,12 @@ stmw_operation (op, mode)
          || GET_MODE (SET_DEST (elt)) != SImode)
        return 0;
       newaddr = XEXP (SET_DEST (elt), 0);
-      if (LEGITIMATE_INDIRECT_ADDRESS_P (newaddr, 0))
+      if (legitimate_indirect_address_p (newaddr, 0))
        {
          newoffset = 0;
          addr_reg = newaddr;
        }
-      else if (LEGITIMATE_OFFSET_ADDRESS_P (SImode, newaddr, 0))
+      else if (legitimate_offset_address_p (SImode, newaddr, 0))
        {
          addr_reg = XEXP (newaddr, 0);
          newoffset = INTVAL (XEXP (newaddr, 1));
@@ -6713,9 +7189,8 @@ validate_condition_mode (code, mode)
     abort ();
   
   /* These should never be generated except for 
-     flag_unsafe_math_optimizations and flag_finite_math_only.  */
+     flag_finite_math_only.  */
   if (mode == CCFPmode
-      && ! flag_unsafe_math_optimizations
       && ! flag_finite_math_only
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
@@ -6767,39 +7242,20 @@ branch_positive_comparison_operator (op, mode)
 
   code = GET_CODE (op);
   return (code == EQ || code == LT || code == GT
-         || (TARGET_SPE && TARGET_HARD_FLOAT && !TARGET_FPRS && code == NE)
+         || (TARGET_E500 && TARGET_HARD_FLOAT && !TARGET_FPRS && code == NE)
          || code == LTU || code == GTU
          || code == UNORDERED);
 }
 
-/* Return 1 if OP is a comparison operation that is valid for an scc insn.
-   We check the opcode against the mode of the CC value and disallow EQ or
-   NE comparisons for integers.  */
+/* Return 1 if OP is a comparison operation that is valid for an scc
+   insn: it must be a positive comparison.  */
 
 int
 scc_comparison_operator (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  enum rtx_code code = GET_CODE (op);
-  enum machine_mode cc_mode;
-
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return 0;
-
-  if (GET_RTX_CLASS (code) != '<')
-    return 0;
-
-  cc_mode = GET_MODE (XEXP (op, 0));
-  if (GET_MODE_CLASS (cc_mode) != MODE_CC)
-    return 0;
-
-  validate_condition_mode (code, cc_mode);
-
-  if (code == NE && cc_mode != CCFPmode)
-    return 0;
-
-  return 1;
+  return branch_positive_comparison_operator (op, mode);
 }
 
 int
@@ -6871,7 +7327,7 @@ includes_rshift_p (shiftop, andop)
 
 /* Return 1 if ANDOP is a mask suitable for use with an rldic insn
    to perform a left shift.  It must have exactly SHIFTOP least
-   signifigant 0's, then one or more 1's, then zero or more 0's.  */
+   significant 0's, then one or more 1's, then zero or more 0's.  */
 
 int
 includes_rldic_lshift_p (shiftop, andop)
@@ -6889,7 +7345,7 @@ includes_rldic_lshift_p (shiftop, andop)
       shift_mask = ~0;
       shift_mask <<= INTVAL (shiftop);
 
-      /* Find the least signifigant one bit.  */
+      /* Find the least significant one bit.  */
       lsb = c & -c;
 
       /* It must coincide with the LSB of the shift mask.  */
@@ -7089,7 +7545,11 @@ addrs_ok_for_quad_peep (addr1, addr2)
       offset1 = 0;
     }
 
-  /* Make sure the second address is a (mem (plus (reg) (const_int))).  */
+/* Make sure the second address is a (mem (plus (reg) (const_int)))
+    or if it is (mem (reg)) then make sure that offset1 is -8 and the same 
+    register as addr1.  */
+  if (offset1 == -8 && GET_CODE (addr2) == REG && reg1 == REGNO (addr2))
+   return 1;
   if (GET_CODE (addr2) != PLUS)
     return 0;
 
@@ -7121,7 +7581,11 @@ secondary_reload_class (class, mode, in)
 {
   int regno;
 
-  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN && flag_pic))
+  if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
+#if TARGET_MACHO
+                    && MACHOPIC_INDIRECT
+#endif
+                    ))
     {
       /* We cannot copy a symbolic operand directly into anything
          other than BASE_REGS for TARGET_ELF.  So indicate that a
@@ -7216,14 +7680,22 @@ ccr_bit (op, scc_p)
 
   validate_condition_mode (code, cc_mode);
 
+  /* When generating a sCOND operation, only positive conditions are
+     allowed.  */
+  if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
+      && code != GTU && code != LTU)
+    abort ();
+  
   switch (code)
     {
     case NE:
-      if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+      if (TARGET_E500 && !TARGET_FPRS
+         && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
        return base_bit + 1;
       return scc_p ? base_bit + 3 : base_bit + 2;
     case EQ:
-      if (TARGET_SPE && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
+      if (TARGET_E500 && !TARGET_FPRS
+         && TARGET_HARD_FLOAT && cc_mode == CCFPmode)
        return base_bit + 1;
       return base_bit + 2;
     case GT:  case GTU:  case UNLE:
@@ -7410,42 +7882,6 @@ print_operand (file, x, code)
       /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
         output_operand.  */
 
-    case 'D':
-      /* There used to be a comment for 'C' reading "This is an
-          optional cror needed for certain floating-point
-          comparisons.  Otherwise write nothing."  */
-
-      /* Similar, except that this is for an scc, so we must be able to
-        encode the test in a single bit that is one.  We do the above
-        for any LE, GE, GEU, or LEU and invert the bit for NE.  */
-      if (GET_CODE (x) == LE || GET_CODE (x) == GE
-         || GET_CODE (x) == LEU || GET_CODE (x) == GEU)
-       {
-         int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
-         fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
-                  base_bit + 2,
-                  base_bit + (GET_CODE (x) == GE || GET_CODE (x) == GEU));
-       }
-
-      else if (GET_CODE (x) == NE)
-       {
-         int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
-         fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3,
-                  base_bit + 2, base_bit + 2);
-       }
-      else if (TARGET_SPE && TARGET_HARD_FLOAT
-              && GET_CODE (x) == EQ
-              && GET_MODE (XEXP (x, 0)) == CCFPmode)
-       {
-         int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
-         fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 1,
-                  base_bit + 1, base_bit + 1);
-       }
-      return;
-
     case 'E':
       /* X is a CR register.  Print the number of the EQ bit of the CR */
       if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
@@ -7474,7 +7910,7 @@ print_operand (file, x, code)
 
     case 'G':
       /* X is a constant integer.  If it is negative, print "m",
-        otherwise print "z".  This is to make a aze or ame insn.  */
+        otherwise print "z".  This is to make an aze or ame insn.  */
       if (GET_CODE (x) != CONST_INT)
        output_operand_lossage ("invalid %%G value");
       else if (INTVAL (x) >= 0)
@@ -7708,13 +8144,17 @@ print_operand (file, x, code)
 
       if (uval & 1)    /* Clear Left */
        {
-         uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+#if HOST_BITS_PER_WIDE_INT > 64
+         uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
+#endif
          i = 64;
        }
       else             /* Clear Right */
        {
          uval = ~uval;
-         uval &= ((unsigned HOST_WIDE_INT) 1 << 63 << 1) - 1;
+#if HOST_BITS_PER_WIDE_INT > 64
+         uval &= ((unsigned HOST_WIDE_INT) 1 << 64) - 1;
+#endif
          i = 63;
        }
       while (uval != 0)
@@ -7857,7 +8297,7 @@ print_operand (file, x, code)
 
     case 'X':
       if (GET_CODE (x) == MEM
-         && LEGITIMATE_INDEXED_ADDRESS_P (XEXP (x, 0), 0))
+         && legitimate_indexed_address_p (XEXP (x, 0), 0))
        putc ('x', file);
       return;
 
@@ -7899,7 +8339,6 @@ print_operand (file, x, code)
              break;
 
            case ABI_V4:
-           case ABI_AIX_NODESC:
            case ABI_DARWIN:
              break;
            }
@@ -7938,7 +8377,7 @@ print_operand (file, x, code)
 
        tmp = XEXP (x, 0);
 
-       if (TARGET_SPE)
+       if (TARGET_E500)
          {
            /* Handle [reg].  */
            if (GET_CODE (tmp) == REG)
@@ -8053,7 +8492,7 @@ print_operand_address (file, x)
       fprintf (file, ")(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
     }
 #endif
-  else if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (x))
+  else if (legitimate_constant_pool_address_p (x))
     {
       if (TARGET_AIX && (!TARGET_ELF || !TARGET_MINIMAL_TOC))
        {
@@ -8093,7 +8532,7 @@ print_operand_address (file, x)
     abort ();
 }
 \f
-/* Target hook for assembling integer objects.  The powerpc version has
+/* Target hook for assembling integer objects.  The PowerPC version has
    to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
    is defined.  It also needs to handle DI-mode objects on 64-bit
    targets.  */
@@ -8162,23 +8601,29 @@ rs6000_assemble_integer (x, size, aligned_p)
    VISIBILITY_TYPE.  */
 
 static void
-rs6000_assemble_visibility (decl, visibility_type)
+rs6000_assemble_visibility (decl, vis)
      tree decl;
-     const char *visibility_type;
+     int vis;
 {
-  default_assemble_visibility (decl, visibility_type);
-
   /* Functions need to have their entry point symbol visibility set as
      well as their descriptor symbol visibility.  */
   if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
     {
-      const char *name;
+      static const char * const visibility_types[] = {
+        NULL, "internal", "hidden", "protected"
+      };
+
+      const char *name, *type;
 
       name = ((* targetm.strip_name_encoding)
              (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))));
+      type = visibility_types[vis];
 
-      fprintf (asm_out_file, "\t.%s\t.%s\n", visibility_type, name);
+      fprintf (asm_out_file, "\t.%s\t%s\n", type, name);
+      fprintf (asm_out_file, "\t.%s\t.%s\n", type, name);
     }
+  else
+    default_assemble_visibility (decl, vis);
 }
 #endif
 \f
@@ -8189,7 +8634,10 @@ rs6000_reverse_condition (mode, code)
 {
   /* Reversal of FP compares takes care -- an ordered compare
      becomes an unordered compare and vice versa.  */
-  if (mode == CCFPmode)
+  if (mode == CCFPmode 
+      && (!flag_finite_math_only
+         || code == UNLT || code == UNLE || code == UNGT || code == UNGE
+         || code == UNEQ || code == LTGT))
     return reverse_condition_maybe_unordered (code);
   else
     return reverse_condition (code);
@@ -8217,7 +8665,8 @@ rs6000_generate_compare (code)
   compare_result = gen_reg_rtx (comp_mode);
 
   /* SPE FP compare instructions on the GPRs.  Yuck!  */
-  if ((TARGET_SPE && TARGET_HARD_FLOAT) && rs6000_compare_fp_p)
+  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
+      && rs6000_compare_fp_p)
     {
       rtx cmp, or1, or2, or_result, compare_result2;
 
@@ -8227,7 +8676,7 @@ rs6000_generate_compare (code)
        case UNEQ:
        case NE:
        case LTGT:
-         cmp = flag_unsafe_math_optimizations
+         cmp = flag_finite_math_only
            ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
                               rs6000_compare_op1)
            : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
@@ -8239,7 +8688,7 @@ rs6000_generate_compare (code)
        case UNGE:
        case GE:
        case GEU:
-         cmp = flag_unsafe_math_optimizations
+         cmp = flag_finite_math_only
            ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
                               rs6000_compare_op1)
            : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
@@ -8251,7 +8700,7 @@ rs6000_generate_compare (code)
        case UNLE:
        case LE:
        case LEU:
-         cmp = flag_unsafe_math_optimizations
+         cmp = flag_finite_math_only
            ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
                               rs6000_compare_op1)
            : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
@@ -8283,7 +8732,7 @@ rs6000_generate_compare (code)
          compare_result2 = gen_reg_rtx (CCFPmode);
 
          /* Do the EQ.  */
-         cmp = flag_unsafe_math_optimizations
+         cmp = flag_finite_math_only
            ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
                               rs6000_compare_op1)
            : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
@@ -8301,7 +8750,7 @@ rs6000_generate_compare (code)
             bit3  bit2  bit1  bit0
 
             ... bit 2 would be a GT CR alias, so later on we
-            look in the GT bits for the branch instructins.
+            look in the GT bits for the branch instructions.
             However, we must be careful to emit correct RTL in
             the meantime, so optimizations don't get confused.  */
 
@@ -8339,10 +8788,10 @@ rs6000_generate_compare (code)
                                             rs6000_compare_op1)));
   
   /* Some kinds of FP comparisons need an OR operation;
-     except for flag_unsafe_math_optimizations we don't bother.  */
+     under flag_finite_math_only we don't bother.  */
   if (rs6000_compare_fp_p
-      && ! flag_unsafe_math_optimizations
-      && ! (TARGET_HARD_FLOAT && TARGET_SPE)
+      && ! flag_finite_math_only
+      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -8389,8 +8838,28 @@ rs6000_emit_sCOND (code, result)
 {
   rtx condition_rtx;
   enum machine_mode op_mode;
+  enum rtx_code cond_code;
 
   condition_rtx = rs6000_generate_compare (code);
+  cond_code = GET_CODE (condition_rtx);
+
+  if (cond_code == NE
+      || cond_code == GE || cond_code == LE
+      || cond_code == GEU || cond_code == LEU
+      || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
+    {
+      rtx not_result = gen_reg_rtx (CCEQmode);
+      rtx not_op, rev_cond_rtx;
+      enum machine_mode cc_mode;
+      
+      cc_mode = GET_MODE (XEXP (condition_rtx, 0));
+
+      rev_cond_rtx = gen_rtx (rs6000_reverse_condition (cc_mode, cond_code),
+                             SImode, XEXP (condition_rtx, 0), const0_rtx);
+      not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
+      condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
+    }
 
   op_mode = GET_MODE (rs6000_compare_op0);
   if (op_mode == VOIDmode)
@@ -8432,7 +8901,7 @@ rs6000_emit_cbranch (code, loc)
    condition code register and its mode specifies what kind of
    comparison we made.
 
-   REVERSED is non-zero if we should reverse the sense of the comparison.
+   REVERSED is nonzero if we should reverse the sense of the comparison.
 
    INSN is the insn.  */
 
@@ -8461,9 +8930,16 @@ output_cbranch (op, label, reversed, insn)
      reverse_condition_maybe_unordered here always but this
      makes the resulting assembler clearer.  */
   if (really_reversed)
-    code = rs6000_reverse_condition (mode, code);
+    {
+      /* Reversal of FP compares takes care -- an ordered compare
+        becomes an unordered compare and vice versa.  */
+      if (mode == CCFPmode)
+       code = reverse_condition_maybe_unordered (code);
+      else
+       code = reverse_condition (code);
+    }
 
-  if ((TARGET_SPE && TARGET_HARD_FLOAT) && mode == CCFPmode)
+  if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT) && mode == CCFPmode)
     {
       /* The efscmp/tst* instructions twiddle bit 2, which maps nicely
         to the GT bit.  */
@@ -8521,7 +8997,7 @@ output_cbranch (op, label, reversed, insn)
        {
          if (abs (prob) > REG_BR_PROB_BASE / 20
              && ((prob > 0) ^ need_longbranch))
-           pred = "+";
+              pred = "+";
          else
            pred = "-";
        }
@@ -8593,7 +9069,7 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
   /* Eliminate half of the comparisons by switching operands, this
      makes the remaining code simpler.  */
   if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
-      || code == LTGT || code == LT)
+      || code == LTGT || code == LT || code == UNLE)
     {
       code = reverse_condition_maybe_unordered (code);
       temp = true_cond;
@@ -8603,20 +9079,20 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
 
   /* UNEQ and LTGT take four instructions for a comparison with zero,
      it'll probably be faster to use a branch here too.  */
-  if (code == UNEQ)
+  if (code == UNEQ && HONOR_NANS (compare_mode))
     return 0;
   
   if (GET_CODE (op1) == CONST_DOUBLE)
     REAL_VALUE_FROM_CONST_DOUBLE (c1, op1);
     
-  /* We're going to try to implement comparions by performing
+  /* We're going to try to implement comparisons by performing
      a subtract, then comparing against zero.  Unfortunately,
      Inf - Inf is NaN which is not zero, and so if we don't
      know that the operand is finite and the comparison
      would treat EQ different to UNORDERED, we can't do it.  */
-  if (! flag_unsafe_math_optimizations
+  if (HONOR_INFINITIES (compare_mode)
       && code != GT && code != UNGE
-      && (GET_CODE (op1) != CONST_DOUBLE || target_isinf (c1))
+      && (GET_CODE (op1) != CONST_DOUBLE || real_isinf (&c1))
       /* Constructs of the form (a OP b ? a : b) are safe.  */
       && ((! rtx_equal_p (op0, false_cond) && ! rtx_equal_p (op1, false_cond))
          || (! rtx_equal_p (op0, true_cond) 
@@ -8633,7 +9109,7 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
 
   /* If we don't care about NaNs we can reduce some of the comparisons
      down to faster ones.  */
-  if (flag_unsafe_math_optimizations)
+  if (! HONOR_NANS (compare_mode))
     switch (code)
       {
       case GT:
@@ -8679,14 +9155,15 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
       break;
 
     case UNGE:
+      /* a UNGE 0 <-> (a GE 0 || -a UNLT 0) */
       temp = gen_reg_rtx (result_mode);
       emit_insn (gen_rtx_SET (VOIDmode, temp,
                              gen_rtx_IF_THEN_ELSE (result_mode,
                                                    gen_rtx_GE (VOIDmode,
                                                                op0, op1),
                                                    true_cond, false_cond)));
-      false_cond = temp;
-      true_cond = false_cond;
+      false_cond = true_cond;
+      true_cond = temp;
 
       temp = gen_reg_rtx (compare_mode);
       emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
@@ -8694,14 +9171,15 @@ rs6000_emit_cmove (dest, op, true_cond, false_cond)
       break;
 
     case GT:
+      /* a GT 0 <-> (a GE 0 && -a UNLT 0) */
       temp = gen_reg_rtx (result_mode);
       emit_insn (gen_rtx_SET (VOIDmode, temp,
                              gen_rtx_IF_THEN_ELSE (result_mode, 
                                                    gen_rtx_GE (VOIDmode,
                                                                op0, op1),
                                                    true_cond, false_cond)));
-      true_cond = temp;
-      false_cond = true_cond;
+      true_cond = false_cond;
+      false_cond = temp;
 
       temp = gen_reg_rtx (compare_mode);
       emit_insn (gen_rtx_SET (VOIDmode, temp, gen_rtx_NEG (compare_mode, op0)));
@@ -8811,7 +9289,7 @@ first_reg_to_save ()
     if (regs_ever_live[first_reg] 
        && (! call_used_regs[first_reg]
            || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                    || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
       break;
 
@@ -8876,19 +9354,6 @@ compute_vrsave_mask ()
   if (mask == 0)
     return mask;
 
-  /* Next, add all registers that are call-clobbered.  We do this
-     because post-reload register optimizers such as regrename_optimize
-     may choose to use them.  They never change the register class
-     chosen by reload, so cannot create new uses of altivec registers
-     if there were none before, so the early exit above is safe.  */
-  /* ??? Alternately, we could define HARD_REGNO_RENAME_OK to disallow
-     altivec registers not saved in the mask, which might well make the
-     adjustments below more effective in eliding the save/restore of
-     VRSAVE in small functions.  */
-  for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (call_used_regs[i])
-      mask |= ALTIVEC_REG_BIT (i);
-
   /* Next, remove the argument registers from the set.  These must
      be in the VRSAVE mask set by the caller, so we don't need to add
      them in again.  More importantly, the mask we compute here is
@@ -9006,8 +9471,7 @@ is_altivec_return_reg (reg, xyes)
    align the stack at program startup.  A happy side-effect is that
    -mno-eabi libraries can be used with -meabi programs.)
 
-   The EABI configuration defaults to the V.4 layout, unless
-   -mcall-aix is used, in which case the AIX layout is used.  However,
+   The EABI configuration defaults to the V.4 layout.  However,
    the stack alignment requirements may differ.  If -mno-eabi is not
    given, the required stack alignment is 8 bytes; if -mno-eabi is
    given, the required alignment is 16 bytes.  (But see V.4 comment
@@ -9023,23 +9487,32 @@ rs6000_stack_info ()
   static rs6000_stack_t info, zero_info;
   rs6000_stack_t *info_ptr = &info;
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
-  enum rs6000_abi abi;
   int ehrd_size;
   int total_raw_size;
 
   /* Zero all fields portably.  */
   info = zero_info;
 
+  if (TARGET_SPE)
+    {
+      /* Cache value so we don't rescan instruction chain over and over.  */
+      if (cfun->machine->insn_chain_scanned_p == 0)
+       {
+         cfun->machine->insn_chain_scanned_p = 1;
+         info_ptr->spe_64bit_regs_used = (int) spe_func_has_64bit_regs_p ();
+       }
+    }
+
   /* Select which calling sequence.  */
-  info_ptr->abi = abi = DEFAULT_ABI;
+  info_ptr->abi = DEFAULT_ABI;
 
   /* 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.  */
   if (((TARGET_TOC && TARGET_MINIMAL_TOC)
-       || (flag_pic == 1 && abi == ABI_V4)
-       || (flag_pic && abi == ABI_DARWIN))
+       || (flag_pic == 1 && DEFAULT_ABI == ABI_V4)
+       || (flag_pic && DEFAULT_ABI == ABI_DARWIN))
       && info_ptr->first_gp_reg_save > RS6000_PIC_OFFSET_TABLE_REGNUM)
     info_ptr->gp_size = reg_size * (32 - RS6000_PIC_OFFSET_TABLE_REGNUM);
   else
@@ -9051,12 +9524,13 @@ rs6000_stack_info ()
      registers live (not the size they are used in), this proves
      difficult because we'd have to traverse the instruction chain at
      the right time, taking reload into account.  This is a real pain,
-     so we opt to save the GPRs in 64-bits always.  Anyone overly
-     concerned with frame size can fix this.  ;-).
+     so we opt to save the GPRs in 64-bits always if but one register
+     gets used in 64-bits.  Otherwise, all the registers in the frame
+     get saved in 32-bits.
 
-     So... since we save all GPRs (except the SP) in 64-bits, the
+     So... since when we save all GPRs (except the SP) in 64-bits, the
      traditional GP save area will be empty.  */
-  if (TARGET_SPE_ABI)
+  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
     info_ptr->gp_size = 0;
 
   info_ptr->first_fp_reg_save = first_fp_reg_to_save ();
@@ -9072,14 +9546,16 @@ rs6000_stack_info ()
 
   /* Determine if we need to save the link register.  */
   if (rs6000_ra_ever_killed ()
-      || (DEFAULT_ABI == ABI_AIX && current_function_profile)
+      || (DEFAULT_ABI == ABI_AIX
+         && current_function_profile
+         && !TARGET_PROFILE_KERNEL)
 #ifdef TARGET_RELOCATABLE
       || (TARGET_RELOCATABLE && (get_pool_size () != 0))
 #endif
       || (info_ptr->first_fp_reg_save != 64
          && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
       || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
-      || (abi == ABI_V4 && current_function_calls_alloca)
+      || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
       || (DEFAULT_ABI == ABI_DARWIN
          && flag_pic
          && current_function_uses_pic_offset_table)
@@ -9095,7 +9571,7 @@ rs6000_stack_info ()
       || regs_ever_live[CR4_REGNO])
     {
       info_ptr->cr_save_p = 1;
-      if (abi == ABI_V4)
+      if (DEFAULT_ABI == ABI_V4)
        info_ptr->cr_size = reg_size;
     }
 
@@ -9109,7 +9585,9 @@ rs6000_stack_info ()
        continue;
 
       /* SPE saves EH registers in 64-bits.  */
-      ehrd_size = i * (TARGET_SPE_ABI ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
+      ehrd_size = i * (TARGET_SPE_ABI
+                      && info_ptr->spe_64bit_regs_used != 0
+                      ? UNITS_PER_SPE_WORD : UNITS_PER_WORD);
     }
   else
     ehrd_size = 0;
@@ -9122,7 +9600,7 @@ rs6000_stack_info ()
   info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
                                         8);
 
-  if (TARGET_SPE_ABI)
+  if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
     info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
   else
     info_ptr->spe_gp_size = 0;
@@ -9139,14 +9617,13 @@ rs6000_stack_info ()
     }
 
   /* Calculate the offsets.  */
-  switch (abi)
+  switch (DEFAULT_ABI)
     {
     case ABI_NONE:
     default:
       abort ();
 
     case ABI_AIX:
-    case ABI_AIX_NODESC:
     case ABI_DARWIN:
       info_ptr->fp_save_offset   = - info_ptr->fp_size;
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
@@ -9182,7 +9659,7 @@ rs6000_stack_info ()
       info_ptr->gp_save_offset   = info_ptr->fp_save_offset - info_ptr->gp_size;
       info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
 
-      if (TARGET_SPE_ABI)
+      if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
       {
         /* Align stack so SPE GPR save area is aligned on a
            double-word boundary.  */
@@ -9268,14 +9745,18 @@ rs6000_stack_info ()
   if (info_ptr->calls_p)
     info_ptr->push_p = 1;
 
-  else if (abi == ABI_V4)
+  else if (DEFAULT_ABI == ABI_V4)
     info_ptr->push_p = total_raw_size > info_ptr->fixed_size;
 
+  else if (frame_pointer_needed)
+    info_ptr->push_p = 1;
+
+  else if (TARGET_XCOFF && write_symbols != NO_DEBUG)
+    info_ptr->push_p = 1;
+
   else
-    info_ptr->push_p = (frame_pointer_needed
-                       || (abi != ABI_DARWIN && write_symbols != NO_DEBUG)
-                       || ((total_raw_size - info_ptr->fixed_size)
-                           > (TARGET_32BIT ? 220 : 288)));
+    info_ptr->push_p
+      = total_raw_size - info_ptr->fixed_size > (TARGET_32BIT ? 220 : 288);
 
   /* Zero offsets if we're not saving those registers.  */
   if (info_ptr->fp_size == 0)
@@ -9290,7 +9771,9 @@ rs6000_stack_info ()
   if (! TARGET_ALTIVEC_ABI || info_ptr->vrsave_mask == 0)
     info_ptr->vrsave_save_offset = 0;
 
-  if (! TARGET_SPE_ABI || info_ptr->spe_gp_size == 0)
+  if (! TARGET_SPE_ABI
+      || info_ptr->spe_64bit_regs_used == 0
+      || info_ptr->spe_gp_size == 0)
     info_ptr->spe_gp_save_offset = 0;
 
   if (! info_ptr->lr_save_p)
@@ -9305,6 +9788,39 @@ rs6000_stack_info ()
   return info_ptr;
 }
 
+/* Return true if the current function uses any GPRs in 64-bit SIMD
+   mode.  */
+
+static bool
+spe_func_has_64bit_regs_p ()
+{
+  rtx insns, insn;
+
+  /* Functions that save and restore all the call-saved registers will
+     need to save/restore the registers in 64-bits.  */
+  if (current_function_calls_eh_return
+      || current_function_calls_setjmp
+      || current_function_has_nonlocal_goto)
+    return true;
+
+  insns = get_insns ();
+
+  for (insn = NEXT_INSN (insns); insn != NULL_RTX; insn = NEXT_INSN (insn))
+    {
+      if (INSN_P (insn))
+       {
+         rtx i;
+
+         i = PATTERN (insn);
+         if (GET_CODE (i) == SET
+             && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
+           return true;
+       }
+    }
+
+  return false;
+}
+
 void
 debug_stack_info (info)
      rs6000_stack_t *info;
@@ -9323,8 +9839,7 @@ debug_stack_info (info)
     {
     default:            abi_string = "Unknown";        break;
     case ABI_NONE:      abi_string = "NONE";           break;
-    case ABI_AIX:
-    case ABI_AIX_NODESC: abi_string = "AIX";           break;
+    case ABI_AIX:       abi_string = "AIX";            break;
     case ABI_DARWIN:    abi_string = "Darwin";         break;
     case ABI_V4:        abi_string = "V.4";            break;
     }
@@ -9459,7 +9974,7 @@ rs6000_return_addr (count, frame)
   /* Currently we don't optimize very well between prolog and body
      code and for PIC code the code can be actually quite bad, so
      don't try to be too clever here.  */
-  if (count != 0 || flag_pic != 0)
+  if (count != 0 || (DEFAULT_ABI != ABI_AIX && flag_pic))
     {
       cfun->machine->ra_needs_full_frame = 1;
 
@@ -9484,36 +9999,36 @@ rs6000_return_addr (count, frame)
    vector parameters are required to have a prototype, so the argument
    type info must be available here.  (The tail recursion case can work
    with vector parameters, but there's no way to distinguish here.) */
-int
-function_ok_for_sibcall (fndecl)
-    tree fndecl;
+static bool
+rs6000_function_ok_for_sibcall (decl, exp)
+    tree decl;
+    tree exp ATTRIBUTE_UNUSED;
 {
   tree type;
-  if (fndecl)
+  if (decl)
     {
       if (TARGET_ALTIVEC_VRSAVE)
         {
-         for (type = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+         for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
               type; type = TREE_CHAIN (type))
            {
              if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
-               return 0;
+               return false;
            }
         }
       if (DEFAULT_ABI == ABI_DARWIN
-         || (*targetm.binds_local_p) (fndecl))
+         || (*targetm.binds_local_p) (decl))
        {
-         tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (fndecl));
+         tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
 
          if (!lookup_attribute ("longcall", attr_list)
              || lookup_attribute ("shortcall", attr_list))
-           return 1;
+           return true;
        }
     }
-  return 0;
+  return false;
 }
 
-/* function rewritten to handle sibcalls */
 static int
 rs6000_ra_ever_killed ()
 {
@@ -9521,23 +10036,28 @@ rs6000_ra_ever_killed ()
   rtx reg;
   rtx insn;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
+  /* Irritatingly, there are two kinds of thunks -- those created with
+     TARGET_ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go
+     through the regular part of the compiler.  This is a very hacky
+     way to tell them apart.  */
+  if (current_function_is_thunk && !no_new_pseudos)
     return 0;
-#endif
-  /* regs_ever_live has LR marked as used if any sibcalls
-     are present.  Which it is, but this should not force
-     saving and restoring in the prologue/epilog.  Likewise,
-     reg_set_between_p thinks a sibcall clobbers LR, so
-     that is inappropriate. */
+
+  /* regs_ever_live has LR marked as used if any sibcalls are present,
+     but this should not force saving and restoring in the
+     pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
+     clobbers LR, so that is inappropriate. */
+
   /* Also, the prologue can generate a store into LR that
      doesn't really count, like this:
+
         move LR->R0
         bcl to set PIC register
         move LR->R31
         move R0->LR
-     When we're called from the epilog, we need to avoid counting
-     this as a store; thus we ignore any insns with a REG_MAYBE_DEAD note. */
+
+     When we're called from the epilogue, we need to avoid counting
+     this as a store.  */
          
   push_topmost_sequence ();
   top = get_insns ();
@@ -9553,8 +10073,8 @@ rs6000_ra_ever_killed ()
          else if (GET_CODE (insn) == CALL_INSN 
                   && !SIBLING_CALL_P (insn))
            return 1;
-         else if (set_of (reg, insn) != NULL_RTX 
-                  && find_reg_note (insn, REG_MAYBE_DEAD, NULL_RTX) == 0)
+         else if (set_of (reg, insn) != NULL_RTX
+                  && !prologue_epilogue_contains (insn))
            return 1;
        }
     }
@@ -9579,94 +10099,100 @@ void
 rs6000_emit_load_toc_table (fromprolog)
      int fromprolog;
 {
-  rtx dest;
+  rtx dest, insn;
   dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
 
-  if (TARGET_ELF && DEFAULT_ABI != ABI_AIX)
+  if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+    {
+      rtx temp = (fromprolog
+                 ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
+                 : gen_reg_rtx (Pmode));
+      insn = emit_insn (gen_load_toc_v4_pic_si (temp));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+      insn = emit_move_insn (dest, temp);
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
+    }
+  else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
     {
-      if (DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+      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));
+      rtx symF;
+
+      /* possibly create the toc section */
+      if (! toc_initialized)
        {
-         rtx temp = (fromprolog 
-                     ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                     : gen_reg_rtx (Pmode));
-         rs6000_maybe_dead (emit_insn (gen_load_toc_v4_pic_si (temp)));
-         rs6000_maybe_dead (emit_move_insn (dest, temp));
+         toc_section ();
+         function_section (current_function_decl);
        }
-      else if (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));
-         rtx symF;
-
-         /* possibly create the toc section */
-         if (! toc_initialized)
-           {
-             toc_section ();
-             function_section (current_function_decl);
-           }
-  
-         if (fromprolog)
-           {
-             rtx symL;
-         
-             ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
-             symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-
-             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)));
-           }
-         else
-           {
-             rtx tocsym;
-             static int reload_toc_labelno = 0;
 
-             tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
+      if (fromprolog)
+       {
+         rtx symL;
 
-             ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
-             symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+         ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
+         symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
 
-             rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1b (tempLR, 
-                                                                   symF, 
-                                                                   tocsym)));
-             rs6000_maybe_dead (emit_move_insn (dest, tempLR));
-             rs6000_maybe_dead (emit_move_insn (temp0, 
-                                                gen_rtx_MEM (Pmode, dest)));
-           }
-         rs6000_maybe_dead (emit_insn (gen_addsi3 (dest, temp0, dest)));
-       }
-      else if (flag_pic == 0 && TARGET_MINIMAL_TOC)
-        {
-         /* This is for AIX code running in non-PIC ELF.  */
-         char buf[30];
-         rtx realsym;
-         ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
-         realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-         
-         rs6000_maybe_dead (emit_insn (gen_elf_high (dest, realsym)));
-         rs6000_maybe_dead (emit_insn (gen_elf_low (dest, dest, realsym)));
+         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)));
        }
       else
-        abort ();
+       {
+         rtx tocsym;
+         static int reload_toc_labelno = 0;
+
+         tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
+
+         ASM_GENERATE_INTERNAL_LABEL (buf, "LCG", reload_toc_labelno++);
+         symF = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+
+         emit_insn (gen_load_toc_v4_PIC_1b (tempLR, symF, tocsym));
+         emit_move_insn (dest, tempLR);
+         emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
+       }
+      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
     }
-  else
+  else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
+    {
+      /* This is for AIX code running in non-PIC ELF32.  */
+      char buf[30];
+      rtx realsym;
+      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);
+    }
+  else if (DEFAULT_ABI == ABI_AIX)
     {
       if (TARGET_32BIT)
-        rs6000_maybe_dead (emit_insn (gen_load_toc_aix_si (dest)));
+       insn = emit_insn (gen_load_toc_aix_si (dest));
       else
-        rs6000_maybe_dead (emit_insn (gen_load_toc_aix_di (dest)));
+       insn = emit_insn (gen_load_toc_aix_di (dest));
+      if (fromprolog)
+       rs6000_maybe_dead (insn);
     }
+  else
+    abort ();
 }
 
 int   
@@ -9679,8 +10205,8 @@ get_TOC_alias_set ()
 }   
 
 /* This retuns nonzero if the current function uses the TOC.  This is
-   determined by the presence of (unspec ... 7), which is generated by
-   the various load_toc_* patterns.  */
+   determined by the presence of (unspec ... UNSPEC_TOC), which is
+   generated by the various load_toc_* patterns.  */
 
 int
 uses_TOC () 
@@ -9696,7 +10222,7 @@ uses_TOC ()
          if (GET_CODE (pat) == PARALLEL) 
            for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
              if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == UNSPEC 
-                && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == 7)
+                && XINT (XVECEXP (PATTERN (insn), 0, i), 1) == UNSPEC_TOC)
                  return 1;
        }
     return 0;
@@ -9875,14 +10401,14 @@ rs6000_emit_allocate_stack (size, copy_r12)
          && REGNO (stack_limit_rtx) > 1 
          && REGNO (stack_limit_rtx) <= 31)
        {
-         emit_insn (Pmode == SImode
+         emit_insn (TARGET_32BIT
                     ? gen_addsi3 (tmp_reg,
                                   stack_limit_rtx,
                                   GEN_INT (size))
                     : gen_adddi3 (tmp_reg,
                                   stack_limit_rtx,
                                   GEN_INT (size)));
-         
+
          emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
                                    const0_rtx));
        }
@@ -9894,7 +10420,7 @@ rs6000_emit_allocate_stack (size, copy_r12)
                                      gen_rtx_PLUS (Pmode, 
                                                    stack_limit_rtx, 
                                                    GEN_INT (size)));
-         
+
          emit_insn (gen_elf_high (tmp_reg, toload));
          emit_insn (gen_elf_low (tmp_reg, tmp_reg, toload));
          emit_insn (gen_cond_trap (LTU, stack_reg, tmp_reg,
@@ -9918,24 +10444,22 @@ rs6000_emit_allocate_stack (size, copy_r12)
          try_split (PATTERN (insn), insn, 0);
          todec = tmp_reg;
        }
-      
-      if (Pmode == SImode)
-       insn = emit_insn (gen_movsi_update (stack_reg, stack_reg, 
-                                           todec, stack_reg));
-      else
-       insn = emit_insn (gen_movdi_update (stack_reg, stack_reg, 
+
+      insn = emit_insn (TARGET_32BIT
+                       ? gen_movsi_update (stack_reg, stack_reg,
+                                           todec, stack_reg)
+                       : gen_movdi_update (stack_reg, stack_reg, 
                                            todec, stack_reg));
     }
   else
     {
-      if (Pmode == SImode)
-       insn = emit_insn (gen_addsi3 (stack_reg, stack_reg, todec));
-      else
-       insn = emit_insn (gen_adddi3 (stack_reg, stack_reg, todec));
+      insn = emit_insn (TARGET_32BIT
+                       ? gen_addsi3 (stack_reg, stack_reg, todec)
+                       : gen_adddi3 (stack_reg, stack_reg, todec));
       emit_move_insn (gen_rtx_MEM (Pmode, stack_reg),
                      gen_rtx_REG (Pmode, 12));
     }
-  
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = 
     gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
@@ -9945,32 +10469,6 @@ rs6000_emit_allocate_stack (size, copy_r12)
                       REG_NOTES (insn));
 }
 
-/* Add a RTX_FRAME_RELATED note so that dwarf2out_frame_debug_expr
-   knows that:
-
-     (mem (plus (blah) (regXX)))
-
-   is really:
-
-     (mem (plus (blah) (const VALUE_OF_REGXX))).  */
-
-static void
-altivec_frame_fixup (insn, reg, val)
-     rtx insn, reg;
-     HOST_WIDE_INT val;
-{
-  rtx real;
-
-  real = copy_rtx (PATTERN (insn));
-
-  real = replace_rtx (real, reg, GEN_INT (val));
-
-  RTX_FRAME_RELATED_P (insn) = 1;
-  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                       real,
-                                       REG_NOTES (insn));
-}
-
 /* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
    with (plus:P (reg 1) VAL), and with REG2 replaced with RREG if REG2
    is not NULL.  It would be nice if dwarf2out_frame_debug_expr could
@@ -10051,13 +10549,80 @@ rs6000_frame_related (insn, reg, val, reg2, rreg)
     }
   else
     abort ();
-  
+
+  if (TARGET_SPE)
+    real = spe_synthesize_frame_save (real);
+
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
                                        real,
                                        REG_NOTES (insn));
 }
 
+/* Given an SPE frame note, return a PARALLEL of SETs with the
+   original note, plus a synthetic register save.  */
+
+static rtx
+spe_synthesize_frame_save (real)
+     rtx real;
+{
+  rtx synth, offset, reg, real2;
+
+  if (GET_CODE (real) != SET
+      || GET_MODE (SET_SRC (real)) != V2SImode)
+    return real;
+
+  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
+     frame related note.  The parallel contains a set of the register
+     being saved, and another set to a synthetic register (n+1200).
+     This is so we can differentiate between 64-bit and 32-bit saves.
+     Words cannot describe this nastiness.  */
+
+  if (GET_CODE (SET_DEST (real)) != MEM
+      || GET_CODE (XEXP (SET_DEST (real), 0)) != PLUS
+      || GET_CODE (SET_SRC (real)) != REG)
+    abort ();
+
+  /* Transform:
+       (set (mem (plus (reg x) (const y)))
+            (reg z))
+     into:
+       (set (mem (plus (reg x) (const y+4)))
+            (reg z+1200))
+  */
+
+  real2 = copy_rtx (real);
+  PUT_MODE (SET_DEST (real2), SImode);
+  reg = SET_SRC (real2);
+  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
+  synth = copy_rtx (real2);
+
+  if (BYTES_BIG_ENDIAN)
+    {
+      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
+      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
+    }
+
+  reg = SET_SRC (synth);
+
+  synth = replace_rtx (synth, reg,
+                      gen_rtx_REG (SImode, REGNO (reg) + 1200));
+
+  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
+  synth = replace_rtx (synth, offset,
+                      GEN_INT (INTVAL (offset)
+                               + (BYTES_BIG_ENDIAN ? 0 : 4)));
+
+  RTX_FRAME_RELATED_P (synth) = 1;
+  RTX_FRAME_RELATED_P (real2) = 1;
+  if (BYTES_BIG_ENDIAN)
+    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
+  else
+    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
+
+  return real;
+}
+
 /* Returns an insn that has a vrsave set operation with the
    appropriate CLOBBERs.  */
 
@@ -10209,14 +10774,15 @@ rs6000_emit_prologue ()
   int using_store_multiple;
   HOST_WIDE_INT sp_offset = 0;
   
-   if (TARGET_SPE_ABI)
+   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
      {
        reg_mode = V2SImode;
        reg_size = 8;
      }
 
   using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
-                         && !TARGET_SPE_ABI
+                         && (!TARGET_SPE_ABI
+                             || info->spe_64bit_regs_used == 0)
                          && info->first_gp_reg_save < 31);
   saving_FPRs_inline = (info->first_fp_reg_save == 64
                        || FP_SAVE_INLINE (info->first_fp_reg_save));
@@ -10268,7 +10834,8 @@ rs6000_emit_prologue ()
 
            insn = emit_move_insn (mem, savereg);
 
-           altivec_frame_fixup (insn, areg, offset);
+           rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                 areg, GEN_INT (offset));
          }
     }
 
@@ -10396,13 +10963,13 @@ rs6000_emit_prologue ()
        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
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+               && ((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)
+           if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
              {
                int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
                rtx b;
@@ -10496,9 +11063,9 @@ rs6000_emit_prologue ()
       insn = emit_move_insn (mem, cr_save_rtx);
 
       /* Now, there's no way that dwarf2out_frame_debug_expr is going
-        to understand '(unspec:SI [(reg:CC 68) ...] 19)'.  But that's
-        OK.  All we have to do is specify that _one_ condition code
-        register is saved in this stack slot.  The thrower's epilogue
+        to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
+        But that's OK.  All we have to do is specify that _one_ condition
+        code register is saved in this stack slot.  The thrower's epilogue
         will then restore all the call-saved registers.
         We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
@@ -10527,7 +11094,9 @@ rs6000_emit_prologue ()
        it.  We use R11 for this purpose because emit_load_toc_table
        can use register 0.  This allows us to use a plain 'blr' to return
        from the procedure more often.  */
-    int save_LR_around_toc_setup = (TARGET_ELF && flag_pic != 0
+    int save_LR_around_toc_setup = (TARGET_ELF
+                                   && DEFAULT_ABI != ABI_AIX
+                                   && flag_pic
                                    && ! info->lr_save_p
                                    && EXIT_BLOCK_PTR->pred != NULL);
     if (save_LR_around_toc_setup)
@@ -10541,17 +11110,21 @@ rs6000_emit_prologue ()
                      gen_rtx_REG (Pmode, 11));
   }
 
+#if TARGET_MACHO
   if (DEFAULT_ABI == ABI_DARWIN
       && flag_pic && current_function_uses_pic_offset_table)
     {
       rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+      const char *picbase = machopic_function_base_name ();
+      rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
 
-      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest)));
+      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
 
       rs6000_maybe_dead (
        emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
                        gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
     }
+#endif
 }
 
 /* Write function prologue.  */
@@ -10640,15 +11213,17 @@ rs6000_emit_epilogue (sibcall)
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
   int i;
 
-  if (TARGET_SPE_ABI)
+  info = rs6000_stack_info ();
+
+  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
     {
       reg_mode = V2SImode;
       reg_size = 8;
     }
 
-  info = rs6000_stack_info ();
   using_load_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
-                        && !TARGET_SPE_ABI
+                        && (!TARGET_SPE_ABI
+                            || info->spe_64bit_regs_used == 0)
                         && info->first_gp_reg_save < 31);
   restoring_FPRs_inline = (sibcall
                           || current_function_calls_eh_return
@@ -10808,7 +11383,7 @@ rs6000_emit_epilogue (sibcall)
       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
-             && ((DEFAULT_ABI == ABI_V4 && flag_pic == 1)
+             && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
        {
          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, 
@@ -10818,7 +11393,7 @@ rs6000_emit_epilogue (sibcall)
          rtx mem = gen_rtx_MEM (reg_mode, addr);
 
          /* Restore 64-bit quantities for SPE.  */
-         if (TARGET_SPE_ABI)
+         if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
            {
              int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
              rtx b;
@@ -10891,7 +11466,7 @@ rs6000_emit_epilogue (sibcall)
                RTVEC_ELT (r, 1) = GEN_INT (1 << (7-i));
                RTVEC_ELT (p, ndx) =
                  gen_rtx_SET (VOIDmode, gen_rtx_REG (CCmode, CR0_REGNO+i), 
-                              gen_rtx_UNSPEC (CCmode, r, 20));
+                              gen_rtx_UNSPEC (CCmode, r, UNSPEC_MOVESI_TO_CR));
                ndx++;
              }
          emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
@@ -10925,7 +11500,7 @@ rs6000_emit_epilogue (sibcall)
        }
       else if (sp_offset != 0)
        {
-         emit_insn (Pmode == SImode
+         emit_insn (TARGET_32BIT
                     ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
                                   GEN_INT (sp_offset))
                     : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
@@ -10936,7 +11511,7 @@ rs6000_emit_epilogue (sibcall)
   if (current_function_calls_eh_return)
     {
       rtx sa = EH_RETURN_STACKADJ_RTX;
-      emit_insn (Pmode == SImode
+      emit_insn (TARGET_32BIT
                 ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx, sa)
                 : gen_adddi3 (sp_reg_rtx, sp_reg_rtx, sa));
     }
@@ -11051,7 +11626,7 @@ rs6000_output_function_epilogue (file, size)
   if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
       && rs6000_traceback != traceback_none)
     {
-      const char *fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+      const char *fname = NULL;
       const char *language_string = lang_hooks.name;
       int fixed_parms = 0, float_parms = 0, parm_info = 0;
       int i;
@@ -11064,15 +11639,17 @@ rs6000_output_function_epilogue (file, size)
       else
        optional_tbtab = !optimize_size && !TARGET_ELF;
 
-      while (*fname == '.')    /* V.4 encodes . in the name */
-       fname++;
+      if (optional_tbtab)
+       {
+         fname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+         while (*fname == '.') /* V.4 encodes . in the name */
+           fname++;
 
-      /* Need label immediately before tbtab, so we can compute its offset
-        from the function start.  */
-      if (*fname == '*')
-       ++fname;
-      ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
-      ASM_OUTPUT_LABEL (file, fname);
+         /* Need label immediately before tbtab, so we can compute
+            its offset from the function start.  */
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
+         ASM_OUTPUT_LABEL (file, fname);
+       }
 
       /* The .tbtab pseudo-op can only be used for the first eight
         expressions, since it can't handle the possibly variable
@@ -11167,7 +11744,7 @@ rs6000_output_function_epilogue (file, size)
 
                      if (mode == SFmode)
                        bits = 0x2;
-                     else if (mode == DFmode)
+                     else if (mode == DFmode || mode == TFmode)
                        bits = 0x3;
                      else
                        abort ();
@@ -11244,6 +11821,8 @@ rs6000_output_function_epilogue (file, size)
       /* Omit this list of longs, because there are no CTL anchors.  */
 
       /* Length of function name.  */
+      if (*fname == '*')
+       ++fname;
       fprintf (file, "\t.short %d\n", (int) strlen (fname));
 
       /* Function name.  */
@@ -11290,168 +11869,97 @@ rs6000_output_function_epilogue (file, size)
    calls FUNCTION instead of jumping to it.  The generic approach does
    not support varargs.  */
 
-void
-output_mi_thunk (file, thunk_fndecl, delta, function)
+static void
+rs6000_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
      FILE *file;
      tree thunk_fndecl ATTRIBUTE_UNUSED;
-     int delta;
+     HOST_WIDE_INT delta;
+     HOST_WIDE_INT vcall_offset;
      tree function;
 {
-  const char *this_reg =
-    reg_names[ aggregate_value_p (TREE_TYPE (TREE_TYPE (function))) ? 4 : 3 ];
-  const char *prefix;
-  const char *fname;
-  const char *r0        = reg_names[0];
-  const char *toc       = reg_names[2];
-  const char *schain    = reg_names[11];
-  const char *r12       = reg_names[12];
-  char buf[512];
-  static int labelno = 0;
-
-  /* Small constants that can be done by one add instruction.  */
-  if (delta >= -32768 && delta <= 32767)
-    {
-      if (! TARGET_NEW_MNEMONICS)
-       fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta, this_reg);
-      else
-       fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta);
-    }
+  rtx this, insn, funexp;
 
-  /* 64-bit constants.  If "int" is 32 bits, we'll never hit this abort.  */
-  else if (TARGET_64BIT && (delta < -2147483647 - 1 || delta > 2147483647))
-    abort ();
+  reload_completed = 1;
+  no_new_pseudos = 1;
 
-  /* Large constants that can be done by one addis instruction.  */
-  else if ((delta & 0xffff) == 0)
-    asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
-                delta >> 16);
+  /* Mark the end of the (empty) prologue.  */
+  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
 
-  /* 32-bit constants that can be done by an add and addis instruction.  */
+  /* Find the "this" pointer.  If the function returns a structure,
+     the structure return pointer is in r3.  */
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+    this = gen_rtx_REG (Pmode, 4);
   else
-    {
-      /* Break into two pieces, propagating the sign bit from the low
-        word to the upper word.  */
-      int delta_low  = ((delta & 0xffff) ^ 0x8000) - 0x8000;
-      int delta_high = (delta - delta_low) >> 16;
-
-      asm_fprintf (file, "\t{cau|addis} %s,%s,%d\n", this_reg, this_reg,
-                  delta_high);
+    this = gen_rtx_REG (Pmode, 3);
 
-      if (! TARGET_NEW_MNEMONICS)
-       fprintf (file, "\tcal %s,%d(%s)\n", this_reg, delta_low, this_reg);
-      else
-       fprintf (file, "\taddi %s,%s,%d\n", this_reg, this_reg, delta_low);
+  /* Apply the constant offset, if required.  */
+  if (delta)
+    {
+      rtx delta_rtx = GEN_INT (delta);
+      emit_insn (TARGET_32BIT
+                ? gen_addsi3 (this, this, delta_rtx)
+                : gen_adddi3 (this, this, delta_rtx));
     }
 
-  /* Get the prefix in front of the names.  */
-  switch (DEFAULT_ABI)
+  /* Apply the offset from the vtable, if required.  */
+  if (vcall_offset)
     {
-    default:
-      abort ();
-
-    case ABI_AIX:
-      prefix = ".";
-      break;
+      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
+      rtx tmp = gen_rtx_REG (Pmode, 12);
 
-    case ABI_V4:
-    case ABI_AIX_NODESC:
-      prefix = "";
-      break;
+      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
+      emit_insn (TARGET_32BIT
+                ? gen_addsi3 (tmp, tmp, vcall_offset_rtx)
+                : gen_adddi3 (tmp, tmp, vcall_offset_rtx));
+      emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp));
+      emit_insn (TARGET_32BIT
+                ? gen_addsi3 (this, this, tmp)
+                : gen_adddi3 (this, this, tmp));
     }
 
-  /* If the function is compiled in this module, jump to it directly.
-     Otherwise, load up its address and jump to it.  */
-
-  fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
-
-  if (current_file_function_operand (XEXP (DECL_RTL (function), 0), VOIDmode)
-      && (! lookup_attribute ("longcall",
-                             TYPE_ATTRIBUTES (TREE_TYPE (function)))
-         || lookup_attribute ("shortcall",
-                              TYPE_ATTRIBUTES (TREE_TYPE (function)))))
-
+  /* Generate a tail call to the target function.  */
+  if (!TREE_USED (function))
     {
-      fprintf (file, "\tb %s", prefix);
-      assemble_name (file, fname);
-      if (DEFAULT_ABI == ABI_V4 && flag_pic) fputs ("@local", file);
-      putc ('\n', file);
+      assemble_external (function);
+      TREE_USED (function) = 1;
     }
-
-  else
-    {
-      switch (DEFAULT_ABI)
-       {
-       default:
-         abort ();
-
-       case ABI_AIX:
-         /* Set up a TOC entry for the function.  */
-         ASM_GENERATE_INTERNAL_LABEL (buf, "Lthunk", labelno);
-         toc_section ();
-         ASM_OUTPUT_INTERNAL_LABEL (file, "Lthunk", labelno);
-         labelno++;
-
-         if (TARGET_MINIMAL_TOC)
-           fputs (TARGET_32BIT ? "\t.long " : DOUBLE_INT_ASM_OP, file);
-         else
-           {
-             fputs ("\t.tc ", file);
-             assemble_name (file, fname);
-             fputs ("[TC],", file);
-           }
-         assemble_name (file, fname);
-         putc ('\n', file);
-         if (TARGET_ELF)
-           function_section (current_function_decl);
-         else
-           text_section();
-         if (TARGET_MINIMAL_TOC)
-           asm_fprintf (file, (TARGET_32BIT)
-                        ? "\t{l|lwz} %s,%s(%s)\n" : "\tld %s,%s(%s)\n", r12,
-                        TARGET_ELF ? ".LCTOC0@toc" : ".LCTOC..1", toc);
-         asm_fprintf (file, (TARGET_32BIT) ? "\t{l|lwz} %s," : "\tld %s,", r12);
-         assemble_name (file, buf);
-         if (TARGET_ELF && TARGET_MINIMAL_TOC)
-           fputs ("-(.LCTOC1)", file);
-         asm_fprintf (file, "(%s)\n", TARGET_MINIMAL_TOC ? r12 : toc);
-         asm_fprintf (file,
-                      (TARGET_32BIT) ? "\t{l|lwz} %s,0(%s)\n" : "\tld %s,0(%s)\n",
-                      r0, r12);
-
-         asm_fprintf (file,
-                      (TARGET_32BIT) ? "\t{l|lwz} %s,4(%s)\n" : "\tld %s,8(%s)\n",
-                      toc, r12);
-
-         asm_fprintf (file, "\tmtctr %s\n", r0);
-         asm_fprintf (file,
-                      (TARGET_32BIT) ? "\t{l|lwz} %s,8(%s)\n" : "\tld %s,16(%s)\n",
-                      schain, r12);
-
-         asm_fprintf (file, "\tbctr\n");
-         break;
-
-       case ABI_AIX_NODESC:
-       case ABI_V4:
-         fprintf (file, "\tb %s", prefix);
-         assemble_name (file, fname);
-         if (flag_pic) fputs ("@plt", file);
-         putc ('\n', file);
-         break;
+  funexp = XEXP (DECL_RTL (function), 0);
+  SYMBOL_REF_FLAGS (funexp) &= ~SYMBOL_FLAG_LOCAL;
+  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
 
 #if TARGET_MACHO
-       case ABI_DARWIN:
-         fprintf (file, "\tb %s", prefix);
-         if (flag_pic && !machopic_name_defined_p (fname))
-           assemble_name (file, machopic_stub_name (fname));
-         else
-           assemble_name (file, fname);
-         putc ('\n', file);
-         break;
+  if (MACHOPIC_INDIRECT)
+    funexp = machopic_indirect_call_target (funexp);
 #endif
-       }
-    }
-}
 
+  /* gen_sibcall expects reload to convert scratch pseudo to LR so we must
+     generate sibcall RTL explicitly to avoid constraint abort.  */
+  insn = emit_call_insn (
+          gen_rtx_PARALLEL (VOIDmode,
+            gen_rtvec (4,
+                       gen_rtx_CALL (VOIDmode,
+                                     funexp, const0_rtx),
+                       gen_rtx_USE (VOIDmode, const0_rtx),
+                       gen_rtx_USE (VOIDmode,
+                                    gen_rtx_REG (SImode,
+                                                 LINK_REGISTER_REGNUM)),
+                       gen_rtx_RETURN (VOIDmode))));
+  SIBLING_CALL_P (insn) = 1;
+  emit_barrier ();
+
+  /* Run just enough of rest_of_compilation to get the insns emitted.
+     There's not really enough bulk here to make other passes such as
+     instruction scheduling worth while.  Note that use_thunk calls
+     assemble_start_function and assemble_end_function.  */
+  insn = get_insns ();
+  shorten_branches (insn);
+  final_start_function (insn, file, 1);
+  final (insn, file, 1, 0);
+  final_end_function ();
+
+  reload_completed = 0;
+  no_new_pseudos = 0;
+}
 \f
 /* A quick summary of the various types of 'constant-pool tables'
    under PowerPC:
@@ -11480,37 +11988,40 @@ output_mi_thunk (file, thunk_fndecl, delta, function)
 
 */
 
-/* Hash table stuff for keeping track of TOC entries.  */
-
-struct toc_hash_struct 
-{
-  /* `key' will satisfy CONSTANT_P; in fact, it will satisfy
-     ASM_OUTPUT_SPECIAL_POOL_ENTRY_P.  */
-  rtx key;
-  enum machine_mode key_mode;
-  int labelno;
-};
-
-static htab_t toc_hash_table;
-
 /* Hash functions for the hash table.  */
 
 static unsigned
 rs6000_hash_constant (k)
      rtx k;
 {
-  unsigned result = (GET_CODE (k) << 3) ^ GET_MODE (k);
-  const char *format = GET_RTX_FORMAT (GET_CODE (k));
-  int flen = strlen (format);
-  int fidx;
+  enum rtx_code code = GET_CODE (k);
+  enum machine_mode mode = GET_MODE (k);
+  unsigned result = (code << 3) ^ mode;
+  const char *format;
+  int flen, fidx;
   
-  if (GET_CODE (k) == LABEL_REF)
-    return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
+  format = GET_RTX_FORMAT (code);
+  flen = strlen (format);
+  fidx = 0;
 
-  if (GET_CODE (k) == CODE_LABEL)
-    fidx = 3;
-  else
-    fidx = 0;
+  switch (code)
+    {
+    case LABEL_REF:
+      return result * 1231 + (unsigned) INSN_UID (XEXP (k, 0));
+
+    case CONST_DOUBLE:
+      if (mode != VOIDmode)
+       return real_hash (CONST_DOUBLE_REAL_VALUE (k)) * result;
+      flen = 2;
+      break;
+
+    case CODE_LABEL:
+      fidx = 3;
+      break;
+
+    default:
+      break;
+    }
 
   for (; fidx < flen; fidx++)
     switch (format[fidx])
@@ -11544,9 +12055,12 @@ rs6000_hash_constant (k)
                                                  >> CHAR_BIT * i);
          }
        break;
+      case '0':
+       break;
       default:
        abort ();
       }
+
   return result;
 }
 
@@ -11576,39 +12090,6 @@ toc_hash_eq (h1, h2)
   return rtx_equal_p (r1, r2);
 }
 
-/* Mark the hash table-entry HASH_ENTRY.  */
-
-static int
-toc_hash_mark_entry (hash_slot, unused)
-     void ** hash_slot;
-     void * unused ATTRIBUTE_UNUSED;
-{
-  const struct toc_hash_struct * hash_entry = 
-    *(const struct toc_hash_struct **) hash_slot;
-  rtx r = hash_entry->key;
-  ggc_set_mark (hash_entry);
-  /* For CODE_LABELS, we don't want to drag in the whole insn chain...  */
-  if (GET_CODE (r) == LABEL_REF)
-    {
-      ggc_set_mark (r);
-      ggc_set_mark (XEXP (r, 0));
-    }
-  else
-    ggc_mark_rtx (r);
-  return 1;
-}
-
-/* Mark all the elements of the TOC hash-table *HT.  */
-
-static void
-toc_hash_mark_table (vht)
-     void *vht;
-{
-  htab_t *ht = vht;
-  
-  htab_traverse (*ht, toc_hash_mark_entry, (void *)0);
-}
-
 /* These are the names given by the C++ front-end to vtables, and
    vtable-like objects.  Ideally, this logic should not be here;
    instead, there should be some programmatic way of inquiring as
@@ -11662,12 +12143,19 @@ output_toc (file, x, labelno, mode)
 
   /* When the linker won't eliminate them, don't output duplicate
      TOC entries (this happens on AIX if there is any kind of TOC,
-     and on SVR4 under -fPIC or -mrelocatable).  */
-  if (TARGET_TOC)
+     and on SVR4 under -fPIC or -mrelocatable).  Don't do this for
+     CODE_LABELs.  */
+  if (TARGET_TOC && GET_CODE (x) != LABEL_REF)
     {
       struct toc_hash_struct *h;
       void * * found;
       
+      /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
+         time because GGC is not initialised at that point.  */
+      if (toc_hash_table == NULL)
+       toc_hash_table = htab_create_ggc (1021, toc_hash_function, 
+                                         toc_hash_eq, NULL);
+
       h = ggc_alloc (sizeof (*h));
       h->key = x;
       h->key_mode = mode;
@@ -11698,12 +12186,47 @@ output_toc (file, x, labelno, mode)
     ASM_OUTPUT_ALIGN (file, 3);
   }
 
-  ASM_OUTPUT_INTERNAL_LABEL (file, "LC", labelno);
+  (*targetm.asm_out.internal_label) (file, "LC", labelno);
 
   /* Handle FP constants specially.  Note that if we have a minimal
      TOC, things we put here aren't actually in the TOC, so we can allow
      FP constants.  */
-  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
+  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
+    {
+      REAL_VALUE_TYPE rv;
+      long k[4];
+
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
+      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+
+      if (TARGET_64BIT)
+       {
+         if (TARGET_MINIMAL_TOC)
+           fputs (DOUBLE_INT_ASM_OP, file);
+         else
+           fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
+                    k[0] & 0xffffffff, k[1] & 0xffffffff,
+                    k[2] & 0xffffffff, k[3] & 0xffffffff);
+         fprintf (file, "0x%lx%08lx,0x%lx%08lx\n",
+                  k[0] & 0xffffffff, k[1] & 0xffffffff,
+                  k[2] & 0xffffffff, k[3] & 0xffffffff);
+         return;
+       }
+      else
+       {
+         if (TARGET_MINIMAL_TOC)
+           fputs ("\t.long ", file);
+         else
+           fprintf (file, "\t.tc FT_%lx_%lx_%lx_%lx[TC],",
+                    k[0] & 0xffffffff, k[1] & 0xffffffff,
+                    k[2] & 0xffffffff, k[3] & 0xffffffff);
+         fprintf (file, "0x%lx,0x%lx,0x%lx,0x%lx\n",
+                  k[0] & 0xffffffff, k[1] & 0xffffffff,
+                  k[2] & 0xffffffff, k[3] & 0xffffffff);
+         return;
+       }
+    }
+  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
     {
       REAL_VALUE_TYPE rv;
       long k[2];
@@ -12011,6 +12534,7 @@ rs6000_gen_section_name (buf, filename, section_desc)
         {
          strcpy (p, section_desc);
          p += strlen (section_desc);
+         break;
         }
 
       else if (ISALNUM (*q))
@@ -12029,6 +12553,9 @@ void
 output_profile_hook (labelno)
      int labelno ATTRIBUTE_UNUSED;
 {
+  if (TARGET_PROFILE_KERNEL)
+    return;
+
   if (DEFAULT_ABI == ABI_AIX)
     {
 #ifdef NO_PROFILE_COUNTERS
@@ -12057,7 +12584,7 @@ output_profile_hook (labelno)
 #if TARGET_MACHO
       /* For PIC code, set up a stub and collect the caller's address
         from r0, which is where the prologue puts it.  */
-      if (flag_pic)
+      if (MACHOPIC_INDIRECT)
        {
          mcount_name = machopic_stub_name (mcount_name);
          if (current_function_uses_pic_offset_table)
@@ -12080,7 +12607,6 @@ output_function_profiler (file, labelno)
   char buf[100];
   int save_lr = 8;
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
   switch (DEFAULT_ABI)
     {
     default:
@@ -12088,14 +12614,12 @@ output_function_profiler (file, labelno)
 
     case ABI_V4:
       save_lr = 4;
-      /* Fall through.  */
-
-    case ABI_AIX_NODESC:
       if (!TARGET_32BIT)
        {
          warning ("no profiling of 64-bit code for this ABI");
          return;
        }
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
       fprintf (file, "\tmflr %s\n", reg_names[0]);
       if (flag_pic == 1)
        {
@@ -12133,28 +12657,82 @@ output_function_profiler (file, labelno)
          asm_fprintf (file, "@l(%s)\n", reg_names[12]);
        }
 
-      if (current_function_needs_context && DEFAULT_ABI == ABI_AIX_NODESC)
-       {
-         asm_fprintf (file, "\t{st|stw} %s,%d(%s)\n",
-                      reg_names[STATIC_CHAIN_REGNUM],
-                      12, reg_names[1]);
-         fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
-         asm_fprintf (file, "\t{l|lwz} %s,%d(%s)\n",
-                      reg_names[STATIC_CHAIN_REGNUM],
-                      12, reg_names[1]);
-       }
-      else
-       /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
-       fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+      /* ABI_V4 saves the static chain reg with ASM_OUTPUT_REG_PUSH.  */
+      fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
       break;
 
     case ABI_AIX:
     case ABI_DARWIN:
-      /* Don't do anything, done in output_profile_hook ().  */
+      if (!TARGET_PROFILE_KERNEL)
+       {
+         /* Don't do anything, done in output_profile_hook (). */
+       }
+      else
+       {
+         if (TARGET_32BIT)
+           abort ();
+
+         asm_fprintf (file, "\tmflr %s\n", reg_names[0]);
+         asm_fprintf (file, "\tstd %s,16(%s)\n", reg_names[0], reg_names[1]);
+
+         if (current_function_needs_context)
+           {
+             asm_fprintf (file, "\tstd %s,24(%s)\n",
+                          reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
+             fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+             asm_fprintf (file, "\tld %s,24(%s)\n",
+                          reg_names[STATIC_CHAIN_REGNUM], reg_names[1]);
+           }
+         else
+           fprintf (file, "\tbl %s\n", RS6000_MCOUNT);
+       }
       break;
     }
 }
 
+\f
+static int
+rs6000_use_dfa_pipeline_interface ()
+{
+  return 1;
+}
+
+/* Power4 load update and store update instructions are cracked into a
+   load or store and an integer insn which are executed in the same cycle.
+   Branches have their own dispatch slot which does not count against the
+   GCC issue rate, but it changes the program flow so there are no other
+   instructions to issue in this cycle.  */
+
+static int
+rs6000_variable_issue (stream, verbose, insn, more)
+  FILE *stream ATTRIBUTE_UNUSED;
+  int verbose ATTRIBUTE_UNUSED;
+  rtx insn;
+  int more;
+{
+  if (GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return more;
+
+  if (rs6000_cpu == PROCESSOR_POWER4)
+    {
+      enum attr_type type = get_attr_type (insn);
+      if (type == TYPE_LOAD_EXT_U || type == TYPE_LOAD_EXT_UX
+         || type == TYPE_LOAD_UX || type == TYPE_STORE_UX)
+       return 0;
+      else if (type == TYPE_LOAD_U || type == TYPE_STORE_U
+              || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
+              || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
+              || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
+              || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
+              || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
+              || type == TYPE_IDIV || type == TYPE_LDIV)
+       return more > 2 ? more - 2 : 0;
+    }
+
+  return more - 1;
+}
+
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
 
@@ -12198,10 +12776,14 @@ rs6000_adjust_cost (insn, link, dep_insn, cost)
               || rs6000_cpu_attr == CPU_POWER4)
              && recog_memoized (dep_insn)
              && (INSN_CODE (dep_insn) >= 0)
-             && (get_attr_type (dep_insn) == TYPE_COMPARE
+             && (get_attr_type (dep_insn) == TYPE_CMP
+                 || get_attr_type (dep_insn) == TYPE_COMPARE
                  || get_attr_type (dep_insn) == TYPE_DELAYED_COMPARE
+                 || get_attr_type (dep_insn) == TYPE_IMUL_COMPARE
+                 || get_attr_type (dep_insn) == TYPE_LMUL_COMPARE
                  || get_attr_type (dep_insn) == TYPE_FPCOMPARE
-                 || get_attr_type (dep_insn) == TYPE_CR_LOGICAL))
+                 || get_attr_type (dep_insn) == TYPE_CR_LOGICAL
+                 || get_attr_type (dep_insn) == TYPE_DELAYED_CR))
            return cost + 2;
        default:
          break;
@@ -12261,15 +12843,21 @@ rs6000_adjust_priority (insn, priority)
 static int
 rs6000_issue_rate ()
 {
+  /* Use issue rate of 1 for first scheduling pass to decrease degradation.  */
+  if (!reload_completed)
+    return 1;
+
   switch (rs6000_cpu_attr) {
   case CPU_RIOS1:  /* ? */
   case CPU_RS64A:
   case CPU_PPC601: /* ? */
   case CPU_PPC7450:
     return 3;
+  case CPU_PPC440:
   case CPU_PPC603:
   case CPU_PPC750:
   case CPU_PPC7400:
+  case CPU_PPC8540:
     return 2; 
   case CPU_RIOS2:
   case CPU_PPC604:
@@ -12283,6 +12871,17 @@ rs6000_issue_rate ()
   }
 }
 
+/* Return how many instructions to look ahead for better insn
+   scheduling.  */
+
+static int
+rs6000_use_sched_lookahead ()
+{
+  if (rs6000_cpu_attr == CPU_PPC8540)
+    return 4;
+  return 0;
+}
+
 \f
 /* Length in units of the trampoline for entering a nested function.  */
 
@@ -12302,7 +12901,6 @@ rs6000_trampoline_size ()
 
     case ABI_DARWIN:
     case ABI_V4:
-    case ABI_AIX_NODESC:
       ret = (TARGET_32BIT) ? 40 : 48;
       break;
     }
@@ -12350,7 +12948,6 @@ rs6000_initialize_trampoline (addr, fnaddr, cxt)
     /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
     case ABI_DARWIN:
     case ABI_V4:
-    case ABI_AIX_NODESC:
       emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
                         FALSE, VOIDmode, 4,
                         addr, pmode,
@@ -12473,6 +13070,10 @@ rs6000_elf_select_section (decl, reloc, align)
      int reloc;
      unsigned HOST_WIDE_INT align;
 {
+  /* Pretend that we're always building for a shared library when
+     ABI_AIX, because otherwise we end up with dynamic relocations
+     in read-only sections.  This happens for function pointers,
+     references to vtables in typeinfo, and probably other cases.  */
   default_elf_select_section_1 (decl, reloc, align,
                                flag_pic || DEFAULT_ABI == ABI_AIX);
 }
@@ -12483,106 +13084,47 @@ rs6000_elf_select_section (decl, reloc, align)
    link-time relocations.  If you do not define this macro, GCC will use
    the symbol name prefixed by `.' as the section name.  Note - this
    macro can now be called for uninitialized data items as well as
-   initialised data and functions.  */
+   initialized data and functions.  */
 
 static void
 rs6000_elf_unique_section (decl, reloc)
      tree decl;
      int reloc;
 {
+  /* As above, pretend that we're always building for a shared library
+     when ABI_AIX, to avoid dynamic relocations in read-only sections.  */
   default_unique_section_1 (decl, reloc,
                            flag_pic || DEFAULT_ABI == ABI_AIX);
 }
-
 \f
-/* If we are referencing a function that is static or is known to be
-   in this file, make the SYMBOL_REF special.  We can use this to indicate
-   that we can branch to this function without emitting a no-op after the
-   call.  For real AIX calling sequences, we also replace the
-   function name with the real name (1 or 2 leading .'s), rather than
-   the function descriptor name.  This saves a lot of overriding code
-   to read the prefixes.  */
+/* For a SYMBOL_REF, set generic flags and then perform some
+   target-specific processing.
+
+   When the AIX ABI is requested on a non-AIX system, replace the
+   function name with the real name (with a leading .) rather than the
+   function descriptor name.  This saves a lot of overriding code to
+   read the prefixes.  */
 
 static void
-rs6000_elf_encode_section_info (decl, first)
+rs6000_elf_encode_section_info (decl, rtl, first)
      tree decl;
+     rtx rtl;
      int first;
 {
-  if (!first)
-    return;
+  default_encode_section_info (decl, rtl, first);
 
-  if (TREE_CODE (decl) == FUNCTION_DECL)
+  if (first
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && !TARGET_AIX
+      && DEFAULT_ABI == ABI_AIX)
     {
-      rtx sym_ref = XEXP (DECL_RTL (decl), 0);
-      if ((TREE_ASM_WRITTEN (decl) || ! TREE_PUBLIC (decl))
-          && ! DECL_WEAK (decl))
-       SYMBOL_REF_FLAG (sym_ref) = 1;
-
-      if (DEFAULT_ABI == ABI_AIX)
-       {
-         size_t len1 = (DEFAULT_ABI == ABI_AIX) ? 1 : 2;
-         size_t len2 = strlen (XSTR (sym_ref, 0));
-         char *str = alloca (len1 + len2 + 1);
-         str[0] = '.';
-         str[1] = '.';
-         memcpy (str + len1, XSTR (sym_ref, 0), len2 + 1);
-
-         XSTR (sym_ref, 0) = ggc_alloc_string (str, len1 + len2);
-       }
+      rtx sym_ref = XEXP (rtl, 0);
+      size_t len = strlen (XSTR (sym_ref, 0));
+      char *str = alloca (len + 2);
+      str[0] = '.';
+      memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
+      XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
     }
-  else if (rs6000_sdata != SDATA_NONE
-          && DEFAULT_ABI == ABI_V4
-          && TREE_CODE (decl) == VAR_DECL)
-    {
-      int size = int_size_in_bytes (TREE_TYPE (decl));
-      tree section_name = DECL_SECTION_NAME (decl);
-      const char *name = (char *)0;
-      int len = 0;
-
-      if (section_name)
-       {
-         if (TREE_CODE (section_name) == STRING_CST)
-           {
-             name = TREE_STRING_POINTER (section_name);
-             len = TREE_STRING_LENGTH (section_name);
-           }
-         else
-           abort ();
-       }
-
-      if ((size > 0 && size <= g_switch_value)
-         || (name
-             && ((len == sizeof (".sdata") - 1
-                  && strcmp (name, ".sdata") == 0)
-                 || (len == sizeof (".sdata2") - 1
-                     && strcmp (name, ".sdata2") == 0)
-                 || (len == sizeof (".sbss") - 1
-                     && strcmp (name, ".sbss") == 0)
-                 || (len == sizeof (".sbss2") - 1
-                     && strcmp (name, ".sbss2") == 0)
-                 || (len == sizeof (".PPC.EMB.sdata0") - 1
-                     && strcmp (name, ".PPC.EMB.sdata0") == 0)
-                 || (len == sizeof (".PPC.EMB.sbss0") - 1
-                     && strcmp (name, ".PPC.EMB.sbss0") == 0))))
-       {
-         rtx sym_ref = XEXP (DECL_RTL (decl), 0);
-         size_t len = strlen (XSTR (sym_ref, 0));
-         char *str = alloca (len + 2);
-
-         str[0] = '@';
-         memcpy (str + 1, XSTR (sym_ref, 0), len + 1);
-         XSTR (sym_ref, 0) = ggc_alloc_string (str, len + 1);
-       }
-    }
-}
-
-static const char *
-rs6000_elf_strip_name_encoding (str)
-     const char *str;
-{
-  while (*str == '*' || *str == '@')
-    str++;
-  return str;
 }
 
 static bool
@@ -12597,7 +13139,10 @@ rs6000_elf_in_small_data_p (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, ".sbss") == 0
+         || strcmp (section, ".sbss2") == 0
+         || strcmp (section, ".PPC.EMB.sdata0") == 0
+         || strcmp (section, ".PPC.EMB.sbss0") == 0)
        return true;
     }
   else
@@ -12606,6 +13151,8 @@ rs6000_elf_in_small_data_p (decl)
 
       if (size > 0
          && size <= g_switch_value
+         /* If it's not public, and we're not going to reference it there,
+            there's no need to put it in the small data section.  */
          && (rs6000_sdata != SDATA_DATA || TREE_PUBLIC (decl)))
        return true;
     }
@@ -12654,17 +13201,6 @@ rs6000_fatal_bad_address (op)
   fatal_insn ("bad address", op);
 }
 
-/* Called to register all of our global variables with the garbage
-   collector.  */
-
-static void
-rs6000_add_gc_roots ()
-{
-  toc_hash_table = htab_create (1021, toc_hash_function, toc_hash_eq, NULL);
-  ggc_add_root (&toc_hash_table, 1, sizeof (toc_hash_table), 
-               toc_hash_mark_table);
-}
-
 #if TARGET_MACHO
 
 #if 0
@@ -12885,9 +13421,10 @@ machopic_output_stub (file, symb, stub)
   GEN_LOCAL_LABEL_FOR_SYMBOL (local_label_0, symb, length, 0);
 
   if (flag_pic == 2)
-    machopic_picsymbol_stub_section ();
+    machopic_picsymbol_stub1_section ();
   else
-    machopic_symbol_stub_section ();
+    machopic_symbol_stub1_section ();
+  fprintf (file, "\t.align 2\n");
 
   fprintf (file, "%s:\n", stub);
   fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
@@ -12900,15 +13437,18 @@ machopic_output_stub (file, symb, stub)
       fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
               lazy_ptr_name, local_label_0);
       fprintf (file, "\tmtlr r0\n");
-      fprintf (file, "\tlwz r12,lo16(%s-%s)(r11)\n",
+      fprintf (file, "\tlwzu r12,lo16(%s-%s)(r11)\n",
               lazy_ptr_name, local_label_0);
       fprintf (file, "\tmtctr r12\n");
-      fprintf (file, "\taddi r11,r11,lo16(%s-%s)\n",
-              lazy_ptr_name, local_label_0);
       fprintf (file, "\tbctr\n");
     }
   else
-    fprintf (file, "non-pure not supported\n");
+   {
+     fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
+     fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
+     fprintf (file, "\tmtctr r12\n");
+     fprintf (file, "\tbctr\n");
+   }
   
   machopic_lazy_symbol_ptr_section ();
   fprintf (file, "%s:\n", lazy_ptr_name);
@@ -13200,29 +13740,343 @@ rs6000_xcoff_section_type_flags (decl, name, reloc)
 
   return flags | (exact_log2 (align) & SECTION_ENTSIZE);
 }
-
 #endif /* TARGET_XCOFF */
 
-/* Note that this is also used for PPC64 Linux.  */
+#if TARGET_MACHO
+/* Cross-module name binding.  Darwin does not support overriding
+   functions at dynamic-link time.  */
 
-static void
-rs6000_xcoff_encode_section_info (decl, first)
+static bool
+rs6000_binds_local_p (decl)
      tree decl;
-     int first ATTRIBUTE_UNUSED;
 {
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && (TREE_ASM_WRITTEN (decl) || ! TREE_PUBLIC (decl))
-      && ! DECL_WEAK (decl))
-    SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+  return default_binds_local_p_1 (decl, 0);
 }
+#endif
 
-/* Cross-module name binding.  For AIX and PPC64 Linux, which always are
-   PIC, use private copy of flag_pic.  */
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-rs6000_binds_local_p (decl)
-     tree decl;
+rs6000_rtx_costs (x, code, outer_code, total)
+     rtx x;
+     int code, outer_code ATTRIBUTE_UNUSED;
+     int *total;
 {
-  return default_binds_local_p_1 (decl, flag_pic || rs6000_flag_pic);
+  switch (code)
+    {
+      /* On the RS/6000, if it is valid in the insn, it is free.
+        So this always returns 0.  */
+    case CONST_INT:
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST_DOUBLE:
+    case HIGH:
+      *total = 0;
+      return true;
+
+    case PLUS:
+      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
+                && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
+                                              + 0x8000) >= 0x10000)
+                && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
+               ? COSTS_N_INSNS (2)
+               : COSTS_N_INSNS (1));
+      return true;
+
+    case AND:
+    case IOR:
+    case XOR:
+      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
+                && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
+                && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
+               ? COSTS_N_INSNS (2)
+               : COSTS_N_INSNS (1));
+      return true;
+
+    case MULT:
+      if (optimize_size)
+       {
+         *total = COSTS_N_INSNS (2);
+         return true;
+       }
+      switch (rs6000_cpu)
+       {
+       case PROCESSOR_RIOS1:
+       case PROCESSOR_PPC405:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? COSTS_N_INSNS (5)
+                   : (INTVAL (XEXP (x, 1)) >= -256
+                      && INTVAL (XEXP (x, 1)) <= 255)
+                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
+         return true;
+
+       case PROCESSOR_PPC440:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? COSTS_N_INSNS (3)
+                   : COSTS_N_INSNS (2));
+         return true;
+
+       case PROCESSOR_RS64A:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
+                   : (INTVAL (XEXP (x, 1)) >= -256
+                      && INTVAL (XEXP (x, 1)) <= 255)
+                   ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
+         return true;
+
+       case PROCESSOR_RIOS2:
+       case PROCESSOR_MPCCORE:
+       case PROCESSOR_PPC604e:
+         *total = COSTS_N_INSNS (2);
+         return true;
+
+       case PROCESSOR_PPC601:
+         *total = COSTS_N_INSNS (5);
+         return true;
+
+       case PROCESSOR_PPC603:
+       case PROCESSOR_PPC7400:
+       case PROCESSOR_PPC750:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? COSTS_N_INSNS (5)
+                   : (INTVAL (XEXP (x, 1)) >= -256
+                      && INTVAL (XEXP (x, 1)) <= 255)
+                   ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
+         return true;
+
+       case PROCESSOR_PPC7450:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? COSTS_N_INSNS (4)
+                   : COSTS_N_INSNS (3));
+         return true;
+
+       case PROCESSOR_PPC403:
+       case PROCESSOR_PPC604:
+       case PROCESSOR_PPC8540:
+         *total = COSTS_N_INSNS (4);
+         return true;
+
+       case PROCESSOR_PPC620:
+       case PROCESSOR_PPC630:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
+                   : (INTVAL (XEXP (x, 1)) >= -256
+                      && INTVAL (XEXP (x, 1)) <= 255)
+                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
+         return true;
+
+       case PROCESSOR_POWER4:
+         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
+                   ? GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
+                   : COSTS_N_INSNS (2));
+         return true;
+
+       default:
+         abort ();
+       }
+
+    case DIV:
+    case MOD:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
+       {
+         *total = COSTS_N_INSNS (2);
+         return true;
+       }
+      /* FALLTHRU */
+
+    case UDIV:
+    case UMOD:
+      switch (rs6000_cpu)
+       {
+       case PROCESSOR_RIOS1:
+         *total = COSTS_N_INSNS (19);
+         return true;
+
+       case PROCESSOR_RIOS2:
+         *total = COSTS_N_INSNS (13);
+         return true;
+
+       case PROCESSOR_RS64A:
+         *total = (GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (65)
+                   : COSTS_N_INSNS (67));
+         return true;
+
+       case PROCESSOR_MPCCORE:
+         *total = COSTS_N_INSNS (6);
+         return true;
+
+       case PROCESSOR_PPC403:
+         *total = COSTS_N_INSNS (33);
+         return true;
+
+       case PROCESSOR_PPC405:
+         *total = COSTS_N_INSNS (35);
+         return true;
+
+       case PROCESSOR_PPC440:
+         *total = COSTS_N_INSNS (34);
+         return true;
+
+       case PROCESSOR_PPC601:
+         *total = COSTS_N_INSNS (36);
+         return true;
+
+       case PROCESSOR_PPC603:
+         *total = COSTS_N_INSNS (37);
+         return true;
+
+       case PROCESSOR_PPC604:
+       case PROCESSOR_PPC604e:
+         *total = COSTS_N_INSNS (20);
+         return true;
+
+       case PROCESSOR_PPC620:
+       case PROCESSOR_PPC630:
+         *total = (GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (21)
+                   : COSTS_N_INSNS (37));
+         return true;
+
+       case PROCESSOR_PPC750:
+       case PROCESSOR_PPC8540:
+       case PROCESSOR_PPC7400:
+         *total = COSTS_N_INSNS (19);
+         return true;
+
+       case PROCESSOR_PPC7450:
+         *total = COSTS_N_INSNS (23);
+         return true;
+
+       case PROCESSOR_POWER4:
+         *total = (GET_MODE (XEXP (x, 1)) != DImode
+                   ? COSTS_N_INSNS (18)
+                   : COSTS_N_INSNS (34));
+         return true;
+
+       default:
+         abort ();
+       }
+
+    case FFS:
+      *total = COSTS_N_INSNS (4);
+      return true;
+
+    case MEM:
+      /* MEM should be slightly more expensive than (plus (reg) (const)) */
+      *total = 5;
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+/* A C expression returning the cost of moving data from a register of class
+   CLASS1 to one of CLASS2.  */
+
+int
+rs6000_register_move_cost (mode, from, to)
+     enum machine_mode mode;
+     enum reg_class from, to;
+{
+  /*  Moves from/to GENERAL_REGS.  */
+  if (reg_classes_intersect_p (to, GENERAL_REGS)
+      || reg_classes_intersect_p (from, GENERAL_REGS))
+    {
+      if (! reg_classes_intersect_p (to, GENERAL_REGS))
+       from = to;
+
+      if (from == FLOAT_REGS || from == ALTIVEC_REGS)
+       return (rs6000_memory_move_cost (mode, from, 0)
+               + rs6000_memory_move_cost (mode, GENERAL_REGS, 0));
+
+/* It's more expensive to move CR_REGS than CR0_REGS because of the shift...*/
+      else if (from == CR_REGS)
+       return 4;
+
+      else
+/* A move will cost one instruction per GPR moved.  */
+       return 2 * HARD_REGNO_NREGS (0, mode);
+    }
+
+/* Moving between two similar registers is just one instruction.  */
+  else if (reg_classes_intersect_p (to, from))
+    return mode == TFmode ? 4 : 2;
+
+/* Everything else has to go through GENERAL_REGS.  */
+  else
+    return (rs6000_register_move_cost (mode, GENERAL_REGS, to) 
+           + rs6000_register_move_cost (mode, from, GENERAL_REGS));
+}
+
+/* A C expressions returning the cost of moving data of MODE from a register to
+   or from memory.  */
+
+int
+rs6000_memory_move_cost (mode, class, in)
+  enum machine_mode mode;
+  enum reg_class class;
+  int in ATTRIBUTE_UNUSED;
+{
+  if (reg_classes_intersect_p (class, GENERAL_REGS))
+    return 4 * HARD_REGNO_NREGS (0, mode);
+  else if (reg_classes_intersect_p (class, FLOAT_REGS))
+    return 4 * HARD_REGNO_NREGS (32, mode);
+  else if (reg_classes_intersect_p (class, ALTIVEC_REGS))
+    return 4 * HARD_REGNO_NREGS (FIRST_ALTIVEC_REGNO, mode);
+  else
+    return 4 + rs6000_register_move_cost (mode, class, GENERAL_REGS);
+}
+
+/* Return true if TYPE is of type __ev64_opaque__.  */
+
+static bool
+is_ev64_opaque_type (type)
+     tree type;
+{
+  return (TARGET_SPE
+         && (type == opaque_V2SI_type_node
+             || type == opaque_V2SF_type_node
+             || type == opaque_p_V2SI_type_node
+             || (TREE_CODE (type) == VECTOR_TYPE
+                 && TYPE_NAME (type)
+                 && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+                 && DECL_NAME (TYPE_NAME (type))
+                 && strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))),
+                            "__ev64_opaque__") == 0)));
+}
+
+static rtx
+rs6000_dwarf_register_span (reg)
+     rtx reg;
+{
+  unsigned regno;
+
+  if (!TARGET_SPE || !SPE_VECTOR_MODE (GET_MODE (reg)))
+    return NULL_RTX;
+
+  regno = REGNO (reg);
+
+  /* The duality of the SPE register size wreaks all kinds of havoc.
+     This is a way of distinguishing r0 in 32-bits from r0 in
+     64-bits.  */
+  return
+    gen_rtx_PARALLEL (VOIDmode,
+                     BYTES_BIG_ENDIAN
+                     ? gen_rtvec (2,
+                                  gen_rtx_REG (SImode, regno + 1200),
+                                  gen_rtx_REG (SImode, regno))
+                     : gen_rtvec (2,
+                                  gen_rtx_REG (SImode, regno),
+                                  gen_rtx_REG (SImode, regno + 1200)));
 }
 
+#include "gt-rs6000.h"