OSDN Git Service

* config/rs6000/rs6000.md (UNSPEC constants): Add UNSPEC_STFIWX.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index fd95f0b..3fc857a 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on IBM RS/6000.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
    This file is part of GCC.
 #include "cfglayout.h"
 #include "sched-int.h"
 #include "tree-gimple.h"
+#include "intl.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
+#if TARGET_MACHO
+#include "gstab.h"  /* for N_SLINE */
+#endif
 
 #ifndef TARGET_NO_PROTOTYPE
 #define TARGET_NO_PROTOTYPE 0
 #endif
 
-#define EASY_VECTOR_15(n) ((n) >= -16 && (n) <= 15)
-#define EASY_VECTOR_15_ADD_SELF(n) ((n) >= 0x10 && (n) <= 0x1e \
-                                          && !((n) & 1))
-
 #define min(A,B)       ((A) < (B) ? (A) : (B))
 #define max(A,B)       ((A) > (B) ? (A) : (B))
 
@@ -79,7 +79,7 @@ typedef struct rs6000_stack {
   int toc_save_p;              /* true if the TOC needs to be saved */
   int push_p;                  /* true if we need to allocate stack space */
   int calls_p;                 /* true if the function makes any calls */
-  int world_save_p;             /* true if we're saving *everything*:
+  int world_save_p;            /* true if we're saving *everything*:
                                   r13-r31, cr, f14-f31, vrsave, v20-v31  */
   enum rs6000_abi abi;         /* which ABI to use */
   int gp_save_offset;          /* offset to save GP regs from initial SP */
@@ -143,6 +143,9 @@ enum rs6000_dependence_cost rs6000_sched_costly_dep;
 const char *rs6000_sched_insert_nops_str;
 enum rs6000_nop_insertion rs6000_sched_insert_nops;
 
+/* Support targetm.vectorize.builtin_mask_for_load.  */
+static GTY(()) tree altivec_builtin_mask_for_load;
+
 /* Size of long double */
 const char *rs6000_long_double_size_string;
 int rs6000_long_double_type_size;
@@ -168,6 +171,9 @@ int rs6000_spe;
 /* Nonzero if floating point operations are done in the GPRs.  */
 int rs6000_float_gprs = 0;
 
+/* Nonzero if we want Darwin's struct-by-value-in-regs ABI.  */
+int rs6000_darwin64_abi;
+
 /* String from -mfloat-gprs=.  */
 const char *rs6000_float_gprs_string;
 
@@ -268,7 +274,8 @@ static GTY(()) int rs6000_sr_alias_set;
 /* Call distance, overridden by -mlongcall and #pragma longcall(1).
    The only place that looks at this is rs6000_set_default_type_attributes;
    everywhere else should rely on the presence or absence of a longcall
-   attribute on the function declaration.  */
+   attribute on the function declaration.  Exception: init_cumulative_args
+   looks at it too, for libcalls.  */
 int rs6000_default_long_calls;
 const char *rs6000_longcall_switch;
 
@@ -291,16 +298,16 @@ struct builtin_description
 /* Target cpu costs.  */
 
 struct processor_costs {
-  const int mulsi;        /* cost of SImode multiplication.  */
+  const int mulsi;       /* cost of SImode multiplication.  */
   const int mulsi_const;  /* cost of SImode multiplication by constant.  */
   const int mulsi_const9; /* cost of SImode mult by short constant.  */
-  const int muldi;        /* cost of DImode multiplication.  */
-  const int divsi;        /* cost of SImode division.  */
-  const int divdi;        /* cost of DImode division.  */
-  const int fp;           /* cost of simple SFmode and DFmode insns.  */
-  const int dmul;         /* cost of DFmode multiplication (and fmadd).  */
-  const int sdiv;         /* cost of SFmode division (fdivs).  */
-  const int ddiv;         /* cost of DFmode division (fdiv).  */
+  const int muldi;       /* cost of DImode multiplication.  */
+  const int divsi;       /* cost of SImode division.  */
+  const int divdi;       /* cost of DImode division.  */
+  const int fp;                  /* cost of simple SFmode and DFmode insns.  */
+  const int dmul;        /* cost of DFmode multiplication (and fmadd).  */
+  const int sdiv;        /* cost of SFmode division (fdivs).  */
+  const int ddiv;        /* cost of DFmode division (fdiv).  */
 };
 
 const struct processor_costs *rs6000_cost;
@@ -594,8 +601,6 @@ struct processor_costs power4_cost = {
 
 \f
 static bool rs6000_function_ok_for_sibcall (tree, tree);
-static int num_insns_constant_wide (HOST_WIDE_INT);
-static void validate_condition_mode (enum rtx_code, enum machine_mode);
 static rtx rs6000_generate_compare (enum rtx_code);
 static void rs6000_maybe_dead (rtx);
 static void rs6000_emit_stack_tie (void);
@@ -611,11 +616,8 @@ static unsigned toc_hash_function (const void *);
 static int toc_hash_eq (const void *, const void *);
 static int constant_pool_expr_1 (rtx, int *, int *);
 static bool constant_pool_expr_p (rtx);
-static bool toc_relative_expr_p (rtx);
 static bool legitimate_small_data_p (enum machine_mode, rtx);
 static bool legitimate_indexed_address_p (rtx, int);
-static bool legitimate_indirect_address_p (rtx, int);
-static bool macho_lo_sum_memory_operand (rtx x, enum machine_mode mode);
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
 static bool rs6000_assemble_integer (rtx, unsigned int, int);
@@ -650,7 +652,7 @@ static bool rs6000_elf_in_small_data_p (tree);
 #endif
 #if TARGET_XCOFF
 static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
-static void rs6000_xcoff_asm_named_section (const char *, unsigned int);
+static void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree);
 static void rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT);
 static void rs6000_xcoff_unique_section (tree, int);
 static void rs6000_xcoff_select_rtx_section (enum machine_mode, rtx,
@@ -681,6 +683,7 @@ static int redefine_groups (FILE *, int, rtx, rtx);
 static int pad_groups (FILE *, int, rtx, rtx);
 static void rs6000_sched_finish (FILE *, int);
 static int rs6000_use_sched_lookahead (void);
+static tree rs6000_builtin_mask_for_load (void);
 
 static void rs6000_init_builtins (void);
 static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
@@ -710,32 +713,42 @@ static rtx altivec_expand_st_builtin (tree, rtx, bool *);
 static rtx altivec_expand_dst_builtin (tree, rtx, bool *);
 static rtx altivec_expand_abs_builtin (enum insn_code, tree, rtx);
 static rtx altivec_expand_predicate_builtin (enum insn_code,
-                                           const char *, tree, rtx);
+                                            const char *, tree, rtx);
 static rtx altivec_expand_lv_builtin (enum insn_code, tree, rtx);
 static rtx altivec_expand_stv_builtin (enum insn_code, tree);
 static void rs6000_parse_abi_options (void);
 static void rs6000_parse_alignment_option (void);
 static void rs6000_parse_tls_size_option (void);
 static void rs6000_parse_yes_no_option (const char *, const char *, int *);
+static void rs6000_parse_float_gprs_option (void);
 static int first_altivec_reg_to_save (void);
 static unsigned int compute_vrsave_mask (void);
-static void compute_save_world_info(rs6000_stack_t *info_ptr);
+static void compute_save_world_info (rs6000_stack_t *info_ptr);
 static void is_altivec_return_reg (rtx, void *);
 static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
 int easy_vector_constant (rtx, enum machine_mode);
-static int easy_vector_same (rtx, enum machine_mode);
-static int easy_vector_splat_const (int, enum machine_mode);
 static bool is_ev64_opaque_type (tree);
 static rtx rs6000_dwarf_register_span (rtx);
 static rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
 static rtx rs6000_tls_get_addr (void);
 static rtx rs6000_got_sym (void);
-static inline int rs6000_tls_symbol_ref_1 (rtx *, void *);
+static int rs6000_tls_symbol_ref_1 (rtx *, void *);
 static const char *rs6000_get_some_local_dynamic_name (void);
 static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
 static rtx rs6000_complex_function_value (enum machine_mode);
 static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree);
+static void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *,
+                                                     HOST_WIDE_INT);
+static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *,
+                                                       tree, HOST_WIDE_INT);
+static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *,
+                                             HOST_WIDE_INT,
+                                             rtx[], int *);
+static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *,
+                                              tree, HOST_WIDE_INT,
+                                              rtx[], int *);
+static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, tree, int, bool);
 static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
 static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
 static void setup_incoming_varargs (CUMULATIVE_ARGS *,
@@ -743,18 +756,30 @@ static void setup_incoming_varargs (CUMULATIVE_ARGS *,
                                    int *, int);
 static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
                                      tree, bool);
+static int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                    tree, bool);
+static const char *invalid_arg_for_unprototyped_fn (tree, tree, tree);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
 static void add_compiler_branch_island (tree, tree, int);
 static int no_previous_def (tree function_name);
 static tree get_prev_label (tree function_name);
+static void rs6000_darwin_file_start (void);
 #endif
 
 static tree rs6000_build_builtin_va_list (void);
 static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
 static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
 static bool rs6000_vector_mode_supported_p (enum machine_mode);
+static int get_vec_cmp_insn (enum rtx_code, enum machine_mode,
+                            enum machine_mode);
+static rtx rs6000_emit_vector_compare (enum rtx_code, rtx, rtx,
+                                      enum machine_mode);
+static int get_vsel_insn (enum machine_mode);
+static void rs6000_emit_vector_select (rtx, rtx, rtx, rtx);
+
 
+const int INSN_NOT_AVAILABLE = -1;
 static enum machine_mode rs6000_eh_return_filter_mode (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
@@ -828,10 +853,6 @@ static const char alt_reg_names[][8] =
 
 /* The VRSAVE bitmask puts bit %v0 as the most significant bit.  */
 #define ALTIVEC_REG_BIT(REGNO) (0x80000000 >> ((REGNO) - FIRST_ALTIVEC_REGNO))
-
-/* Return 1 for a symbol ref for a thread-local storage symbol.  */
-#define RS6000_SYMBOL_REF_TLS_P(RTX) \
-  (GET_CODE (RTX) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (RTX) != 0)
 \f
 /* Initialize the GCC target structure.  */
 #undef TARGET_ATTRIBUTE_TABLE
@@ -905,6 +926,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
 
+#undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
+#define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load
+
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
 
@@ -966,6 +990,8 @@ static const char alt_reg_names[][8] =
 #define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES rs6000_arg_partial_bytes
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
@@ -979,6 +1005,20 @@ static const char alt_reg_names[][8] =
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
 
+#undef TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN
+#define TARGET_INVALID_ARG_FOR_UNPROTOTYPED_FN invalid_arg_for_unprototyped_fn
+
+/* MPC604EUM 3.5.2 Weak Consistency between Multiple Processors
+   The PowerPC architecture requires only weak consistency among
+   processors--that is, memory accesses between processors need not be
+   sequentially consistent and memory accesses among processors can occur
+   in any order. The ability to order memory accesses weakly provides
+   opportunities for more efficient use of the system bus. Unless a
+   dependency exists, the 604e allows read operations to precede store
+   operations.  */
+#undef TARGET_RELAXED_ORDERING
+#define TARGET_RELAXED_ORDERING true
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -1098,6 +1138,8 @@ rs6000_override_options (const char *default_cpu)
         {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        /* 8548 has a dummy entry for now.  */
+        {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
         {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
          POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
@@ -1145,7 +1187,7 @@ rs6000_override_options (const char *default_cpu)
 
   rs6000_init_hard_regno_mode_ok ();
 
- set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
 set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
 #ifdef OS_MISSING_POWERPC64
   if (OS_MISSING_POWERPC64)
     set_masks &= ~MASK_POWERPC64;
@@ -1155,9 +1197,8 @@ rs6000_override_options (const char *default_cpu)
     set_masks &= ~MASK_ALTIVEC;
 #endif
 
-  /* Don't override these by the processor default if given explicitly.  */
-  set_masks &= ~(target_flags_explicit
-                & (MASK_MULTIPLE | MASK_STRING | MASK_SOFT_FLOAT));
+  /* Don't override by the processor default if given explicitly.  */
+  set_masks &= ~target_flags_explicit;
 
   /* Identify the processor type.  */
   rs6000_select[0].string = default_cpu;
@@ -1241,7 +1282,7 @@ rs6000_override_options (const char *default_cpu)
       else if (! strncmp (rs6000_traceback_name, "no", 2))
        rs6000_traceback = traceback_none;
       else
-       error ("unknown -mtraceback arg `%s'; expecting `full', `partial' or `none'",
+       error ("unknown -mtraceback arg %qs; expecting %<full%>, %<partial%> or %<none%>",
               rs6000_traceback_name);
     }
 
@@ -1265,20 +1306,32 @@ rs6000_override_options (const char *default_cpu)
       rs6000_altivec_vrsave = 1;
     }
 
+  /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
+  if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
+    {
+      rs6000_darwin64_abi = 1;
+      /* Setting to empty string is same as "-mone-byte-bool".  */
+#if TARGET_MACHO
+      darwin_one_byte_bool = "";
+#endif
+      /* Default to natural alignment, for better performance.  */
+      rs6000_alignment_flags = MASK_ALIGN_NATURAL;
+    }
+
   /* Handle -mabi= options.  */
   rs6000_parse_abi_options ();
 
   /* Handle -malign-XXXXX option.  */
   rs6000_parse_alignment_option ();
 
+  rs6000_parse_float_gprs_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);
 
   /* Handle -mtls-size option.  */
   rs6000_parse_tls_size_option ();
@@ -1289,6 +1342,9 @@ rs6000_override_options (const char *default_cpu)
 #ifdef SUBSUBTARGET_OVERRIDE_OPTIONS
   SUBSUBTARGET_OVERRIDE_OPTIONS;
 #endif
+#ifdef SUB3TARGET_OVERRIDE_OPTIONS
+  SUB3TARGET_OVERRIDE_OPTIONS;
+#endif
 
   if (TARGET_E500)
     {
@@ -1302,7 +1358,7 @@ rs6000_override_options (const char *default_cpu)
 
       /* No SPE means 64-bit long doubles, even if an E500.  */
       if (rs6000_spe_string != 0
-          && !strcmp (rs6000_spe_string, "no"))
+         && !strcmp (rs6000_spe_string, "no"))
        rs6000_long_double_type_size = 64;
     }
   else if (rs6000_select[1].string != NULL)
@@ -1339,7 +1395,7 @@ rs6000_override_options (const char *default_cpu)
       while (base[-1] != 'm') base--;
 
       if (*rs6000_longcall_switch != '\0')
-       error ("invalid option `%s'", base);
+       error ("invalid option %qs", base);
       rs6000_default_long_calls = (base[0] != 'n');
     }
 
@@ -1350,7 +1406,7 @@ rs6000_override_options (const char *default_cpu)
       while (base[-1] != 'm') base--;
 
       if (*rs6000_warn_altivec_long_switch != '\0')
-       error ("invalid option `%s'", base);
+       error ("invalid option %qs", base);
       rs6000_warn_altivec_long = (base[0] != 'n');
     }
 
@@ -1367,15 +1423,15 @@ rs6000_override_options (const char *default_cpu)
   if (rs6000_sched_costly_dep_str)
     {
       if (! strcmp (rs6000_sched_costly_dep_str, "no"))
-        rs6000_sched_costly_dep = no_dep_costly;
+       rs6000_sched_costly_dep = no_dep_costly;
       else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
-        rs6000_sched_costly_dep = all_deps_costly;
+       rs6000_sched_costly_dep = all_deps_costly;
       else if (! strcmp (rs6000_sched_costly_dep_str, "true_store_to_load"))
-        rs6000_sched_costly_dep = true_store_to_load_dep_costly;
+       rs6000_sched_costly_dep = true_store_to_load_dep_costly;
       else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
-        rs6000_sched_costly_dep = store_to_load_dep_costly;
+       rs6000_sched_costly_dep = store_to_load_dep_costly;
       else
-        rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
+       rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
     }
 
   /* Handle -minsert-sched-nops option.  */
@@ -1384,13 +1440,13 @@ rs6000_override_options (const char *default_cpu)
   if (rs6000_sched_insert_nops_str)
     {
       if (! strcmp (rs6000_sched_insert_nops_str, "no"))
-        rs6000_sched_insert_nops = sched_finish_none;
+       rs6000_sched_insert_nops = sched_finish_none;
       else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
-        rs6000_sched_insert_nops = sched_finish_pad_groups;
+       rs6000_sched_insert_nops = sched_finish_pad_groups;
       else if (! strcmp (rs6000_sched_insert_nops_str, "regroup_exact"))
-        rs6000_sched_insert_nops = sched_finish_regroup_exact;
+       rs6000_sched_insert_nops = sched_finish_regroup_exact;
       else
-        rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
+       rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
     }
 
 #ifdef TARGET_REGNAMES
@@ -1429,9 +1485,23 @@ rs6000_override_options (const char *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;
+  /* Set branch target alignment, if not optimizing for size.  */
+  if (!optimize_size)
+    {
+      if (rs6000_sched_groups)
+       {
+         if (align_functions <= 0)
+           align_functions = 16;
+         if (align_jumps <= 0)
+           align_jumps = 16;
+         if (align_loops <= 0)
+           align_loops = 16;
+       }
+      if (align_jumps_max_skip <= 0)
+       align_jumps_max_skip = 15;
+      if (align_loops_max_skip <= 0)
+       align_loops_max_skip = 15;
+    }
 
   /* Arrange to save and restore machine status around nested functions.  */
   init_machine_status = rs6000_init_machine_status;
@@ -1522,6 +1592,16 @@ rs6000_override_options (const char *default_cpu)
       }
 }
 
+/* Implement targetm.vectorize.builtin_mask_for_load.  */
+static tree
+rs6000_builtin_mask_for_load (void)
+{
+  if (TARGET_ALTIVEC)
+    return altivec_builtin_mask_for_load;
+  else
+    return 0;
+}
+
 /* Handle generic options of the form -mfoo=yes/no.
    NAME is the option name.
    VALUE is the option value.
@@ -1561,12 +1641,42 @@ rs6000_parse_abi_options (void)
        error ("not configured for ABI: '%s'", rs6000_abi_string);
     }
 
+  /* These are here for testing during development only, do not
+     document in the manual please.  */
+  else if (! strcmp (rs6000_abi_string, "d64"))
+    {
+      rs6000_darwin64_abi = 1;
+      warning ("Using darwin64 ABI");
+    }
+  else if (! strcmp (rs6000_abi_string, "d32"))
+    {
+      rs6000_darwin64_abi = 0;
+      warning ("Using old darwin ABI");
+    }
+
   else if (! strcmp (rs6000_abi_string, "no-spe"))
     rs6000_spe_abi = 0;
   else
     error ("unknown ABI specified: '%s'", rs6000_abi_string);
 }
 
+/* Handle -mfloat-gprs= options.  */
+static void
+rs6000_parse_float_gprs_option (void)
+{
+  if (rs6000_float_gprs_string == 0)
+    return;
+  else if (! strcmp (rs6000_float_gprs_string, "yes")
+          || ! strcmp (rs6000_float_gprs_string, "single"))
+    rs6000_float_gprs = 1;
+  else if (! strcmp (rs6000_float_gprs_string, "double"))
+    rs6000_float_gprs = 2;
+  else if (! strcmp (rs6000_float_gprs_string, "no"))
+    rs6000_float_gprs = 0;
+  else
+    error ("invalid option for -mfloat-gprs");
+}
+
 /* Handle -malign-XXXXXX options.  */
 static void
 rs6000_parse_alignment_option (void)
@@ -1574,7 +1684,16 @@ rs6000_parse_alignment_option (void)
   if (rs6000_alignment_string == 0)
     return;
   else if (! strcmp (rs6000_alignment_string, "power"))
-    rs6000_alignment_flags = MASK_ALIGN_POWER;
+    {
+      /* On 64-bit Darwin, power alignment is ABI-incompatible with
+        some C library functions, so warn about it. The flag may be
+        useful for performance studies from time to time though, so
+        don't disable it entirely.  */
+      if (DEFAULT_ABI == ABI_DARWIN && TARGET_64BIT)
+       warning ("-malign-power is not supported for 64-bit Darwin;"
+                " it is incompatible with the installed C and C++ libraries");
+      rs6000_alignment_flags = MASK_ALIGN_POWER;
+    }
   else if (! strcmp (rs6000_alignment_string, "natural"))
     rs6000_alignment_flags = MASK_ALIGN_NATURAL;
   else
@@ -1596,7 +1715,7 @@ rs6000_parse_tls_size_option (void)
   else if (strcmp (rs6000_tls_size_string, "64") == 0)
     rs6000_tls_size = 64;
   else
-    error ("bad value `%s' for -mtls-size switch", rs6000_tls_size_string);
+    error ("bad value %qs for -mtls-size switch", rs6000_tls_size_string);
 }
 
 void
@@ -1658,7 +1777,14 @@ rs6000_file_start (void)
       if (*start == '\0')
        putc ('\n', file);
     }
+
+  if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
+    {
+      toc_section ();
+      text_section ();
+    }
 }
+
 \f
 /* Return nonzero if this function is known to have a null epilogue.  */
 
@@ -1682,313 +1808,10 @@ direct_return (void)
   return 0;
 }
 
-/* Returns 1 always.  */
-
-int
-any_operand (rtx op ATTRIBUTE_UNUSED,
-            enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return 1;
-}
-
-/* Returns 1 always.  */
-
-int
-any_parallel_operand (rtx op ATTRIBUTE_UNUSED,
-                     enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return 1;
-}
-
-/* Returns 1 if op is the count register.  */
-
-int
-count_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (REGNO (op) == COUNT_REGISTER_REGNUM)
-    return 1;
-
-  if (REGNO (op) > FIRST_PSEUDO_REGISTER)
-    return 1;
-
-  return 0;
-}
-
-/* Returns 1 if op is an altivec register.  */
-
-int
-altivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-
-  return (register_operand (op, mode)
-         && (GET_CODE (op) != REG
-             || REGNO (op) > FIRST_PSEUDO_REGISTER
-             || ALTIVEC_REGNO_P (REGNO (op))));
-}
-
-int
-xer_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (XER_REGNO_P (REGNO (op)))
-    return 1;
-
-  return 0;
-}
-
-/* Return 1 if OP is a signed 8-bit constant.  Int multiplication
-   by such constants completes more quickly.  */
-
-int
-s8bit_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return ( GET_CODE (op) == CONST_INT
-         && (INTVAL (op) >= -128 && INTVAL (op) <= 127));
-}
-
-/* Return 1 if OP is a constant that can fit in a D field.  */
-
-int
-short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
-}
-
-/* Similar for an unsigned D field.  */
-
-int
-u_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && CONST_OK_FOR_LETTER_P (INTVAL (op) & GET_MODE_MASK (mode), 'K'));
-}
-
-/* Return 1 if OP is a CONST_INT that cannot fit in a signed D field.  */
-
-int
-non_short_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) >= 0x10000);
-}
-
-/* Returns 1 if OP is a CONST_INT that is a positive value
-   and an exact power of 2.  */
-
-int
-exact_log2_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && INTVAL (op) > 0
-         && exact_log2 (INTVAL (op)) >= 0);
-}
-
-/* Returns 1 if OP is a register that is not special (i.e., not MQ,
-   ctr, or lr).  */
-
-int
-gpc_reg_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         && (GET_CODE (op) != REG
-             || (REGNO (op) >= ARG_POINTER_REGNUM
-                 && !XER_REGNO_P (REGNO (op)))
-             || REGNO (op) < MQ_REGNO));
-}
-
-/* Returns 1 if OP is either a pseudo-register or a register denoting a
-   CR field.  */
-
-int
-cc_reg_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         && (GET_CODE (op) != REG
-             || REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || CR_REGNO_P (REGNO (op))));
-}
-
-/* Returns 1 if OP is either a pseudo-register or a register denoting a
-   CR field that isn't CR0.  */
-
-int
-cc_reg_not_cr0_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         && (GET_CODE (op) != REG
-             || REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || CR_REGNO_NOT_CR0_P (REGNO (op))));
-}
-
-/* Returns 1 if OP is either a constant integer valid for a D-field or
-   a non-special register.  If a register, it must be in the proper
-   mode unless MODE is VOIDmode.  */
-
-int
-reg_or_short_operand (rtx op, enum machine_mode mode)
-{
-  return short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
-}
-
-/* Similar, except check if the negation of the constant would be
-   valid for a D-field.  Don't allow a constant zero, since all the
-   patterns that call this predicate use "addic r1,r2,-constant" on
-   a constant value to set a carry when r2 is greater or equal to
-   "constant".  That doesn't work for zero.  */
-
-int
-reg_or_neg_short_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT)
-    return CONST_OK_FOR_LETTER_P (INTVAL (op), 'P') && INTVAL (op) != 0;
-
-  return gpc_reg_operand (op, mode);
-}
-
-/* Returns 1 if OP is either a constant integer valid for a DS-field or
-   a non-special register.  If a register, it must be in the proper
-   mode unless MODE is VOIDmode.  */
-
-int
-reg_or_aligned_short_operand (rtx op, enum machine_mode mode)
-{
-  if (gpc_reg_operand (op, mode))
-    return 1;
-  else if (short_cint_operand (op, mode) && !(INTVAL (op) & 3))
-    return 1;
-
-  return 0;
-}
-
-
-/* Return 1 if the operand is either a register or an integer whose
-   high-order 16 bits are zero.  */
-
-int
-reg_or_u_short_operand (rtx op, enum machine_mode mode)
-{
-  return u_short_cint_operand (op, mode) || gpc_reg_operand (op, mode);
-}
-
-/* Return 1 is the operand is either a non-special register or ANY
-   constant integer.  */
-
-int
-reg_or_cint_operand (rtx op, enum machine_mode mode)
-{
-  return (GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode));
-}
-
-/* Return 1 is the operand is either a non-special register or ANY
-   32-bit signed constant integer.  */
-
-int
-reg_or_arith_cint_operand (rtx op, enum machine_mode mode)
-{
-  return (gpc_reg_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT
-#if HOST_BITS_PER_WIDE_INT != 32
-             && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80000000)
-                 < (unsigned HOST_WIDE_INT) 0x100000000ll)
-#endif
-             ));
-}
-
-/* Return 1 is the operand is either a non-special register or a 32-bit
-   signed constant integer valid for 64-bit addition.  */
-
-int
-reg_or_add_cint64_operand (rtx op, enum machine_mode mode)
-{
-  return (gpc_reg_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT
-#if HOST_BITS_PER_WIDE_INT == 32
-             && INTVAL (op) < 0x7fff8000
-#else
-             && ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x80008000)
-                 < 0x100000000ll)
-#endif
-             ));
-}
-
-/* Return 1 is the operand is either a non-special register or a 32-bit
-   signed constant integer valid for 64-bit subtraction.  */
-
-int
-reg_or_sub_cint64_operand (rtx op, enum machine_mode mode)
-{
-  return (gpc_reg_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT
-#if HOST_BITS_PER_WIDE_INT == 32
-             && (- INTVAL (op)) < 0x7fff8000
-#else
-             && ((unsigned HOST_WIDE_INT) ((- INTVAL (op)) + 0x80008000)
-                 < 0x100000000ll)
-#endif
-             ));
-}
-
-/* Return 1 is the operand is either a non-special register or ANY
-   32-bit unsigned constant integer.  */
-
-int
-reg_or_logical_cint_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT)
-    {
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT)
-       {
-         if (GET_MODE_BITSIZE (mode) <= 32)
-           abort ();
-
-         if (INTVAL (op) < 0)
-           return 0;
-       }
-
-      return ((INTVAL (op) & GET_MODE_MASK (mode)
-              & (~ (unsigned HOST_WIDE_INT) 0xffffffff)) == 0);
-    }
-  else if (GET_CODE (op) == CONST_DOUBLE)
-    {
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
-         || mode != DImode)
-       abort ();
-
-      return CONST_DOUBLE_HIGH (op) == 0;
-    }
-  else
-    return gpc_reg_operand (op, mode);
-}
-
-/* Return 1 if the operand is an operand that can be loaded via the GOT.  */
-
-int
-got_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == SYMBOL_REF
-         || GET_CODE (op) == CONST
-         || GET_CODE (op) == LABEL_REF);
-}
-
-/* Return 1 if the operand is a simple references that can be loaded via
-   the GOT (labels involving addition aren't allowed).  */
-
-int
-got_no_const_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF);
-}
-
 /* Return the number of instructions it takes to form a constant in an
    integer register.  */
 
-static int
+int
 num_insns_constant_wide (HOST_WIDE_INT value)
 {
   /* signed constant loadable with {cal|addi} */
@@ -2030,7 +1853,7 @@ num_insns_constant (rtx op, enum machine_mode mode)
 #if HOST_BITS_PER_WIDE_INT == 64
       if ((INTVAL (op) >> 31) != 0 && (INTVAL (op) >> 31) != -1
          && mask64_operand (op, mode))
-           return 2;
+       return 2;
       else
 #endif
        return num_insns_constant_wide (INTVAL (op));
@@ -2095,117 +1918,44 @@ num_insns_constant (rtx op, enum machine_mode mode)
     abort ();
 }
 
-/* Return 1 if the operand is a CONST_DOUBLE and it can be put into a
-   register with one instruction per word.  We only do this if we can
-   safely read CONST_DOUBLE_{LOW,HIGH}.  */
+/* Returns the constant for the splat instruction, if exists.  */
 
 int
-easy_fp_constant (rtx op, enum machine_mode mode)
+easy_vector_splat_const (int cst, enum machine_mode mode)
 {
-  if (GET_CODE (op) != CONST_DOUBLE
-      || GET_MODE (op) != mode
-      || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
-    return 0;
-
-  /* Consider all constants with -msoft-float to be easy.  */
-  if ((TARGET_SOFT_FLOAT || !TARGET_FPRS)
-      && mode != DImode)
-    return 1;
-
-  /* If we are using V.4 style PIC, consider all constants to be hard.  */
-  if (flag_pic && DEFAULT_ABI == ABI_V4)
-    return 0;
-
-#ifdef TARGET_RELOCATABLE
-  /* Similarly if we are using -mrelocatable, consider all constants
-     to be hard.  */
-  if (TARGET_RELOCATABLE)
-    return 0;
-#endif
-
-  if (mode == TFmode)
+  switch (mode)
     {
-      long k[4];
-      REAL_VALUE_TYPE rv;
+    case V4SImode:
+      if (EASY_VECTOR_15 (cst)
+         || EASY_VECTOR_15_ADD_SELF (cst))
+       return cst;
+      if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
+       break;
+      cst = cst >> 16;
+      /* Fall thru */
 
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+    case V8HImode:
+      if (EASY_VECTOR_15 (cst)
+         || EASY_VECTOR_15_ADD_SELF (cst))
+       return cst;
+      if ((cst & 0xff) != ((cst >> 8) & 0xff))
+       break;
+      cst = cst >> 8;
+      /* Fall thru */
 
-      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);
+    case V16QImode:
+      if (EASY_VECTOR_15 (cst)
+         || EASY_VECTOR_15_ADD_SELF (cst))
+       return cst;
+    default:
+      break;
     }
-
-  else if (mode == DFmode)
-    {
-      long k[2];
-      REAL_VALUE_TYPE rv;
-
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
-
-      return (num_insns_constant_wide ((HOST_WIDE_INT) k[0]) == 1
-             && num_insns_constant_wide ((HOST_WIDE_INT) k[1]) == 1);
-    }
-
-  else if (mode == SFmode)
-    {
-      long l;
-      REAL_VALUE_TYPE rv;
-
-      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
-
-      return num_insns_constant_wide (l) == 1;
-    }
-
-  else if (mode == DImode)
-    return ((TARGET_POWERPC64
-            && GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_LOW (op) == 0)
-           || (num_insns_constant (op, DImode) <= 2));
-
-  else if (mode == SImode)
-    return 1;
-  else
-    abort ();
-}
-
-/* Returns the constant for the splat instruction, if exists.  */
-
-static int
-easy_vector_splat_const (int cst, enum machine_mode mode)
-{
-  switch (mode)
-    {
-    case V4SImode:
-      if (EASY_VECTOR_15 (cst)
-         || EASY_VECTOR_15_ADD_SELF (cst))
-       return cst;
-      if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
-       break;
-      cst = cst >> 16;
-    case V8HImode:
-      if (EASY_VECTOR_15 (cst)
-         || EASY_VECTOR_15_ADD_SELF (cst))
-       return cst;
-      if ((cst & 0xff) != ((cst >> 8) & 0xff))
-       break;
-      cst = cst >> 8;
-    case V16QImode:
-         if (EASY_VECTOR_15 (cst)
-             || EASY_VECTOR_15_ADD_SELF (cst))
-           return cst;
-    default:
-      break;
-    }
-  return 0;
-}
-
+  return 0;
+}
 
 /* Return nonzero if all elements of a vector have the same value.  */
 
-static int
+int
 easy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   int units, i, cst;
@@ -2221,75 +1971,6 @@ easy_vector_same (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   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 (rtx op, enum machine_mode mode)
-{
-  int cst, cst2;
-
-  if (GET_CODE (op) != CONST_VECTOR
-      || (!TARGET_ALTIVEC
-         && !TARGET_SPE))
-    return 0;
-
-  if (zero_constant (op, mode)
-      && ((TARGET_ALTIVEC && ALTIVEC_VECTOR_MODE (mode))
-         || (TARGET_SPE && SPE_VECTOR_MODE (mode))))
-    return 1;
-
-  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_same (op, mode))
-    {
-      cst = easy_vector_splat_const (cst, mode);
-      if (EASY_VECTOR_15_ADD_SELF (cst)
-         || EASY_VECTOR_15 (cst))
-       return 1;
-    }
-  return 0;
-}
-
-/* Same as easy_vector_constant but only for EASY_VECTOR_15_ADD_SELF.  */
-
-int
-easy_vector_constant_add_self (rtx op, enum machine_mode mode)
-{
-  int cst;
-  if (TARGET_ALTIVEC
-      && GET_CODE (op) == CONST_VECTOR
-      && easy_vector_same (op, mode))
-    {
-      cst = easy_vector_splat_const (INTVAL (CONST_VECTOR_ELT (op, 0)), mode);
-      if (EASY_VECTOR_15_ADD_SELF (cst))
-       return 1;
-    }
-  return 0;
-}
-
 /* Generate easy_vector_constant out of a easy_vector_constant_add_self.  */
 
 rtx
@@ -2338,6 +2019,8 @@ output_vec_const_move (rtx *operands)
              else if (EASY_VECTOR_15_ADD_SELF (cst))
                return "#";
              cst = cst >> 16;
+             /* Fall thru */
+
            case V8HImode:
              if (EASY_VECTOR_15 (cst))
                {
@@ -2347,6 +2030,8 @@ output_vec_const_move (rtx *operands)
              else if (EASY_VECTOR_15_ADD_SELF (cst))
                return "#";
              cst = cst >> 8;
+             /* Fall thru */
+
            case V16QImode:
              if (EASY_VECTOR_15 (cst))
                {
@@ -2355,6 +2040,7 @@ output_vec_const_move (rtx *operands)
                }
              else if (EASY_VECTOR_15_ADD_SELF (cst))
                return "#";
+
            default:
              abort ();
            }
@@ -2369,8 +2055,7 @@ output_vec_const_move (rtx *operands)
         pattern of V1DI, V4HI, and V2SF.
 
         FIXME: We should probably return # and add post reload
-        splitters for these, but this way is so easy ;-).
-      */
+        splitters for these, but this way is so easy ;-).  */
       operands[1] = GEN_INT (cst);
       operands[2] = GEN_INT (cst2);
       if (cst == cst2)
@@ -2382,257 +2067,26 @@ output_vec_const_move (rtx *operands)
   abort ();
 }
 
-/* Return 1 if the operand is the constant 0.  This works for scalars
-   as well as vectors.  */
-int
-zero_constant (rtx op, enum machine_mode mode)
-{
-  return op == CONST0_RTX (mode);
-}
-
-/* Return 1 if the operand is 0.0.  */
-int
-zero_fp_constant (rtx op, enum machine_mode mode)
-{
-  return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
-}
-
-/* Return 1 if the operand is in volatile memory.  Note that during
-   the RTL generation phase, memory_operand does not return TRUE for
-   volatile memory references.  So this function allows us to
-   recognize volatile references where its safe.  */
-
-int
-volatile_mem_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-
-  if (!MEM_VOLATILE_P (op))
-    return 0;
-
-  if (mode != GET_MODE (op))
-    return 0;
-
-  if (reload_completed)
-    return memory_operand (op, mode);
-
-  if (reload_in_progress)
-    return strict_memory_address_p (mode, XEXP (op, 0));
-
-  return memory_address_p (mode, XEXP (op, 0));
-}
-
-/* Return 1 if the operand is an offsettable memory operand.  */
-
-int
-offsettable_mem_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == MEM)
-         && offsettable_address_p (reload_completed || reload_in_progress,
-                                   mode, XEXP (op, 0)));
-}
-
-/* Return 1 if the operand is either an easy FP constant (see above) or
-   memory.  */
-
-int
-mem_or_easy_const_operand (rtx op, enum machine_mode mode)
-{
-  return memory_operand (op, mode) || easy_fp_constant (op, mode);
-}
-
-/* Return 1 if the operand is either a non-special register or an item
-   that can be used as the operand of a `mode' add insn.  */
-
-int
-add_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == CONST_INT)
-    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
-           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
-
-  return gpc_reg_operand (op, mode);
-}
-
-/* Return 1 if OP is a constant but not a valid add_operand.  */
-
-int
-non_add_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
-         && !CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
-}
-
-/* Return 1 if the operand is a non-special register or a constant that
-   can be used as the operand of an OR or XOR insn on the RS/6000.  */
-
-int
-logical_operand (rtx op, enum machine_mode mode)
-{
-  HOST_WIDE_INT opl, oph;
-
-  if (gpc_reg_operand (op, mode))
-    return 1;
-
-  if (GET_CODE (op) == CONST_INT)
-    {
-      opl = INTVAL (op) & GET_MODE_MASK (mode);
-
-#if HOST_BITS_PER_WIDE_INT <= 32
-      if (GET_MODE_BITSIZE (mode) > HOST_BITS_PER_WIDE_INT && opl < 0)
-       return 0;
-#endif
-    }
-  else if (GET_CODE (op) == CONST_DOUBLE)
-    {
-      if (GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT)
-       abort ();
-
-      opl = CONST_DOUBLE_LOW (op);
-      oph = CONST_DOUBLE_HIGH (op);
-      if (oph != 0)
-       return 0;
-    }
-  else
-    return 0;
-
-  return ((opl & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0
-         || (opl & ~ (unsigned HOST_WIDE_INT) 0xffff0000) == 0);
-}
-
-/* Return 1 if C is a constant that is not a logical operand (as
-   above), but could be split into one.  */
-
-int
-non_logical_cint_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE)
-         && ! logical_operand (op, mode)
-         && reg_or_logical_cint_operand (op, mode));
-}
-
-/* Return 1 if C is a constant that can be encoded in a 32-bit mask on the
-   RS/6000.  It is if there are no more than two 1->0 or 0->1 transitions.
-   Reject all ones and all zeros, since these should have been optimized
-   away and confuse the making of MB and ME.  */
-
-int
-mask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  HOST_WIDE_INT c, lsb;
-
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-
-  c = INTVAL (op);
-
-  /* Fail in 64-bit mode if the mask wraps around because the upper
-     32-bits of the mask will all be 1s, contrary to GCC's internal view.  */
-  if (TARGET_POWERPC64 && (c & 0x80000001) == 0x80000001)
-    return 0;
-
-  /* We don't change the number of transitions by inverting,
-     so make sure we start with the LS bit zero.  */
-  if (c & 1)
-    c = ~c;
-
-  /* Reject all zeros or all ones.  */
-  if (c == 0)
-    return 0;
-
-  /* Find the first transition.  */
-  lsb = c & -c;
-
-  /* Invert to look for a second transition.  */
-  c = ~c;
-
-  /* Erase first transition.  */
-  c &= -lsb;
-
-  /* Find the second transition (if any).  */
-  lsb = c & -c;
-
-  /* Match if all the bits above are 1's (or c is zero).  */
-  return c == -lsb;
-}
-
-/* Return 1 for the PowerPC64 rlwinm corner case.  */
-
-int
-mask_operand_wrap (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  HOST_WIDE_INT c, lsb;
-
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-
-  c = INTVAL (op);
-
-  if ((c & 0x80000001) != 0x80000001)
-    return 0;
-
-  c = ~c;
-  if (c == 0)
-    return 0;
-
-  lsb = c & -c;
-  c = ~c;
-  c &= -lsb;
-  lsb = c & -c;
-  return c == -lsb;
-}
-
-/* Return 1 if the operand is a constant that is a PowerPC64 mask.
-   It is if there are no more than one 1->0 or 0->1 transitions.
-   Reject all zeros, since zero should have been optimized away and
-   confuses the making of MB and ME.  */
-
-int
-mask64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == CONST_INT)
-    {
-      HOST_WIDE_INT c, lsb;
-
-      c = INTVAL (op);
-
-      /* Reject all zeros.  */
-      if (c == 0)
-       return 0;
-
-      /* We don't change the number of transitions by inverting,
-        so make sure we start with the LS bit zero.  */
-      if (c & 1)
-       c = ~c;
-
-      /* 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;
-}
-
-/* Like mask64_operand, but allow up to three transitions.  This
-   predicate is used by insn patterns that generate two rldicl or
-   rldicr machine insns.  */
-
 int
-mask64_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+mask64_1or2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED,
+                      bool allow_one)
 {
   if (GET_CODE (op) == CONST_INT)
     {
       HOST_WIDE_INT c, lsb;
-
+      bool one_ok;
+      
       c = INTVAL (op);
 
       /* Disallow all zeros.  */
       if (c == 0)
        return 0;
 
+      /* We can use a single rlwinm insn if no upper bits of C are set
+         AND there are zero, one or two transitions in the _whole_ of
+         C.  */
+      one_ok = !(c & ~(HOST_WIDE_INT)0xffffffff);
+      
       /* We don't change the number of transitions by inverting,
         so make sure we start with the LS bit zero.  */
       if (c & 1)
@@ -2656,6 +2110,9 @@ mask64_2_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
       /* Erase second transition.  */
       c &= -lsb;
 
+      if (one_ok && !(allow_one || c))
+       return 0;
+
       /* Find the third transition (if any).  */
       lsb = c & -c;
 
@@ -2735,205 +2192,60 @@ build_mask64_2_operands (rtx in, rtx *out)
 #endif
 }
 
-/* Return 1 if the operand is either a non-special register or a constant
-   that can be used as the operand of a PowerPC64 logical AND insn.  */
+/* Return TRUE if OP is an invalid SUBREG operation on the e500.  */
 
-int
-and64_operand (rtx op, enum machine_mode mode)
+bool
+invalid_e500_subreg (rtx op, enum machine_mode mode)
 {
-  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis.  */
-    return (gpc_reg_operand (op, mode) || mask64_operand (op, mode));
-
-  return (logical_operand (op, mode) || mask64_operand (op, mode));
-}
-
-/* Like the above, but also match constants that can be implemented
-   with two rldicl or rldicr insns.  */
+  /* Reject (subreg:SI (reg:DF)).  */
+  if (GET_CODE (op) == SUBREG
+      && mode == SImode
+      && REG_P (SUBREG_REG (op))
+      && GET_MODE (SUBREG_REG (op)) == DFmode)
+    return true;
 
-int
-and64_2_operand (rtx op, enum machine_mode mode)
-{
-  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis.  */
-    return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
+  /* Reject (subreg:DF (reg:DI)).  */
+  if (GET_CODE (op) == SUBREG
+      && mode == DFmode
+      && REG_P (SUBREG_REG (op))
+      && GET_MODE (SUBREG_REG (op)) == DImode)
+    return true;
 
-  return logical_operand (op, mode) || mask64_2_operand (op, mode);
+  return false;
 }
 
-/* Return 1 if the operand is either a non-special register or a
-   constant that can be used as the operand of an RS/6000 logical AND insn.  */
+/* Darwin, AIX increases natural record alignment to doubleword if the first
+   field is an FP double while the FP fields remain word aligned.  */
 
-int
-and_operand (rtx op, enum machine_mode mode)
+unsigned int
+rs6000_special_round_type_align (tree type, int computed, int specified)
 {
-  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis.  */
-    return (gpc_reg_operand (op, mode) || mask_operand (op, mode));
+  tree field = TYPE_FIELDS (type);
 
-  return (logical_operand (op, mode) || mask_operand (op, mode));
-}
+  /* Skip all non field decls */ 
+  while (field != NULL && TREE_CODE (field) != FIELD_DECL)
+    field = TREE_CHAIN (field);
 
-/* Return 1 if the operand is a general register or memory operand.  */
+  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
+    return MAX (computed, specified);
 
-int
-reg_or_mem_operand (rtx op, enum machine_mode mode)
-{
-  return (gpc_reg_operand (op, mode)
-         || memory_operand (op, mode)
-         || macho_lo_sum_memory_operand (op, mode)
-         || volatile_mem_operand (op, mode));
+  return MAX (MAX (computed, specified), 64);
 }
 
-/* Return 1 if the operand is a general register or memory operand without
-   pre_inc or pre_dec which produces invalid form of PowerPC lwa
-   instruction.  */
+/* Return 1 for an operand in small memory on V.4/eabi.  */
 
 int
-lwa_operand (rtx op, enum machine_mode mode)
+small_data_operand (rtx op ATTRIBUTE_UNUSED,
+                   enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  rtx inner = op;
-
-  if (reload_completed && GET_CODE (inner) == SUBREG)
-    inner = SUBREG_REG (inner);
+#if TARGET_ELF
+  rtx sym_ref;
 
-  return gpc_reg_operand (inner, mode)
-    || (memory_operand (inner, mode)
-       && GET_CODE (XEXP (inner, 0)) != PRE_INC
-       && GET_CODE (XEXP (inner, 0)) != PRE_DEC
-       && (GET_CODE (XEXP (inner, 0)) != PLUS
-           || GET_CODE (XEXP (XEXP (inner, 0), 1)) != CONST_INT
-           || INTVAL (XEXP (XEXP (inner, 0), 1)) % 4 == 0));
-}
+  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
+    return 0;
 
-/* Return 1 if the operand, used inside a MEM, is a SYMBOL_REF.  */
-
-int
-symbol_ref_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-
-  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
-   to CALL.  This is a SYMBOL_REF, a pseudo-register, LR or CTR.  */
-
-int
-call_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != mode)
-    return 0;
-
-  return (GET_CODE (op) == SYMBOL_REF
-         || (GET_CODE (op) == REG
-             && (REGNO (op) == LINK_REGISTER_REGNUM
-                 || REGNO (op) == COUNT_REGISTER_REGNUM
-                 || REGNO (op) >= FIRST_PSEUDO_REGISTER)));
-}
-
-/* Return 1 if the operand is a SYMBOL_REF for a function known to be in
-   this file.  */
-
-int
-current_file_function_operand (rtx op,
-                              enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == SYMBOL_REF
-         && (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.  */
-
-int
-input_operand (rtx op, enum machine_mode mode)
-{
-  /* Memory is always valid.  */
-  if (memory_operand (op, mode))
-    return 1;
-
-  /* For floating-point, easy constants are valid.  */
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && CONSTANT_P (op)
-      && easy_fp_constant (op, mode))
-    return 1;
-
-  /* Allow any integer constant.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
-      && (GET_CODE (op) == CONST_INT
-         || 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
-      || GET_MODE_SIZE (mode) > UNITS_PER_WORD)
-    return register_operand (op, mode);
-
-  /* The only cases left are integral modes one word or smaller (we
-     do not get called for MODE_CC values).  These can be in any
-     register.  */
-  if (register_operand (op, mode))
-    return 1;
-
-  /* A SYMBOL_REF referring to the TOC is valid.  */
-  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))
-    return 1;
-
-  /* V.4 allows SYMBOL_REFs and CONSTs that are in the small data region
-     to be valid.  */
-  if (DEFAULT_ABI == ABI_V4
-      && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST)
-      && small_data_operand (op, Pmode))
-    return 1;
-
-  return 0;
-}
-
-
-/* Darwin, AIX increases natural record alignment to doubleword if the first
-   field is an FP double while the FP fields remain word aligned.  */
-
-unsigned int
-rs6000_special_round_type_align (tree type, int computed, int specified)
-{
-  tree field = TYPE_FIELDS (type);
-
-  /* Skip all the static variables only if ABI is greater than
-     1 or equal to 0.  */
-  while (field != NULL && TREE_CODE (field) == VAR_DECL)
-    field = TREE_CHAIN (field);
-
-  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
-    return MAX (computed, specified);
-
-  return MAX (MAX (computed, specified), 64);
-}
-
-/* Return 1 for an operand in small memory on V.4/eabi.  */
-
-int
-small_data_operand (rtx op ATTRIBUTE_UNUSED,
-                   enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-#if TARGET_ELF
-  rtx sym_ref;
-
-  if (rs6000_sdata == SDATA_NONE || rs6000_sdata == SDATA_DATA)
-    return 0;
-
-  if (DEFAULT_ABI != ABI_V4)
-    return 0;
+  if (DEFAULT_ABI != ABI_V4)
+    return 0;
 
   if (GET_CODE (op) == SYMBOL_REF)
     sym_ref = op;
@@ -2950,10 +2262,10 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
       HOST_WIDE_INT summand;
 
       /* We have to be careful here, because it is the referenced address
-        that must be 32k from _SDA_BASE_, not just the symbol.  */
+        that must be 32k from _SDA_BASE_, not just the symbol.  */
       summand = INTVAL (XEXP (sum, 1));
       if (summand < 0 || (unsigned HOST_WIDE_INT) summand > g_switch_value)
-       return 0;
+       return 0;
 
       sym_ref = XEXP (sum, 0);
     }
@@ -2985,6 +2297,25 @@ word_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return (off % 4) == 0;
 }
 
+/* Return true if the operand is an indirect or indexed memory operand.  */
+
+int
+indexed_or_indirect_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  rtx addr;
+  if (!memory_operand (op, mode))
+    return 0;
+
+  addr = XEXP (op, 0);
+  if (GET_CODE (addr) == REG)
+    return 1;
+  if (GET_CODE (addr) == PLUS
+      && GET_CODE (XEXP (addr, 0)) == REG
+      && GET_CODE (XEXP (addr, 1)) == REG)
+    return 1;
+  return 0;
+}
+
 /* Return true if either operand is a general purpose register.  */
 
 bool
@@ -3000,7 +2331,7 @@ gpr_or_gpr_p (rtx op0, rtx op1)
 static int
 constant_pool_expr_1 (rtx op, int *have_sym, int *have_toc)
 {
-  switch (GET_CODE(op))
+  switch (GET_CODE (op))
     {
     case SYMBOL_REF:
       if (RS6000_SYMBOL_REF_TLS_P (op))
@@ -3043,7 +2374,7 @@ constant_pool_expr_p (rtx op)
   return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_sym;
 }
 
-static bool
+bool
 toc_relative_expr_p (rtx op)
 {
   int have_sym = 0;
@@ -3110,7 +2441,18 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       return SPE_CONST_OFFSET_OK (offset);
 
     case DFmode:
+      if (TARGET_E500_DOUBLE)
+       return SPE_CONST_OFFSET_OK (offset);
+
     case DImode:
+      /* On e500v2, we may have:
+
+          (subreg:DF (mem:DI (plus (reg) (const_int))) 0).
+
+         Which gets addressed with evldd instructions.  */
+      if (TARGET_E500_DOUBLE)
+       return SPE_CONST_OFFSET_OK (offset);
+
       if (mode == DFmode || !TARGET_POWERPC64)
        extra = 4;
       else if (offset & 3)
@@ -3142,6 +2484,7 @@ legitimate_indexed_address_p (rtx x, int strict)
 
   if (GET_CODE (x) != PLUS)
     return false;
+
   op0 = XEXP (x, 0);
   op1 = XEXP (x, 1);
 
@@ -3154,19 +2497,19 @@ legitimate_indexed_address_p (rtx x, int strict)
              && INT_REG_OK_FOR_INDEX_P (op0, strict)));
 }
 
-static inline bool
+inline bool
 legitimate_indirect_address_p (rtx x, int strict)
 {
   return GET_CODE (x) == REG && INT_REG_OK_FOR_BASE_P (x, strict);
 }
 
-static bool
+bool
 macho_lo_sum_memory_operand (rtx x, enum machine_mode mode)
 {
-    if (!TARGET_MACHO || !flag_pic
-        || mode != SImode || GET_CODE(x) != MEM)
-      return false;
-    x = XEXP (x, 0);
+  if (!TARGET_MACHO || !flag_pic
+      || mode != SImode || GET_CODE (x) != MEM)
+    return false;
+  x = XEXP (x, 0);
 
   if (GET_CODE (x) != LO_SUM)
     return false;
@@ -3188,6 +2531,9 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
+  /* Restrict addressing for DI because of our SUBREG hackery.  */
+  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
+    return false;
   x = XEXP (x, 1);
 
   if (TARGET_ELF || TARGET_MACHO)
@@ -3198,7 +2544,9 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_NUNITS (mode) != 1)
        return false;
-      if (GET_MODE_BITSIZE (mode) > 64)
+      if (GET_MODE_BITSIZE (mode) > 64
+         || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
+             && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode)))
        return false;
 
       return CONSTANT_P (x);
@@ -3261,7 +2609,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_MODE_NUNITS (mode) == 1
           && ((TARGET_HARD_FLOAT && TARGET_FPRS)
               || TARGET_POWERPC64
-              || (mode != DFmode && mode != TFmode))
+              || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
+                  && mode != TFmode))
           && (TARGET_POWERPC64 || mode != DImode)
           && mode != TImode)
     {
@@ -3280,24 +2629,28 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       reg = force_reg (Pmode, x);
       return reg;
     }
-  else if (SPE_VECTOR_MODE (mode))
+  else if (SPE_VECTOR_MODE (mode)
+          || (TARGET_E500_DOUBLE && (mode == DFmode
+                                     || mode == DImode)))
     {
+      if (mode == DImode)
+       return NULL_RTX;
       /* We accept [reg + reg] and [reg + OFFSET].  */
 
       if (GET_CODE (x) == PLUS)
-      {
-        rtx op1 = XEXP (x, 0);
-        rtx op2 = XEXP (x, 1);
+       {
+         rtx op1 = XEXP (x, 0);
+         rtx op2 = XEXP (x, 1);
 
-        op1 = force_reg (Pmode, op1);
+         op1 = force_reg (Pmode, op1);
 
-        if (GET_CODE (op2) != REG
-            && (GET_CODE (op2) != CONST_INT
-                || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
-          op2 = force_reg (Pmode, op2);
+         if (GET_CODE (op2) != REG
+             && (GET_CODE (op2) != CONST_INT
+                 || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
+           op2 = force_reg (Pmode, op2);
 
-        return gen_rtx_PLUS (Pmode, op1, op2);
-      }
+         return gen_rtx_PLUS (Pmode, op1, op2);
+       }
 
       return force_reg (Pmode, x);
     }
@@ -3576,15 +2929,6 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
   return dest;
 }
 
-/* Return 1 if X is a SYMBOL_REF for a TLS symbol.  This is used in
-   instruction definitions.  */
-
-int
-rs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return RS6000_SYMBOL_REF_TLS_P (x);
-}
-
 /* Return 1 if X contains a thread-local symbol.  */
 
 bool
@@ -3599,7 +2943,7 @@ rs6000_tls_referenced_p (rtx x)
 /* Return 1 if *X is a thread-local symbol.  This is the same as
    rs6000_tls_symbol_ref except for the type of the unused argument.  */
 
-static inline int
+static int
 rs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
 {
   return RS6000_SYMBOL_REF_TLS_P (*x);
@@ -3627,7 +2971,8 @@ rs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
    machopic_function_base_name() defined.  */
 rtx
 rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
-       int opnum, int type, int ind_levels ATTRIBUTE_UNUSED, int *win)
+                                 int opnum, int type,
+                                 int ind_levels ATTRIBUTE_UNUSED, int *win)
 {
   /* We must recognize output that we have already generated ourselves.  */
   if (GET_CODE (x) == PLUS
@@ -3637,8 +2982,8 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     {
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                   opnum, (enum reload_type)type);
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
       *win = 1;
       return x;
     }
@@ -3658,53 +3003,79 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       /* Result of previous invocation of this function on Darwin
         floating point constant.  */
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-               BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-               opnum, (enum reload_type)type);
+                  BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
       *win = 1;
       return x;
     }
 #endif
+
+  /* Force ld/std non-word aligned offset into base register by wrapping
+     in offset 0.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && REGNO (XEXP (x, 0)) < 32
+      && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && (INTVAL (XEXP (x, 1)) & 3) != 0
+      && !ALTIVEC_VECTOR_MODE (mode)
+      && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
+      && TARGET_POWERPC64)
+    {
+      x = gen_rtx_PLUS (GET_MODE (x), x, GEN_INT (0));
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, (enum reload_type) type);
+      *win = 1;
+      return x;
+    }
+
   if (GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == REG
       && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
       && REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && !SPE_VECTOR_MODE (mode)
+      && !(TARGET_E500_DOUBLE && (mode == DFmode
+                                 || mode == DImode))
       && !ALTIVEC_VECTOR_MODE (mode))
     {
       HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
       HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
       HOST_WIDE_INT high
-        = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+       = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
 
       /* Check for 32-bit overflow.  */
       if (high + low != val)
-        {
+       {
          *win = 0;
          return x;
        }
 
       /* Reload the high part into a base reg; leave the low part
-         in the mem directly.  */
+        in the mem directly.  */
 
       x = gen_rtx_PLUS (GET_MODE (x),
-                        gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
-                                      GEN_INT (high)),
-                        GEN_INT (low));
+                       gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
+                                     GEN_INT (high)),
+                       GEN_INT (low));
 
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                   BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                   opnum, (enum reload_type)type);
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
       *win = 1;
       return x;
     }
+
 #if TARGET_MACHO
   if (GET_CODE (x) == SYMBOL_REF
       && DEFAULT_ABI == ABI_DARWIN
       && !ALTIVEC_VECTOR_MODE (mode)
       && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
-      /* Don't do this for TFmode, since the result isn't offsettable.  */
-      && mode != TFmode)
+      /* Don't do this for TFmode, since the result isn't offsettable.
+        The same goes for DImode without 64-bit gprs.  */
+      && mode != TFmode
+      && (mode != DImode || TARGET_POWERPC64))
     {
       if (flag_pic)
        {
@@ -3717,7 +3088,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
        }
       else
        x = gen_rtx_LO_SUM (GET_MODE (x),
-              gen_rtx_HIGH (Pmode, x), 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,
@@ -3726,6 +3097,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       return x;
     }
 #endif
+
   if (TARGET_TOC
       && constant_pool_expr_p (x)
       && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
@@ -3758,6 +3130,14 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 int
 rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
 {
+  /* If this is an unaligned stvx/ldvx type address, discard the outer AND.  */
+  if (TARGET_ALTIVEC
+      && ALTIVEC_VECTOR_MODE (mode)
+      && GET_CODE (x) == AND
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && INTVAL (XEXP (x, 1)) == -16)
+    x = XEXP (x, 0);
+
   if (RS6000_SYMBOL_REF_TLS_P (x))
     return 0;
   if (legitimate_indirect_address_p (x, reg_ok_strict))
@@ -3765,6 +3145,8 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
   if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
       && !ALTIVEC_VECTOR_MODE (mode)
       && !SPE_VECTOR_MODE (mode)
+      /* Restrict addressing for DI because of our SUBREG hackery.  */
+      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
@@ -3777,7 +3159,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == REG
       && (XEXP (x, 0) == virtual_stack_vars_rtx
-         || XEXP (x, 0) == arg_pointer_rtx)
+         || XEXP (x, 0) == arg_pointer_rtx)
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     return 1;
   if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
@@ -3786,7 +3168,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && mode != TFmode
       && ((TARGET_HARD_FLOAT && TARGET_FPRS)
          || TARGET_POWERPC64
-         || (mode != DFmode && mode != TFmode))
+         || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
       && (TARGET_POWERPC64 || mode != DImode)
       && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
@@ -3851,6 +3233,9 @@ rs6000_hard_regno_nregs (int regno, enum machine_mode mode)
   if (FP_REGNO_P (regno))
     return (GET_MODE_SIZE (mode) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD;
 
+  if (TARGET_E500_DOUBLE && mode == DFmode)
+    return 1;
+
   if (SPE_SIMD_REGNO_P (regno) && TARGET_SPE && SPE_VECTOR_MODE (mode))
     return (GET_MODE_SIZE (mode) + UNITS_PER_SPE_WORD - 1) / UNITS_PER_SPE_WORD;
 
@@ -3882,7 +3267,7 @@ rs6000_conditional_register_usage (void)
   if (TARGET_SOFT_FLOAT || !TARGET_FPRS)
     for (i = 32; i < 64; i++)
       fixed_regs[i] = call_used_regs[i]
-        = call_really_used_regs[i] = 1;
+       = call_really_used_regs[i] = 1;
 
   if (DEFAULT_ABI == ABI_V4
       && PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM
@@ -3914,7 +3299,7 @@ rs6000_conditional_register_usage (void)
     {
       global_regs[SPEFSCR_REGNO] = 1;
       fixed_regs[FIXED_SCRATCH]
-        = call_used_regs[FIXED_SCRATCH]
+       = call_used_regs[FIXED_SCRATCH]
        = call_really_used_regs[FIXED_SCRATCH] = 1;
     }
 
@@ -3946,7 +3331,7 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
   if (mode == QImode || mode == HImode)
     {
       if (dest == NULL)
-        dest = gen_reg_rtx (mode);
+       dest = gen_reg_rtx (mode);
       emit_insn (gen_rtx_SET (VOIDmode, dest, source));
       return dest;
     }
@@ -4090,6 +3475,7 @@ rs6000_eliminate_indexed_memrefs (rtx operands[2])
 {
   if (GET_CODE (operands[0]) == MEM
       && GET_CODE (XEXP (operands[0], 0)) != REG
+      && ! legitimate_constant_pool_address_p (XEXP (operands[0], 0))
       && ! reload_in_progress)
     operands[0]
       = replace_equiv_address (operands[0],
@@ -4097,6 +3483,7 @@ rs6000_eliminate_indexed_memrefs (rtx operands[2])
 
   if (GET_CODE (operands[1]) == MEM
       && GET_CODE (XEXP (operands[1], 0)) != REG
+      && ! legitimate_constant_pool_address_p (XEXP (operands[1], 0))
       && ! reload_in_progress)
     operands[1]
       = replace_equiv_address (operands[1],
@@ -4151,22 +3538,9 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       return;
     }
 
-  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 (!no_new_pseudos && GET_CODE (operands[0]) == MEM
+      && !gpc_reg_operand (operands[1], mode))
+    operands[1] = force_reg (mode, operands[1]);
 
   if (mode == SFmode && ! TARGET_POWERPC
       && TARGET_HARD_FLOAT && TARGET_FPRS
@@ -4324,20 +3698,12 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                                  operands[1], mode, operands[0]);
                  if (operands[0] != operands[1])
                    emit_insn (gen_rtx_SET (VOIDmode,
-                                           operands[0], operands[1]));
+                                           operands[0], operands[1]));
                  return;
                }
 #endif
-             if (mode == DImode)
-               {
-                 emit_insn (gen_macho_high_di (target, operands[1]));
-                 emit_insn (gen_macho_low_di (operands[0], target, operands[1]));
-               }
-             else
-               {
-                 emit_insn (gen_macho_high (target, operands[1]));
-                 emit_insn (gen_macho_low (operands[0], target, operands[1]));
-               }
+             emit_insn (gen_macho_high (target, operands[1]));
+             emit_insn (gen_macho_low (operands[0], target, operands[1]));
              return;
            }
 
@@ -4425,7 +3791,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
            {
              operands[1]
                = gen_const_mem (mode,
-                                create_TOC_reference (XEXP (operands[1], 0)));
+                                create_TOC_reference (XEXP (operands[1], 0)));
              set_mem_alias_set (operands[1], get_TOC_alias_set ());
            }
        }
@@ -4497,12 +3863,54 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 static bool
 rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
 {
+  /* In the darwin64 abi, try to use registers for larger structs
+     if possible.  */
+  if (rs6000_darwin64_abi
+      && TREE_CODE (type) == RECORD_TYPE
+      && int_size_in_bytes (type) > 0)
+    {
+      CUMULATIVE_ARGS valcum;
+      rtx valret;
+
+      valcum.words = 0;
+      valcum.fregno = FP_ARG_MIN_REG;
+      valcum.vregno = ALTIVEC_ARG_MIN_REG;
+      /* Do a trial code generation as if this were going to be passed
+        as an argument; if any part goes in memory, we return NULL.  */
+      valret = rs6000_darwin64_record_arg (&valcum, type, 1, true);
+      if (valret)
+       return false;
+      /* Otherwise fall through to more conventional ABI rules.  */
+    }
+
   if (AGGREGATE_TYPE_P (type)
       && (TARGET_AIX_STRUCT_RET
          || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
     return true;
+
+  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
+     modes only exist for GCC vector types if -maltivec.  */
+  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI
+      && ALTIVEC_VECTOR_MODE (TYPE_MODE (type)))
+    return false;
+
+  /* Return synthetic vectors in memory.  */
+  if (TREE_CODE (type) == VECTOR_TYPE
+      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
+    {
+      static bool warned_for_return_big_vectors = false;
+      if (!warned_for_return_big_vectors)
+       {
+         warning ("GCC vector returned by reference: "
+                  "non-standard ABI extension with no compatibility guarantee");
+         warned_for_return_big_vectors = true;
+       }
+      return true;
+    }
+
   if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
     return true;
+
   return false;
 }
 
@@ -4538,10 +3946,11 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
     cum->nargs_prototype = n_named_args;
 
   /* Check for a longcall attribute.  */
-  if (fntype
-      && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
-      && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
-    cum->call_cookie = CALL_LONG;
+  if ((!fntype && rs6000_default_long_calls)
+      || (fntype
+         && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
+         && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))))
+    cum->call_cookie |= CALL_LONG;
 
   if (TARGET_DEBUG_ARG)
     {
@@ -4560,15 +3969,15 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
               cum->prototype, cum->nargs_prototype);
     }
 
-    if (fntype
-       && !TARGET_ALTIVEC
-       && TARGET_ALTIVEC_ABI
-        && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
-      {
-       error ("Cannot return value in vector register because"
-              " altivec instructions are disabled, use -maltivec"
-              " to enable them.");
-      }
+  if (fntype
+      && !TARGET_ALTIVEC
+      && TARGET_ALTIVEC_ABI
+      && ALTIVEC_VECTOR_MODE (TYPE_MODE (TREE_TYPE (fntype))))
+    {
+      error ("Cannot return value in vector register because"
+            " altivec instructions are disabled, use -maltivec"
+            " to enable them.");
+    }
 }
 \f
 /* Return true if TYPE must be passed on the stack and not in registers.  */
@@ -4605,7 +4014,7 @@ function_arg_padding (enum machine_mode mode, tree type)
     {
       /* GCC used to pass structures of the same size as integer types as
         if they were in fact integers, ignoring FUNCTION_ARG_PADDING.
-        ie. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
+        i.e. Structures of size 1 or 2 (or 4 when TARGET_64BIT) were
         passed padded downward, except that -mstrict-align further
         muddied the water in that multi-component structures of 2 and 4
         bytes in size were passed padded upward.
@@ -4644,21 +4053,46 @@ function_arg_padding (enum machine_mode mode, tree type)
    of an argument with the specified mode and type.  If it is not defined,
    PARM_BOUNDARY is used for all arguments.
 
-   V.4 wants long longs to be double word aligned.  */
+   V.4 wants long longs to be double word aligned.
+   Doubleword align SPE vectors.
+   Quadword align Altivec vectors.
+   Quadword align large synthetic vector types.   */
 
 int
-function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
+function_arg_boundary (enum machine_mode mode, tree type)
 {
   if (DEFAULT_ABI == ABI_V4 && GET_MODE_SIZE (mode) == 8)
     return 64;
-  else if (SPE_VECTOR_MODE (mode))
+  else if (SPE_VECTOR_MODE (mode)
+          || (type && TREE_CODE (type) == VECTOR_TYPE
+              && int_size_in_bytes (type) >= 8
+              && int_size_in_bytes (type) < 16))
     return 64;
-  else if (ALTIVEC_VECTOR_MODE (mode))
+  else if (ALTIVEC_VECTOR_MODE (mode)
+          || (type && TREE_CODE (type) == VECTOR_TYPE
+              && int_size_in_bytes (type) >= 16))
+    return 128;
+  else if (rs6000_darwin64_abi && mode == BLKmode
+          && type && TYPE_ALIGN (type) > 64)
     return 128;
   else
     return PARM_BOUNDARY;
 }
 
+/* For a function parm of MODE and TYPE, return the starting word in
+   the parameter area.  NWORDS of the parameter area are already used.  */
+
+static unsigned int
+rs6000_parm_start (enum machine_mode mode, tree type, unsigned int nwords)
+{
+  unsigned int align;
+  unsigned int parm_offset;
+
+  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+  parm_offset = DEFAULT_ABI == ABI_V4 ? 2 : 6;
+  return nwords + (-(parm_offset + nwords) & align);
+}
+
 /* Compute the size (in words) of a function argument.  */
 
 static unsigned long
@@ -4677,6 +4111,86 @@ rs6000_arg_size (enum machine_mode mode, tree type)
     return (size + 7) >> 3;
 }
 \f
+/* Use this to flush pending int fields.  */
+
+static void
+rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *cum,
+                                         HOST_WIDE_INT bitpos)
+{
+  unsigned int startbit, endbit;
+  int intregs, intoffset;
+  enum machine_mode mode;
+
+  if (cum->intoffset == -1)
+    return;
+
+  intoffset = cum->intoffset;
+  cum->intoffset = -1;
+
+  if (intoffset % BITS_PER_WORD != 0)
+    {
+      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+                           MODE_INT, 0);
+      if (mode == BLKmode)
+       {
+         /* We couldn't find an appropriate mode, which happens,
+            e.g., in packed structs when there are 3 bytes to load.
+            Back intoffset back to the beginning of the word in this
+            case.  */
+         intoffset = intoffset & -BITS_PER_WORD;
+       }
+    }
+
+  startbit = intoffset & -BITS_PER_WORD;
+  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+  intregs = (endbit - startbit) / BITS_PER_WORD;
+  cum->words += intregs;
+}
+
+/* The darwin64 ABI calls for us to recurse down through structs,
+   looking for elements passed in registers.  Unfortunately, we have
+   to track int register count here also because of misalignments
+   in powerpc alignment mode.  */
+
+static void
+rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *cum,
+                                           tree type,
+                                           HOST_WIDE_INT startbitpos)
+{
+  tree f;
+
+  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+    if (TREE_CODE (f) == FIELD_DECL)
+      {
+       HOST_WIDE_INT bitpos = startbitpos;
+       tree ftype = TREE_TYPE (f);
+       enum machine_mode mode = TYPE_MODE (ftype);
+
+       if (DECL_SIZE (f) != 0
+           && host_integerp (bit_position (f), 1))
+         bitpos += int_bit_position (f);
+
+       /* ??? FIXME: else assume zero offset.  */
+
+       if (TREE_CODE (ftype) == RECORD_TYPE)
+         rs6000_darwin64_record_arg_advance_recurse (cum, ftype, bitpos);
+       else if (USE_FP_FOR_ARG_P (cum, mode, ftype))
+         {
+           rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
+           cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+           cum->words += (GET_MODE_SIZE (mode) + 7) >> 3;
+         }
+       else if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, 1))
+         {
+           rs6000_darwin64_record_arg_advance_flush (cum, bitpos);
+           cum->vregno++;
+           cum->words += 2;
+         }
+       else if (cum->intoffset == -1)
+         cum->intoffset = bitpos;
+      }
+}
+
 /* Update the data in CUM to advance over an argument
    of mode MODE and data type TYPE.
    (TYPE is null for libcalls where that information may not be available.)
@@ -4687,16 +4201,23 @@ rs6000_arg_size (enum machine_mode mode, tree type)
 
 void
 function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                     tree type, int named)
+                     tree type, int named, int depth)
 {
-  cum->nargs_prototype--;
+  int size;
 
-  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+  /* Only tick off an argument if we're not recursing.  */
+  if (depth == 0)
+    cum->nargs_prototype--;
+
+  if (TARGET_ALTIVEC_ABI
+      && (ALTIVEC_VECTOR_MODE (mode)
+         || (type && TREE_CODE (type) == VECTOR_TYPE
+             && int_size_in_bytes (type) == 16)))
     {
       bool stack = false;
 
       if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
-        {
+       {
          cum->vregno++;
          if (!TARGET_ALTIVEC)
            error ("Cannot pass argument in vector register because"
@@ -4714,7 +4235,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        stack = true;
 
       if (stack)
-        {
+       {
          int align;
 
          /* Vector parameters must be 16-byte aligned.  This places
@@ -4744,6 +4265,33 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
           && !cum->stdarg
           && cum->sysv_gregno <= GP_ARG_MAX_REG)
     cum->sysv_gregno++;
+
+  else if (rs6000_darwin64_abi
+          && mode == BLKmode
+          && TREE_CODE (type) == RECORD_TYPE
+          && (size = int_size_in_bytes (type)) > 0)
+    {
+      /* Variable sized types have size == -1 and are
+        treated as if consisting entirely of ints.
+        Pad to 16 byte boundary if needed.  */
+      if (TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
+         && (cum->words % 2) != 0)
+       cum->words++;
+      /* For varargs, we can just go up by the size of the struct. */
+      if (!named)
+       cum->words += (size + 7) / 8;
+      else
+       {
+         /* It is tempting to say int register count just goes up by
+            sizeof(type)/8, but this is wrong in a case such as
+            { int; double; int; } [powerpc alignment].  We have to
+            grovel through the fields for these too.  */
+         cum->intoffset = 0;
+         rs6000_darwin64_record_arg_advance_recurse (cum, type, 0);
+         rs6000_darwin64_record_arg_advance_flush (cum, 
+                                                   size * BITS_PER_UNIT);
+       }
+    }
   else if (DEFAULT_ABI == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
@@ -4754,7 +4302,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          else
            {
              if (mode == DFmode)
-               cum->words += cum->words & 1;
+               cum->words += cum->words & 1;
              cum->words += rs6000_arg_size (mode, type);
            }
        }
@@ -4799,15 +4347,10 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else
     {
       int n_words = rs6000_arg_size (mode, type);
-      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+      int start_words = cum->words;
+      int align_words = rs6000_parm_start (mode, type, start_words);
 
-      /* The simple alignment calculation here works because
-        function_arg_boundary / PARM_BOUNDARY will only be 1 or 2.
-        If we ever want to handle alignments larger than 8 bytes for
-        32-bit or 16 bytes for 64-bit, then we'll need to take into
-        account the offset to the start of the parm save area.  */
-      align &= cum->words;
-      cum->words += align + n_words;
+      cum->words = align_words + n_words;
 
       if (GET_MODE_CLASS (mode) == MODE_FLOAT
          && TARGET_HARD_FLOAT && TARGET_FPRS)
@@ -4819,20 +4362,60 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                   cum->words, cum->fregno);
          fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s, ",
                   cum->nargs_prototype, cum->prototype, GET_MODE_NAME (mode));
-         fprintf (stderr, "named = %d, align = %d\n", named, align);
+         fprintf (stderr, "named = %d, align = %d, depth = %d\n",
+                  named, align_words - start_words, depth);
        }
     }
 }
 
-/* Determine where to put a SIMD argument on the SPE.  */
+static rtx
+spe_build_register_parallel (enum machine_mode mode, int gregno)
+{
+  rtx r1, r3;
+
+  if (mode == DFmode)
+    {
+      r1 = gen_rtx_REG (DImode, gregno);
+      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
+      return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
+    }
+  else if (mode == DCmode)
+    {
+      r1 = gen_rtx_REG (DImode, gregno);
+      r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
+      r3 = gen_rtx_REG (DImode, gregno + 2);
+      r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
+      return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
+    }
+  abort ();
+  return NULL_RTX;
+}
 
+/* Determine where to put a SIMD argument on the SPE.  */
 static rtx
 rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                         tree type)
 {
+  int gregno = cum->sysv_gregno;
+
+  /* On E500 v2, double arithmetic is done on the full 64-bit GPR, but
+     are passed and returned in a pair of GPRs for ABI compatibility.  */
+  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DCmode))
+    {
+      int n_words = rs6000_arg_size (mode, type);
+
+      /* Doubles go in an odd/even register pair (r5/r6, etc).  */
+      if (mode == DFmode)
+       gregno += (1 - gregno) & 1;
+
+      /* Multi-reg args are not split between registers and stack.  */
+      if (gregno + n_words - 1 > GP_ARG_MAX_REG)
+       return NULL_RTX;
+
+      return spe_build_register_parallel (mode, gregno);
+    }
   if (cum->stdarg)
     {
-      int gregno = cum->sysv_gregno;
       int n_words = rs6000_arg_size (mode, type);
 
       /* SPE vectors are put in odd registers.  */
@@ -4855,24 +4438,206 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
   else
     {
-      if (cum->sysv_gregno <= GP_ARG_MAX_REG)
-       return gen_rtx_REG (mode, cum->sysv_gregno);
+      if (gregno <= GP_ARG_MAX_REG)
+       return gen_rtx_REG (mode, gregno);
       else
        return NULL_RTX;
     }
 }
 
-/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
+/* A subroutine of rs6000_darwin64_record_arg.  Assign the bits of the
+   structure between cum->intoffset and bitpos to integer registers.  */
 
-static rtx
-rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
+static void
+rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *cum, 
+                                 HOST_WIDE_INT bitpos, rtx rvec[], int *k)
 {
-  int n_units;
-  int i, k;
-  rtx rvec[GP_ARG_NUM_REG + 1];
+  enum machine_mode mode;
+  unsigned int regno;
+  unsigned int startbit, endbit;
+  int this_regno, intregs, intoffset;
+  rtx reg;
 
-  if (align_words >= GP_ARG_NUM_REG)
-    return NULL_RTX;
+  if (cum->intoffset == -1)
+    return;
+
+  intoffset = cum->intoffset;
+  cum->intoffset = -1;
+
+  /* If this is the trailing part of a word, try to only load that
+     much into the register.  Otherwise load the whole register.  Note
+     that in the latter case we may pick up unwanted bits.  It's not a
+     problem at the moment but may wish to revisit.  */
+
+  if (intoffset % BITS_PER_WORD != 0)
+    {
+      mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+                         MODE_INT, 0);
+      if (mode == BLKmode)
+       {
+         /* We couldn't find an appropriate mode, which happens,
+            e.g., in packed structs when there are 3 bytes to load.
+            Back intoffset back to the beginning of the word in this
+            case.  */
+        intoffset = intoffset & -BITS_PER_WORD;
+        mode = word_mode;
+       }
+    }
+  else
+    mode = word_mode;
+
+  startbit = intoffset & -BITS_PER_WORD;
+  endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+  intregs = (endbit - startbit) / BITS_PER_WORD;
+  this_regno = cum->words + intoffset / BITS_PER_WORD;
+
+  if (intregs > 0 && intregs > GP_ARG_NUM_REG - this_regno)
+    cum->use_stack = 1;
+    
+  intregs = MIN (intregs, GP_ARG_NUM_REG - this_regno);
+  if (intregs <= 0)
+    return;
+
+  intoffset /= BITS_PER_UNIT;
+  do
+    {
+      regno = GP_ARG_MIN_REG + this_regno;
+      reg = gen_rtx_REG (mode, regno);
+      rvec[(*k)++] =
+       gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
+
+      this_regno += 1;
+      intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+      mode = word_mode;
+      intregs -= 1;
+    }
+  while (intregs > 0);
+}
+
+/* Recursive workhorse for the following.  */
+
+static void
+rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type, 
+                                   HOST_WIDE_INT startbitpos, rtx rvec[],
+                                   int *k)
+{
+  tree f;
+
+  for (f = TYPE_FIELDS (type); f ; f = TREE_CHAIN (f))
+    if (TREE_CODE (f) == FIELD_DECL)
+      {
+       HOST_WIDE_INT bitpos = startbitpos;
+       tree ftype = TREE_TYPE (f);
+       enum machine_mode mode = TYPE_MODE (ftype);
+
+       if (DECL_SIZE (f) != 0
+           && host_integerp (bit_position (f), 1))
+         bitpos += int_bit_position (f);
+
+       /* ??? FIXME: else assume zero offset.  */
+
+       if (TREE_CODE (ftype) == RECORD_TYPE)
+         rs6000_darwin64_record_arg_recurse (cum, ftype, bitpos, rvec, k);
+       else if (cum->named && USE_FP_FOR_ARG_P (cum, mode, ftype))
+         {
+#if 0
+           switch (mode)
+             {
+             case SCmode: mode = SFmode; break;
+             case DCmode: mode = DFmode; break;
+             case TCmode: mode = TFmode; break;
+             default: break;
+             }
+#endif
+           rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
+           rvec[(*k)++]
+             = gen_rtx_EXPR_LIST (VOIDmode, 
+                                  gen_rtx_REG (mode, cum->fregno++),
+                                  GEN_INT (bitpos / BITS_PER_UNIT));
+           if (mode == TFmode)
+             cum->fregno++;
+         }
+       else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
+         {
+           rs6000_darwin64_record_arg_flush (cum, bitpos, rvec, k);
+           rvec[(*k)++]
+             = gen_rtx_EXPR_LIST (VOIDmode, 
+                                  gen_rtx_REG (mode, cum->vregno++), 
+                                  GEN_INT (bitpos / BITS_PER_UNIT));
+         }
+       else if (cum->intoffset == -1)
+         cum->intoffset = bitpos;
+      }
+}
+
+/* For the darwin64 ABI, we want to construct a PARALLEL consisting of
+   the register(s) to be used for each field and subfield of a struct
+   being passed by value, along with the offset of where the
+   register's value may be found in the block.  FP fields go in FP
+   register, vector fields go in vector registers, and everything
+   else goes in int registers, packed as in memory.  
+
+   This code is also used for function return values.  RETVAL indicates
+   whether this is the case.
+
+   Much of this is taken from the Sparc V9 port, which has a similar
+   calling convention.  */
+
+static rtx
+rs6000_darwin64_record_arg (CUMULATIVE_ARGS *orig_cum, tree type,
+                           int named, bool retval)
+{
+  rtx rvec[FIRST_PSEUDO_REGISTER];
+  int k = 1, kbase = 1;
+  HOST_WIDE_INT typesize = int_size_in_bytes (type);
+  /* This is a copy; modifications are not visible to our caller.  */
+  CUMULATIVE_ARGS copy_cum = *orig_cum;
+  CUMULATIVE_ARGS *cum = &copy_cum;
+
+  /* Pad to 16 byte boundary if needed.  */
+  if (!retval && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
+      && (cum->words % 2) != 0)
+    cum->words++;
+
+  cum->intoffset = 0;
+  cum->use_stack = 0;
+  cum->named = named;
+
+  /* Put entries into rvec[] for individual FP and vector fields, and
+     for the chunks of memory that go in int regs.  Note we start at
+     element 1; 0 is reserved for an indication of using memory, and
+     may or may not be filled in below. */
+  rs6000_darwin64_record_arg_recurse (cum, type, 0, rvec, &k);
+  rs6000_darwin64_record_arg_flush (cum, typesize * BITS_PER_UNIT, rvec, &k);
+
+  /* If any part of the struct went on the stack put all of it there.
+     This hack is because the generic code for
+     FUNCTION_ARG_PARTIAL_NREGS cannot handle cases where the register
+     parts of the struct are not at the beginning.  */
+  if (cum->use_stack)
+    {
+      if (retval)
+       return NULL_RTX;    /* doesn't go in registers at all */
+      kbase = 0;
+      rvec[0] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+    }
+  if (k > 1 || cum->use_stack)
+    return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k - kbase, &rvec[kbase]));
+  else
+    return NULL_RTX;
+}
+
+/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
+
+static rtx
+rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
+{
+  int n_units;
+  int i, k;
+  rtx rvec[GP_ARG_NUM_REG + 1];
+
+  if (align_words >= GP_ARG_NUM_REG)
+    return NULL_RTX;
 
   n_units = rs6000_arg_size (mode, type);
 
@@ -4896,6 +4661,8 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
        In any case, the code to store the whole arg to memory is often
        more efficient than code to store pieces, and we know that space
        is available in the right place for the whole arg.  */
+    /* FIXME: This should be fixed since the conversion to
+       TARGET_ARG_PARTIAL_BYTES.  */
     rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
 
   i = 0;
@@ -4919,7 +4686,8 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
     This is null for libcalls where that information may
     not be available.
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
-    the preceding args and about the function being called.
+    the preceding args and about the function being called.  It is
+    not modified in this routine.
    NAMED is nonzero if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).
 
@@ -4937,7 +4705,7 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
    with MODE and TYPE set to that of the pointer to the arg, not the arg
    itself.  */
 
-struct rtx_def *
+rtx
 function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
              tree type, int named)
 {
@@ -4967,34 +4735,46 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       return GEN_INT (cum->call_cookie);
     }
 
+  if (rs6000_darwin64_abi && mode == BLKmode
+      && TREE_CODE (type) == RECORD_TYPE)
+    {
+      rtx rslt = rs6000_darwin64_record_arg (cum, type, named, false);
+      if (rslt != NULL_RTX)
+       return rslt;
+      /* Else fall through to usual handling.  */
+    }
+
   if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
     if (TARGET_64BIT && ! cum->prototype)
       {
-       /* Vector parameters get passed in vector register
-          and also in GPRs or memory, in absence of prototype.  */
-       int align_words;
-       rtx slot;
-       align_words = (cum->words + 1) & ~1;
-
-       if (align_words >= GP_ARG_NUM_REG)
-         {
-           slot = NULL_RTX;
-         }
-       else
-         {
-           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
-         }
-       return gen_rtx_PARALLEL (mode,
-                gen_rtvec (2,
-                           gen_rtx_EXPR_LIST (VOIDmode,
-                                              slot, const0_rtx),
-                           gen_rtx_EXPR_LIST (VOIDmode,
-                                              gen_rtx_REG (mode, cum->vregno),
-                                              const0_rtx)));
+       /* Vector parameters get passed in vector register
+          and also in GPRs or memory, in absence of prototype.  */
+       int align_words;
+       rtx slot;
+       align_words = (cum->words + 1) & ~1;
+
+       if (align_words >= GP_ARG_NUM_REG)
+         {
+           slot = NULL_RTX;
+         }
+       else
+         {
+           slot = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+         }
+       return gen_rtx_PARALLEL (mode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              slot, const0_rtx),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (mode, cum->vregno),
+                                              const0_rtx)));
       }
     else
       return gen_rtx_REG (mode, cum->vregno);
-  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+  else if (TARGET_ALTIVEC_ABI
+          && (ALTIVEC_VECTOR_MODE (mode)
+              || (type && TREE_CODE (type) == VECTOR_TYPE
+                  && int_size_in_bytes (type) == 16)))
     {
       if (named || abi == ABI_V4)
        return NULL_RTX;
@@ -5035,8 +4815,12 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
        }
     }
-  else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
+  else if (TARGET_SPE_ABI && TARGET_SPE
+          && (SPE_VECTOR_MODE (mode)
+              || (TARGET_E500_DOUBLE && (mode == DFmode
+                                         || mode == DCmode))))
     return rs6000_spe_function_arg (cum, mode, type);
+
   else if (abi == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
@@ -5070,8 +4854,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
   else
     {
-      int align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
-      int align_words = cum->words + (cum->words & align);
+      int align_words = rs6000_parm_start (mode, type, cum->words);
 
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
@@ -5098,7 +4881,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          needs_psave = (type
                         && (cum->nargs_prototype <= 0
                             || (DEFAULT_ABI == ABI_AIX
-                                && TARGET_XL_CALL
+                                && TARGET_XL_COMPAT
                                 && align_words >= GP_ARG_NUM_REG)));
 
          if (!needs_psave && mode == fmode)
@@ -5120,11 +4903,22 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                         include the portion actually in registers here.  */
                      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
                      rtx off;
+                     int i=0;
+                     if (align_words + n_words > GP_ARG_NUM_REG
+                         && (TARGET_32BIT && TARGET_POWERPC64))
+                       /* Not all of the arg fits in gprs.  Say that it
+                          goes in memory too, using a magic NULL_RTX
+                          component.  Also see comment in
+                          rs6000_mixed_function_arg for why the normal
+                          function_arg_partial_nregs scheme doesn't work
+                          in this case. */
+                       rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX,
+                                                      const0_rtx);
                      do
                        {
                          r = gen_rtx_REG (rmode,
                                           GP_ARG_MIN_REG + align_words);
-                         off = GEN_INT (k * GET_MODE_SIZE (rmode));
+                         off = GEN_INT (i++ * GET_MODE_SIZE (rmode));
                          rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
                        }
                      while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
@@ -5152,6 +4946,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          if (TARGET_32BIT && TARGET_POWERPC64)
            return rs6000_mixed_function_arg (mode, type, align_words);
 
+         if (mode == BLKmode)
+           mode = Pmode;
+
          return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
        }
       else
@@ -5163,15 +4960,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    the number of registers used.  For args passed entirely in registers
    or entirely in memory, zero.  When an arg is described by a PARALLEL,
    perhaps using more than one register type, this function returns the
-   number of registers used by the first element of the PARALLEL.  */
+   number of bytes of registers used by the PARALLEL.  */
 
-int
-function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                           tree type, int named)
+static int
+rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                         tree type, bool named)
 {
   int ret = 0;
-  int align;
-  int parm_offset;
   int align_words;
 
   if (DEFAULT_ABI == ABI_V4)
@@ -5181,9 +4976,13 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && cum->nargs_prototype >= 0)
     return 0;
 
-  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
-  parm_offset = TARGET_32BIT ? 2 : 0;
-  align_words = cum->words + ((parm_offset - cum->words) & align);
+  /* In this complicated case we just disable the partial_nregs code.  */
+  if (rs6000_darwin64_abi && mode == BLKmode
+      && TREE_CODE (type) == RECORD_TYPE
+      && int_size_in_bytes (type) > 0)
+    return 0;
+
+  align_words = rs6000_parm_start (mode, type, cum->words);
 
   if (USE_FP_FOR_ARG_P (cum, mode, type)
       /* If we are passing this arg in gprs as well, then this function
@@ -5192,7 +4991,7 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && !(type
           && (cum->nargs_prototype <= 0
               || (DEFAULT_ABI == ABI_AIX
-                  && TARGET_XL_CALL
+                  && TARGET_XL_COMPAT
                   && align_words >= GP_ARG_NUM_REG))))
     {
       if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
@@ -5205,8 +5004,10 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
     ret = GP_ARG_NUM_REG - align_words;
 
+  ret *= (TARGET_32BIT ? 4 : 8);
+
   if (ret != 0 && TARGET_DEBUG_ARG)
-    fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
+    fprintf (stderr, "rs6000_arg_partial_bytes: %d\n", ret);
 
   return ret;
 }
@@ -5227,20 +5028,58 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static bool
 rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
-                         enum machine_mode mode ATTRIBUTE_UNUSED,
-                         tree type, bool named ATTRIBUTE_UNUSED)
+                         enum machine_mode mode, tree type,
+                         bool named ATTRIBUTE_UNUSED)
 {
-  if ((DEFAULT_ABI == ABI_V4
-       && ((type && AGGREGATE_TYPE_P (type))
-          || mode == TFmode))
-      || (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
-      || (type && int_size_in_bytes (type) < 0))
+  if (DEFAULT_ABI == ABI_V4 && mode == TFmode)
     {
       if (TARGET_DEBUG_ARG)
-       fprintf (stderr, "function_arg_pass_by_reference\n");
+       fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n");
+      return 1;
+    }
 
+  if (!type)
+    return 0;
+
+  if (DEFAULT_ABI == ABI_V4 && AGGREGATE_TYPE_P (type))
+    {
+      if (TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_pass_by_reference: V4 aggregate\n");
+      return 1;
+    }
+
+  if (int_size_in_bytes (type) < 0)
+    {
+      if (TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_pass_by_reference: variable size\n");
+      return 1;
+    }
+
+  /* Allow -maltivec -mabi=no-altivec without warning.  Altivec vector
+     modes only exist for GCC vector types if -maltivec.  */
+  if (TARGET_32BIT && !TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+    {
+      if (TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_pass_by_reference: AltiVec\n");
+      return 1;
+    }
+
+  /* Pass synthetic vectors in memory.  */
+  if (TREE_CODE (type) == VECTOR_TYPE
+      && int_size_in_bytes (type) > (TARGET_ALTIVEC_ABI ? 16 : 8))
+    {
+      static bool warned_for_pass_big_vectors = false;
+      if (TARGET_DEBUG_ARG)
+       fprintf (stderr, "function_arg_pass_by_reference: synthetic vector\n");
+      if (!warned_for_pass_big_vectors)
+       {
+         warning ("GCC vector passed by reference: "
+                  "non-standard ABI extension with no compatibility guarantee");
+         warned_for_pass_big_vectors = true;
+       }
       return 1;
     }
+
   return 0;
 }
 
@@ -5253,27 +5092,26 @@ rs6000_move_block_from_reg (int regno, rtx x, int nregs)
   if (nregs == 0)
     return;
 
-    for (i = 0; i < nregs; i++)
+  for (i = 0; i < nregs; i++)
     {
-      rtx tem = adjust_address_nv (x, reg_mode, i*GET_MODE_SIZE(reg_mode));
+      rtx tem = adjust_address_nv (x, reg_mode, i * GET_MODE_SIZE (reg_mode));
       if (reload_completed)
-      {
-       if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
-         tem = NULL_RTX;
-       else
-         tem = simplify_gen_subreg (reg_mode, x, BLKmode,
-                                    i * GET_MODE_SIZE(reg_mode));
-      }
+       {
+         if (! strict_memory_address_p (reg_mode, XEXP (tem, 0)))
+           tem = NULL_RTX;
+         else
+           tem = simplify_gen_subreg (reg_mode, x, BLKmode,
+                                      i * GET_MODE_SIZE (reg_mode));
+       }
       else
        tem = replace_equiv_address (tem, XEXP (tem, 0));
 
       if (tem == NULL_RTX)
-        abort ();
+       abort ();
 
       emit_move_insn (tem, gen_rtx_REG (reg_mode, regno + i));
     }
 }
-
 \f
 /* Perform any needed actions needed for a function that is receiving a
    variable number of arguments.
@@ -5291,7 +5129,8 @@ rs6000_move_block_from_reg (int regno, rtx x, int nregs)
 
 static void
 setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-               tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl)
+                       tree type, int *pretend_size ATTRIBUTE_UNUSED,
+                       int no_rtl)
 {
   CUMULATIVE_ARGS next_cum;
   int reg_size = TARGET_32BIT ? 4 : 8;
@@ -5300,7 +5139,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   /* Skip the last named argument.  */
   next_cum = *cum;
-  function_arg_advance (&next_cum, mode, type, 1);
+  function_arg_advance (&next_cum, mode, type, 1, 0);
 
   if (DEFAULT_ABI == ABI_V4)
     {
@@ -5323,13 +5162,13 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   if (! no_rtl && first_reg_offset < GP_ARG_NUM_REG)
     {
       mem = gen_rtx_MEM (BLKmode,
-                        plus_constant (save_area,
+                        plus_constant (save_area,
                                        first_reg_offset * reg_size)),
       set_mem_alias_set (mem, set);
       set_mem_align (mem, BITS_PER_WORD);
 
       rs6000_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);
     }
 
   /* Save FP registers if needed.  */
@@ -5343,18 +5182,20 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       rtx lab = gen_label_rtx ();
       int off = (GP_ARG_NUM_REG * reg_size) + ((fregno - FP_ARG_MIN_REG) * 8);
 
-      emit_jump_insn (gen_rtx_SET (VOIDmode,
-                                  pc_rtx,
-                                  gen_rtx_IF_THEN_ELSE (VOIDmode,
+      emit_jump_insn
+       (gen_rtx_SET (VOIDmode,
+                     pc_rtx,
+                     gen_rtx_IF_THEN_ELSE (VOIDmode,
                                            gen_rtx_NE (VOIDmode, cr1,
-                                                       const0_rtx),
+                                                       const0_rtx),
                                            gen_rtx_LABEL_REF (VOIDmode, lab),
                                            pc_rtx)));
 
       while (fregno <= FP_ARG_V4_MAX_REG)
        {
          mem = gen_rtx_MEM (DFmode, plus_constant (save_area, off));
-          set_mem_alias_set (mem, set);
+         set_mem_alias_set (mem, set);
+         set_mem_align (mem, GET_MODE_ALIGNMENT (DFmode));
          emit_move_insn (mem, gen_rtx_REG (DFmode, fregno));
          fregno++;
          off += 8;
@@ -5434,7 +5275,7 @@ rs6000_va_start (tree valist, rtx nextarg)
   f_ovf = TREE_CHAIN (f_res);
   f_sav = TREE_CHAIN (f_ovf);
 
-  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  valist = build_va_arg_indirect_ref (valist);
   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
@@ -5442,8 +5283,10 @@ rs6000_va_start (tree valist, rtx nextarg)
 
   /* Count number of gp and fp argument registers used.  */
   words = current_function_args_info.words;
-  n_gpr = current_function_args_info.sysv_gregno - GP_ARG_MIN_REG;
-  n_fpr = current_function_args_info.fregno - FP_ARG_MIN_REG;
+  n_gpr = MIN (current_function_args_info.sysv_gregno - GP_ARG_MIN_REG,
+              GP_ARG_NUM_REG);
+  n_fpr = MIN (current_function_args_info.fregno - FP_ARG_MIN_REG,
+              FP_ARG_NUM_REG);
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr, "va_start: words = "HOST_WIDE_INT_PRINT_DEC", n_gpr = "
@@ -5493,7 +5336,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
     {
       t = rs6000_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
-      return build_fold_indirect_ref (t);
+      return build_va_arg_indirect_ref (t);
     }
 
   if (DEFAULT_ABI != ABI_V4)
@@ -5532,7 +5375,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   f_ovf = TREE_CHAIN (f_res);
   f_sav = TREE_CHAIN (f_ovf);
 
-  valist = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (valist)), valist);
+  valist = build_va_arg_indirect_ref (valist);
   gpr = build (COMPONENT_REF, TREE_TYPE (f_gpr), valist, f_gpr, NULL_TREE);
   fpr = build (COMPONENT_REF, TREE_TYPE (f_fpr), valist, f_fpr, NULL_TREE);
   ovf = build (COMPONENT_REF, TREE_TYPE (f_ovf), valist, f_ovf, NULL_TREE);
@@ -5648,7 +5491,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
     }
 
   addr = fold_convert (ptrtype, addr);
-  return build_fold_indirect_ref (addr);
+  return build_va_arg_indirect_ref (addr);
 }
 
 /* Builtins.  */
@@ -5675,18 +5518,18 @@ static const struct builtin_description bdesc_3arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vmsumuhs, "__builtin_altivec_vmsumuhs", ALTIVEC_BUILTIN_VMSUMUHS },
   { MASK_ALTIVEC, CODE_FOR_altivec_vmsumshs, "__builtin_altivec_vmsumshs", ALTIVEC_BUILTIN_VMSUMSHS },
   { MASK_ALTIVEC, CODE_FOR_altivec_vnmsubfp, "__builtin_altivec_vnmsubfp", ALTIVEC_BUILTIN_VNMSUBFP },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4sf, "__builtin_altivec_vperm_4sf", ALTIVEC_BUILTIN_VPERM_4SF },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v4si, "__builtin_altivec_vperm_4si", ALTIVEC_BUILTIN_VPERM_4SI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v8hi, "__builtin_altivec_vperm_8hi", ALTIVEC_BUILTIN_VPERM_8HI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vperm_v16qi, "__builtin_altivec_vperm_16qi", ALTIVEC_BUILTIN_VPERM_16QI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4sf, "__builtin_altivec_vsel_4sf", ALTIVEC_BUILTIN_VSEL_4SF },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v4si, "__builtin_altivec_vsel_4si", ALTIVEC_BUILTIN_VSEL_4SI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v8hi, "__builtin_altivec_vsel_8hi", ALTIVEC_BUILTIN_VSEL_8HI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsel_v16qi, "__builtin_altivec_vsel_16qi", ALTIVEC_BUILTIN_VSEL_16QI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v16qi, "__builtin_altivec_vsldoi_16qi", ALTIVEC_BUILTIN_VSLDOI_16QI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v8hi, "__builtin_altivec_vsldoi_8hi", ALTIVEC_BUILTIN_VSLDOI_8HI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4si, "__builtin_altivec_vsldoi_4si", ALTIVEC_BUILTIN_VSLDOI_4SI },
+  { MASK_ALTIVEC, CODE_FOR_altivec_vsldoi_v4sf, "__builtin_altivec_vsldoi_4sf", ALTIVEC_BUILTIN_VSLDOI_4SF },
 };
 
 /* DST operations: void foo (void *, const int, const char).  */
@@ -5715,7 +5558,7 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vadduws, "__builtin_altivec_vadduws", ALTIVEC_BUILTIN_VADDUWS },
   { MASK_ALTIVEC, CODE_FOR_altivec_vaddsws, "__builtin_altivec_vaddsws", ALTIVEC_BUILTIN_VADDSWS },
   { MASK_ALTIVEC, CODE_FOR_andv4si3, "__builtin_altivec_vand", ALTIVEC_BUILTIN_VAND },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vandc, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
+  { MASK_ALTIVEC, CODE_FOR_andcv4si3, "__builtin_altivec_vandc", ALTIVEC_BUILTIN_VANDC },
   { MASK_ALTIVEC, CODE_FOR_altivec_vavgub, "__builtin_altivec_vavgub", ALTIVEC_BUILTIN_VAVGUB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vavgsb, "__builtin_altivec_vavgsb", ALTIVEC_BUILTIN_VAVGSB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vavguh, "__builtin_altivec_vavguh", ALTIVEC_BUILTIN_VAVGUH },
@@ -5767,7 +5610,7 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vmulosb, "__builtin_altivec_vmulosb", ALTIVEC_BUILTIN_VMULOSB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vmulouh, "__builtin_altivec_vmulouh", ALTIVEC_BUILTIN_VMULOUH },
   { MASK_ALTIVEC, CODE_FOR_altivec_vmulosh, "__builtin_altivec_vmulosh", ALTIVEC_BUILTIN_VMULOSH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vnor, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
+  { MASK_ALTIVEC, CODE_FOR_altivec_norv4si3, "__builtin_altivec_vnor", ALTIVEC_BUILTIN_VNOR },
   { MASK_ALTIVEC, CODE_FOR_iorv4si3, "__builtin_altivec_vor", ALTIVEC_BUILTIN_VOR },
   { MASK_ALTIVEC, CODE_FOR_altivec_vpkuhum, "__builtin_altivec_vpkuhum", ALTIVEC_BUILTIN_VPKUHUM },
   { MASK_ALTIVEC, CODE_FOR_altivec_vpkuwum, "__builtin_altivec_vpkuwum", ALTIVEC_BUILTIN_VPKUWUM },
@@ -6307,24 +6150,24 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
      If you think this is disgusting, look at the specs for the
      AltiVec predicates.  */
 
-     switch (cr6_form_int)
-       {
-       case 0:
-        emit_insn (gen_cr6_test_for_zero (target));
-        break;
-       case 1:
-        emit_insn (gen_cr6_test_for_zero_reverse (target));
-        break;
-       case 2:
-        emit_insn (gen_cr6_test_for_lt (target));
-        break;
-       case 3:
-        emit_insn (gen_cr6_test_for_lt_reverse (target));
-        break;
-       default:
-        error ("argument 1 of __builtin_altivec_predicate is out of range");
-        break;
-       }
+  switch (cr6_form_int)
+    {
+    case 0:
+      emit_insn (gen_cr6_test_for_zero (target));
+      break;
+    case 1:
+      emit_insn (gen_cr6_test_for_zero_reverse (target));
+      break;
+    case 2:
+      emit_insn (gen_cr6_test_for_lt (target));
+      break;
+    case 3:
+      emit_insn (gen_cr6_test_for_lt_reverse (target));
+      break;
+    default:
+      error ("argument 1 of __builtin_altivec_predicate is out of range");
+      break;
+    }
 
   return target;
 }
@@ -6474,10 +6317,10 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
       || arg2 == error_mark_node)
     return const0_rtx;
 
-  if (icode == CODE_FOR_altivec_vsldoi_4sf
-      || icode == CODE_FOR_altivec_vsldoi_4si
-      || icode == CODE_FOR_altivec_vsldoi_8hi
-      || icode == CODE_FOR_altivec_vsldoi_16qi)
+  if (icode == CODE_FOR_altivec_vsldoi_v4sf
+      || icode == CODE_FOR_altivec_vsldoi_v4si
+      || icode == CODE_FOR_altivec_vsldoi_v8hi
+      || icode == CODE_FOR_altivec_vsldoi_v16qi)
     {
       /* Only allow 4-bit unsigned literals.  */
       STRIP_NOPS (arg2);
@@ -6524,16 +6367,16 @@ altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LD_INTERNAL_16qi:
-      icode = CODE_FOR_altivec_lvx_16qi;
+      icode = CODE_FOR_altivec_lvx_v16qi;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_8hi:
-      icode = CODE_FOR_altivec_lvx_8hi;
+      icode = CODE_FOR_altivec_lvx_v8hi;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_4si:
-      icode = CODE_FOR_altivec_lvx_4si;
+      icode = CODE_FOR_altivec_lvx_v4si;
       break;
     case ALTIVEC_BUILTIN_LD_INTERNAL_4sf:
-      icode = CODE_FOR_altivec_lvx_4sf;
+      icode = CODE_FOR_altivec_lvx_v4sf;
       break;
     default:
       *expandedp = false;
@@ -6578,16 +6421,16 @@ altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_ST_INTERNAL_16qi:
-      icode = CODE_FOR_altivec_stvx_16qi;
+      icode = CODE_FOR_altivec_stvx_v16qi;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_8hi:
-      icode = CODE_FOR_altivec_stvx_8hi;
+      icode = CODE_FOR_altivec_stvx_v8hi;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_4si:
-      icode = CODE_FOR_altivec_stvx_4si;
+      icode = CODE_FOR_altivec_stvx_v4si;
       break;
     case ALTIVEC_BUILTIN_ST_INTERNAL_4sf:
-      icode = CODE_FOR_altivec_stvx_4sf;
+      icode = CODE_FOR_altivec_stvx_v4sf;
       break;
     default:
       *expandedp = false;
@@ -6656,12 +6499,12 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
        if (TREE_CODE (arg2) != INTEGER_CST
            || TREE_INT_CST_LOW (arg2) & ~0x3)
          {
-           error ("argument to `%s' must be a 2-bit unsigned literal", d->name);
+           error ("argument to %qs must be a 2-bit unsigned literal", d->name);
            return const0_rtx;
          }
 
        if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
-         op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+         op0 = copy_to_mode_reg (Pmode, op0);
        if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
          op1 = copy_to_mode_reg (mode1, op1);
 
@@ -6782,9 +6625,9 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     case ALTIVEC_BUILTIN_COMPILETIME_ERROR:
       arg0 = TREE_VALUE (arglist);
       while (TREE_CODE (arg0) == NOP_EXPR || TREE_CODE (arg0) == ADDR_EXPR
-             || TREE_CODE (arg0) == ARRAY_REF)
+            || TREE_CODE (arg0) == ARRAY_REF)
        arg0 = TREE_OPERAND (arg0, 0);
-      error ("invalid parameter combination for `%s' AltiVec intrinsic",
+      error ("invalid parameter combination for %qs AltiVec intrinsic",
             TREE_STRING_POINTER (arg0));
 
       return const0_rtx;
@@ -6800,32 +6643,33 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
   for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
     if (dp->code == fcode)
-      return altivec_expand_predicate_builtin (dp->icode, dp->opcode, arglist, target);
+      return altivec_expand_predicate_builtin (dp->icode, dp->opcode,
+                                              arglist, target);
 
   /* LV* are funky.  We initialized them differently.  */
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LVSL:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
-                                          arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVSR:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
-                                         arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVEBX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
-                                         arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVEHX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
-                                         arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVEWX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
-                                         arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVXL:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
-                                         arglist, target);
+                                       arglist, target);
     case ALTIVEC_BUILTIN_LVX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
-                                         arglist, target);
+                                       arglist, target);
     default:
       break;
       /* Fall through.  */
@@ -7169,8 +7013,8 @@ spe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
 
 static rtx
 rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
-                     enum machine_mode mode ATTRIBUTE_UNUSED,
-                     int ignore ATTRIBUTE_UNUSED)
+                      enum machine_mode mode ATTRIBUTE_UNUSED,
+                      int ignore ATTRIBUTE_UNUSED)
 {
   tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
   tree arglist = TREE_OPERAND (exp, 1);
@@ -7180,6 +7024,48 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   rtx ret;
   bool success;
 
+  if (fcode == ALTIVEC_BUILTIN_MASK_FOR_LOAD
+      || fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
+    {
+      int icode = (int) CODE_FOR_altivec_lvsr;
+      enum machine_mode tmode = insn_data[icode].operand[0].mode;
+      enum machine_mode mode = insn_data[icode].operand[1].mode;
+      tree arg;
+      rtx op, addr, pat;
+
+      if (!TARGET_ALTIVEC)
+       abort ();
+
+      arg = TREE_VALUE (arglist);
+      if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+       abort ();
+      op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
+      addr = memory_address (mode, op);
+      if (fcode == ALTIVEC_BUILTIN_MASK_FOR_STORE)
+       op = addr;
+      else
+       {
+         /* For the load case need to negate the address.  */
+         op = gen_reg_rtx (GET_MODE (addr));
+         emit_insn (gen_rtx_SET (VOIDmode, op,
+                        gen_rtx_NEG (GET_MODE (addr), addr)));
+       }
+      op = gen_rtx_MEM (mode, op);
+
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+
+      /*pat = gen_altivec_lvsr (target, op);*/
+      pat = GEN_FCN (icode) (target, op);
+      if (!pat)
+       return 0;
+      emit_insn (pat);
+
+      return target;
+    }
+
   if (TARGET_ALTIVEC)
     {
       ret = altivec_expand_builtin (exp, target, &success);
@@ -7770,6 +7656,21 @@ altivec_init_builtins (void)
 
       def_builtin (d->mask, d->name, type, d->code);
     }
+
+  if (TARGET_ALTIVEC)
+    {
+      tree decl;
+
+      /* Initialize target builtin that implements
+         targetm.vectorize.builtin_mask_for_load.  */
+
+      decl = lang_hooks.builtin_function ("__builtin_altivec_mask_for_load",
+                                         v16qi_ftype_long_pcvoid,
+                                         ALTIVEC_BUILTIN_MASK_FOR_LOAD,
+                                         BUILT_IN_MD, NULL, NULL_TREE);
+      /* Record the decl. Will be used by rs6000_builtin_mask_for_load.  */
+      altivec_builtin_mask_for_load = decl;
+    }
 }
 
 static void
@@ -7910,11 +7811,11 @@ rs6000_common_init_builtins (void)
     = build_function_type_list (V8HI_type_node,
                                V8HI_type_node, V8HI_type_node,
                                V8HI_type_node, NULL_TREE);
- tree v4si_ftype_v8hi_v8hi_v4si
 tree v4si_ftype_v8hi_v8hi_v4si
     = build_function_type_list (V4SI_type_node,
                                V8HI_type_node, V8HI_type_node,
                                V4SI_type_node, NULL_TREE);
- tree v4si_ftype_v16qi_v16qi_v4si
 tree v4si_ftype_v16qi_v16qi_v4si
     = build_function_type_list (V4SI_type_node,
                                V16QI_type_node, V16QI_type_node,
                                V4SI_type_node, NULL_TREE);
@@ -7994,11 +7895,11 @@ rs6000_common_init_builtins (void)
              type = v16qi_ftype_v16qi_v16qi_v16qi;
              break;
            default:
-             abort();
+             abort ();
            }
        }
       else if (mode0 == mode1 && mode1 == mode2 && mode3 == V16QImode)
-        {
+       {
          switch (mode0)
            {
            case V4SImode:
@@ -8014,7 +7915,7 @@ rs6000_common_init_builtins (void)
              type = v16qi_ftype_v16qi_v16qi_v16qi;
              break;
            default:
-             abort();
+             abort ();
            }
        }
       else if (mode0 == V4SImode && mode1 == V16QImode && mode2 == V16QImode
@@ -8203,11 +8104,11 @@ rs6000_common_init_builtins (void)
       mode1 = insn_data[d->icode].operand[1].mode;
 
       if (mode0 == V4SImode && mode1 == QImode)
-        type = v4si_ftype_int;
+       type = v4si_ftype_int;
       else if (mode0 == V8HImode && mode1 == QImode)
-        type = v8hi_ftype_int;
+       type = v8hi_ftype_int;
       else if (mode0 == V16QImode && mode1 == QImode)
-        type = v16qi_ftype_int;
+       type = v16qi_ftype_int;
       else if (mode0 == V4SFmode && mode1 == V4SFmode)
        type = v4sf_ftype_v4sf;
       else if (mode0 == V8HImode && mode1 == V16QImode)
@@ -8249,10 +8150,10 @@ rs6000_init_libfuncs (void)
        }
 
       /* Standard AIX/Darwin/64-bit SVR4 quad floating point routines.  */
-      set_optab_libfunc (add_optab, TFmode, "_xlqadd");
-      set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
-      set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
-      set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
+      set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
+      set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
+      set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
+      set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
     }
   else
     {
@@ -8297,11 +8198,12 @@ expand_block_clear (rtx operands[])
   rtx orig_dest = operands[0];
   rtx bytes_rtx        = operands[1];
   rtx align_rtx = operands[2];
-  int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
-  int align;
-  int bytes;
+  bool constp  = (GET_CODE (bytes_rtx) == CONST_INT);
+  HOST_WIDE_INT align;
+  HOST_WIDE_INT bytes;
   int offset;
   int clear_bytes;
+  int clear_step;
 
   /* If this is not a fixed size move, just call memcpy */
   if (! constp)
@@ -8317,49 +8219,59 @@ expand_block_clear (rtx operands[])
   if (bytes <= 0)
     return 1;
 
-  if (bytes > (TARGET_POWERPC64 && align >= 32 ? 64 : 32))
-    return 0;
+  /* Use the builtin memset after a point, to avoid huge code bloat.
+     When optimize_size, avoid any significant code bloat; calling
+     memset is about 4 instructions, so allow for one instruction to
+     load zero and three to do clearing.  */
+  if (TARGET_ALTIVEC && align >= 128)
+    clear_step = 16;
+  else if (TARGET_POWERPC64 && align >= 32)
+    clear_step = 8;
+  else
+    clear_step = 4;
 
-  if (optimize_size && bytes > 16)
+  if (optimize_size && bytes > 3 * clear_step)
+    return 0;
+  if (! optimize_size && bytes > 8 * clear_step)
     return 0;
 
   for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
     {
-      rtx (*mov) (rtx, rtx);
       enum machine_mode mode = BLKmode;
       rtx dest;
 
-      if (bytes >= 8 && TARGET_POWERPC64
-              /* 64-bit loads and stores require word-aligned
-                 displacements.  */
-              && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
+      if (bytes >= 16 && TARGET_ALTIVEC && align >= 128)
+       {
+         clear_bytes = 16;
+         mode = V4SImode;
+       }
+      else if (bytes >= 8 && TARGET_POWERPC64
+         /* 64-bit loads and stores require word-aligned
+            displacements.  */
+         && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
        {
          clear_bytes = 8;
          mode = DImode;
-         mov = gen_movdi;
        }
-      else if (bytes >= 4 && !STRICT_ALIGNMENT)
+      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
        {                       /* move 4 bytes */
          clear_bytes = 4;
          mode = SImode;
-         mov = gen_movsi;
        }
-      else if (bytes == 2 && !STRICT_ALIGNMENT)
+      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          clear_bytes = 2;
          mode = HImode;
-         mov = gen_movhi;
        }
       else /* move 1 byte at a time */
        {
          clear_bytes = 1;
          mode = QImode;
-         mov = gen_movqi;
        }
 
       dest = adjust_address (orig_dest, mode, offset);
 
-      emit_insn ((*mov) (dest, const0_rtx));
+      emit_move_insn (dest, CONST0_RTX (mode));
     }
 
   return 1;
@@ -8419,7 +8331,15 @@ expand_block_move (rtx operands[])
       enum machine_mode mode = BLKmode;
       rtx src, dest;
 
-      if (TARGET_STRING
+      /* Altivec first, since it will be faster than a string move
+        when it applies, and usually not significantly larger.  */
+      if (TARGET_ALTIVEC && bytes >= 16 && align >= 128)
+       {
+         move_bytes = 16;
+         mode = V4SImode;
+         gen_func.mov = gen_movv4si;
+       }
+      else if (TARGET_STRING
          && bytes > 24         /* move up to 32 bytes at a time */
          && ! fixed_regs[5]
          && ! fixed_regs[6]
@@ -8469,13 +8389,13 @@ expand_block_move (rtx operands[])
          move_bytes = (bytes > 8) ? 8 : bytes;
          gen_func.movmemsi = gen_movmemsi_2reg;
        }
-      else if (bytes >= 4 && !STRICT_ALIGNMENT)
+      else if (bytes >= 4 && (align >= 32 || !STRICT_ALIGNMENT))
        {                       /* move 4 bytes */
          move_bytes = 4;
          mode = SImode;
          gen_func.mov = gen_movsi;
        }
-      else if (bytes == 2 && !STRICT_ALIGNMENT)
+      else if (bytes == 2 && (align >= 16 || !STRICT_ALIGNMENT))
        {                       /* move 2 bytes */
          move_bytes = 2;
          mode = HImode;
@@ -8528,580 +8448,81 @@ expand_block_move (rtx operands[])
              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.movmemsi) (dest, src,
-                                          GEN_INT (move_bytes & 31),
-                                          align_rtx));
-       }
-    }
-
-  return 1;
-}
-
-\f
-/* Return 1 if OP is suitable for a save_world call in prologue. It is
-   known to be a PARALLEL. */
-int
-save_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int index;
-  int i;
-  rtx elt;
-  int count = XVECLEN (op, 0);
-
-  if (count != 55)
-    return 0;
-
-  index = 0;
-  if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
-      || GET_CODE (XVECEXP (op, 0, index++)) != USE)
-    return 0;
-
-  for (i=1; i <= 18; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != MEM
-         || ! memory_operand (SET_DEST (elt), DFmode)
-         || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != DFmode)
-       return 0;
-    }
-
-  for (i=1; i <= 12; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != MEM
-         || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != V4SImode)
-       return 0;
-    }
-
-  for (i=1; i <= 19; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != MEM
-         || ! memory_operand (SET_DEST (elt), Pmode)
-         || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != Pmode)
-       return 0;
-    }
-
-  elt = XVECEXP (op, 0, index++);
-  if (GET_CODE (elt) != SET
-      || GET_CODE (SET_DEST (elt)) != MEM
-      || ! memory_operand (SET_DEST (elt), Pmode)
-      || GET_CODE (SET_SRC (elt)) != REG
-      || REGNO (SET_SRC (elt)) != CR2_REGNO
-      || GET_MODE (SET_SRC (elt)) != Pmode)
-    return 0;
-
-  if (GET_CODE (XVECEXP (op, 0, index++)) != USE
-      || GET_CODE (XVECEXP (op, 0, index++)) != USE
-      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
-    return 0;
-  return 1;
-}
-
-/* Return 1 if OP is suitable for a save_world call in prologue. It is
-   known to be a PARALLEL. */
-int
-restore_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int index;
-  int i;
-  rtx elt;
-  int count = XVECLEN (op, 0);
-
-  if (count != 59)
-    return 0;
-
-  index = 0;
-  if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN
-      || GET_CODE (XVECEXP (op, 0, index++)) != USE
-      || GET_CODE (XVECEXP (op, 0, index++)) != USE
-      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
-    return 0;
-
-  elt = XVECEXP (op, 0, index++);
-  if (GET_CODE (elt) != SET
-      || GET_CODE (SET_SRC (elt)) != MEM
-      || ! memory_operand (SET_SRC (elt), Pmode)
-      || GET_CODE (SET_DEST (elt)) != REG
-      || REGNO (SET_DEST (elt)) != CR2_REGNO
-      || GET_MODE (SET_DEST (elt)) != Pmode)
-    return 0;
-
-  for (i=1; i <= 19; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != MEM
-         || ! memory_operand (SET_SRC (elt), Pmode)
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != Pmode)
-       return 0;
-    }
-
-  for (i=1; i <= 12; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != MEM
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != V4SImode)
-       return 0;
-    }
-
-  for (i=1; i <= 18; i++)
-    {
-      elt = XVECEXP (op, 0, index++);
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != MEM
-         || ! memory_operand (SET_SRC (elt), DFmode)
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != DFmode)
-       return 0;
-    }
-
-  if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
-      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
-      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
-      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
-      || GET_CODE (XVECEXP (op, 0, index++)) != USE)
-    return 0;
-  return 1;
-}
-
-\f
-/* Return 1 if OP is a load multiple operation.  It is known to be a
-   PARALLEL and the first section will be tested.  */
-
-int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  unsigned int dest_regno;
-  rtx src_addr;
-  int i;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
-    return 0;
-
-  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
-  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
-
-  for (i = 1; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i);
-
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != SImode
-         || REGNO (SET_DEST (elt)) != dest_regno + i
-         || GET_CODE (SET_SRC (elt)) != MEM
-         || GET_MODE (SET_SRC (elt)) != SImode
-         || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
-         || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
-         || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
-         || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != i * 4)
-       return 0;
-    }
-
-  return 1;
-}
-
-/* Similar, but tests for store multiple.  Here, the second vector element
-   is a CLOBBER.  It will be tested later.  */
-
-int
-store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0) - 1;
-  unsigned int src_regno;
-  rtx dest_addr;
-  int i;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
-    return 0;
-
-  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
-  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
-
-  for (i = 1; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i + 1);
-
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != SImode
-         || REGNO (SET_SRC (elt)) != src_regno + i
-         || GET_CODE (SET_DEST (elt)) != MEM
-         || GET_MODE (SET_DEST (elt)) != SImode
-         || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
-         || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
-         || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
-         || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != i * 4)
-       return 0;
-    }
-
-  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 (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
-vrsave_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  unsigned int dest_regno, src_regno;
-  int i;
-
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC_VOLATILE)
-    return 0;
-
-  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
-  src_regno  = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
-
-  if (dest_regno != VRSAVE_REGNO
-      && src_regno != VRSAVE_REGNO)
-    return 0;
-
-  for (i = 1; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i);
-
-      if (GET_CODE (elt) != CLOBBER
-         && GET_CODE (elt) != SET)
-       return 0;
-    }
-
-  return 1;
-}
-
-/* Return 1 for an PARALLEL suitable for mfcr.  */
-
-int
-mfcr_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  int i;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count < 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
-      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
-    return 0;
-
-  for (i = 0; i < count; i++)
-    {
-      rtx exp = XVECEXP (op, 0, i);
-      rtx unspec;
-      int maskval;
-      rtx src_reg;
-
-      src_reg = XVECEXP (SET_SRC (exp), 0, 0);
-
-      if (GET_CODE (src_reg) != REG
-         || GET_MODE (src_reg) != CCmode
-         || ! CR_REGNO_P (REGNO (src_reg)))
-       return 0;
-
-      if (GET_CODE (exp) != SET
-         || GET_CODE (SET_DEST (exp)) != REG
-         || GET_MODE (SET_DEST (exp)) != SImode
-         || ! INT_REGNO_P (REGNO (SET_DEST (exp))))
-       return 0;
-      unspec = SET_SRC (exp);
-      maskval = 1 << (MAX_CR_REGNO - REGNO (src_reg));
-
-      if (GET_CODE (unspec) != UNSPEC
-         || XINT (unspec, 1) != UNSPEC_MOVESI_FROM_CR
-         || XVECLEN (unspec, 0) != 2
-         || XVECEXP (unspec, 0, 0) != src_reg
-         || GET_CODE (XVECEXP (unspec, 0, 1)) != CONST_INT
-         || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
-       return 0;
-    }
-  return 1;
-}
-
-/* Return 1 for an PARALLEL suitable for mtcrf.  */
-
-int
-mtcrf_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  int i;
-  rtx src_reg;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count < 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC
-      || XVECLEN (SET_SRC (XVECEXP (op, 0, 0)), 0) != 2)
-    return 0;
-  src_reg = XVECEXP (SET_SRC (XVECEXP (op, 0, 0)), 0, 0);
-
-  if (GET_CODE (src_reg) != REG
-      || GET_MODE (src_reg) != SImode
-      || ! INT_REGNO_P (REGNO (src_reg)))
-    return 0;
-
-  for (i = 0; i < count; i++)
-    {
-      rtx exp = XVECEXP (op, 0, i);
-      rtx unspec;
-      int maskval;
-
-      if (GET_CODE (exp) != SET
-         || GET_CODE (SET_DEST (exp)) != REG
-         || GET_MODE (SET_DEST (exp)) != CCmode
-         || ! CR_REGNO_P (REGNO (SET_DEST (exp))))
-       return 0;
-      unspec = SET_SRC (exp);
-      maskval = 1 << (MAX_CR_REGNO - REGNO (SET_DEST (exp)));
-
-      if (GET_CODE (unspec) != UNSPEC
-         || 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
-         || INTVAL (XVECEXP (unspec, 0, 1)) != maskval)
-       return 0;
-    }
-  return 1;
-}
-
-/* Return 1 for an PARALLEL suitable for lmw.  */
-
-int
-lmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  unsigned int dest_regno;
-  rtx src_addr;
-  unsigned int base_regno;
-  HOST_WIDE_INT offset;
-  int i;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
-    return 0;
-
-  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
-  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
-
-  if (dest_regno > 31
-      || count != 32 - (int) dest_regno)
-    return 0;
-
-  if (legitimate_indirect_address_p (src_addr, 0))
-    {
-      offset = 0;
-      base_regno = REGNO (src_addr);
-      if (base_regno == 0)
-       return 0;
-    }
-  else if (rs6000_legitimate_offset_address_p (SImode, src_addr, 0))
-    {
-      offset = INTVAL (XEXP (src_addr, 1));
-      base_regno = REGNO (XEXP (src_addr, 0));
-    }
-  else
-    return 0;
-
-  for (i = 0; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i);
-      rtx newaddr;
-      rtx addr_reg;
-      HOST_WIDE_INT newoffset;
-
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != SImode
-         || REGNO (SET_DEST (elt)) != dest_regno + i
-         || GET_CODE (SET_SRC (elt)) != MEM
-         || GET_MODE (SET_SRC (elt)) != SImode)
-       return 0;
-      newaddr = XEXP (SET_SRC (elt), 0);
-      if (legitimate_indirect_address_p (newaddr, 0))
-       {
-         newoffset = 0;
-         addr_reg = newaddr;
-       }
-      else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0))
-       {
-         addr_reg = XEXP (newaddr, 0);
-         newoffset = INTVAL (XEXP (newaddr, 1));
-       }
-      else
-       return 0;
-      if (REGNO (addr_reg) != base_regno
-         || newoffset != offset + 4 * i)
-       return 0;
-    }
-
-  return 1;
-}
-
-/* Return 1 for an PARALLEL suitable for stmw.  */
-
-int
-stmw_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  int count = XVECLEN (op, 0);
-  unsigned int src_regno;
-  rtx dest_addr;
-  unsigned int base_regno;
-  HOST_WIDE_INT offset;
-  int i;
-
-  /* Perform a quick check so we don't blow up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != MEM
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != REG)
-    return 0;
-
-  src_regno = REGNO (SET_SRC (XVECEXP (op, 0, 0)));
-  dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, 0)), 0);
-
-  if (src_regno > 31
-      || count != 32 - (int) src_regno)
-    return 0;
-
-  if (legitimate_indirect_address_p (dest_addr, 0))
-    {
-      offset = 0;
-      base_regno = REGNO (dest_addr);
-      if (base_regno == 0)
-       return 0;
-    }
-  else if (rs6000_legitimate_offset_address_p (SImode, dest_addr, 0))
-    {
-      offset = INTVAL (XEXP (dest_addr, 1));
-      base_regno = REGNO (XEXP (dest_addr, 0));
-    }
-  else
-    return 0;
-
-  for (i = 0; i < count; i++)
-    {
-      rtx elt = XVECEXP (op, 0, i);
-      rtx newaddr;
-      rtx addr_reg;
-      HOST_WIDE_INT newoffset;
+         set_mem_size (dest, GEN_INT (move_bytes));
 
-      if (GET_CODE (elt) != SET
-         || GET_CODE (SET_SRC (elt)) != REG
-         || GET_MODE (SET_SRC (elt)) != SImode
-         || REGNO (SET_SRC (elt)) != src_regno + i
-         || GET_CODE (SET_DEST (elt)) != MEM
-         || GET_MODE (SET_DEST (elt)) != SImode)
-       return 0;
-      newaddr = XEXP (SET_DEST (elt), 0);
-      if (legitimate_indirect_address_p (newaddr, 0))
-       {
-         newoffset = 0;
-         addr_reg = newaddr;
-       }
-      else if (rs6000_legitimate_offset_address_p (SImode, newaddr, 0))
-       {
-         addr_reg = XEXP (newaddr, 0);
-         newoffset = INTVAL (XEXP (newaddr, 1));
+         emit_insn ((*gen_func.movmemsi) (dest, src,
+                                          GEN_INT (move_bytes & 31),
+                                          align_rtx));
        }
-      else
-       return 0;
-      if (REGNO (addr_reg) != base_regno
-         || newoffset != offset + 4 * i)
-       return 0;
     }
 
   return 1;
 }
+
+\f
+/* 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 (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";
+}
+
 \f
 /* A validation routine: say whether CODE, a condition code, and MODE
    match.  The other alternatives either don't make sense or should
    never be generated.  */
 
-static void
+void
 validate_condition_mode (enum rtx_code code, enum machine_mode mode)
 {
   if ((GET_RTX_CLASS (code) != RTX_COMPARE
@@ -9140,82 +8561,6 @@ validate_condition_mode (enum rtx_code code, enum machine_mode mode)
     abort ();
 }
 
-/* Return 1 if OP is a comparison operation that is valid for a branch insn.
-   We only check the opcode against the mode of the CC value here.  */
-
-int
-branch_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (op);
-  enum machine_mode cc_mode;
-
-  if (!COMPARISON_P (op))
-    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);
-
-  return 1;
-}
-
-/* Return 1 if OP is a comparison operation that is valid for a branch
-   insn and which is true if the corresponding bit in the CC register
-   is set.  */
-
-int
-branch_positive_comparison_operator (rtx op, enum machine_mode mode)
-{
-  enum rtx_code code;
-
-  if (! branch_comparison_operator (op, mode))
-    return 0;
-
-  code = GET_CODE (op);
-  return (code == EQ || code == LT || code == GT
-         || code == LTU || code == GTU
-         || code == UNORDERED);
-}
-
-/* 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 (rtx op, enum machine_mode mode)
-{
-  return branch_positive_comparison_operator (op, mode);
-}
-
-int
-trap_comparison_operator (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  return COMPARISON_P (op);
-}
-
-int
-boolean_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (op);
-  return (code == AND || code == IOR || code == XOR);
-}
-
-int
-boolean_or_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (op);
-  return (code == IOR || code == XOR);
-}
-
-int
-min_max_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (op);
-  return (code == SMIN || code == SMAX || code == UMIN || code == UMAX);
-}
 \f
 /* Return 1 if ANDOP is a mask that has no bits on that are not in the
    mask required to convert the result of a rotate insn into a shift
@@ -9470,11 +8815,11 @@ mems_ok_for_quad_peep (rtx mem1, rtx mem2)
        return 0;
       else
        {
-          reg1 = REGNO (XEXP (addr1, 0));
+         reg1 = REGNO (XEXP (addr1, 0));
          /* The offset must be constant!  */
          if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
-            return 0;
-          offset1 = INTVAL (XEXP (addr1, 1));
+           return 0;
+         offset1 = INTVAL (XEXP (addr1, 1));
        }
     }
   else if (GET_CODE (addr1) != REG)
@@ -9523,23 +8868,23 @@ secondary_reload_class (enum reg_class class,
 
   if (TARGET_ELF || (DEFAULT_ABI == ABI_DARWIN
 #if TARGET_MACHO
-                    && MACHOPIC_INDIRECT
+                    && MACHOPIC_INDIRECT
 #endif
-                    ))
+                    ))
     {
       /* We cannot copy a symbolic operand directly into anything
-         other than BASE_REGS for TARGET_ELF.  So indicate that a
-         register from BASE_REGS is needed as an intermediate
-         register.
+        other than BASE_REGS for TARGET_ELF.  So indicate that a
+        register from BASE_REGS is needed as an intermediate
+        register.
 
         On Darwin, pic addresses require a load from memory, which
         needs a base register.  */
       if (class != BASE_REGS
-          && (GET_CODE (in) == SYMBOL_REF
-              || GET_CODE (in) == HIGH
-              || GET_CODE (in) == LABEL_REF
-              || GET_CODE (in) == CONST))
-        return BASE_REGS;
+         && (GET_CODE (in) == SYMBOL_REF
+             || GET_CODE (in) == HIGH
+             || GET_CODE (in) == LABEL_REF
+             || GET_CODE (in) == CONST))
+       return BASE_REGS;
     }
 
   if (GET_CODE (in) == REG)
@@ -9653,7 +8998,7 @@ ccr_bit (rtx op, int scc_p)
 \f
 /* Return the GOT register.  */
 
-struct rtx_def *
+rtx
 rs6000_got_register (rtx value ATTRIBUTE_UNUSED)
 {
   /* The second flow pass currently (June 1999) can't update
@@ -9872,7 +9217,7 @@ print_operand (FILE *file, rtx x, int code)
     case 'B':
       /* If the low-order bit is zero, write 'r'; otherwise, write 'l'
         for 64-bit mask direction.  */
-      putc (((INT_LOWPART(x) & 1) == 0 ? 'r' : 'l'), file);
+      putc (((INT_LOWPART (x) & 1) == 0 ? 'r' : 'l'), file);
       return;
 
       /* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
@@ -9894,8 +9239,7 @@ print_operand (FILE *file, rtx x, int code)
       /* Bit 1 is EQ bit.  */
       i = 4 * (REGNO (x) - CR0_REGNO) + 2;
 
-      /* If we want bit 31, write a shift count of zero, not 32.  */
-      fprintf (file, "%d", i == 31 ? 0 : i + 1);
+      fprintf (file, "%d", i);
       return;
 
     case 'E':
@@ -10021,7 +9365,7 @@ print_operand (FILE *file, rtx x, int code)
       /* Write second word of DImode or DFmode reference.  Works on register
         or non-indexed memory only.  */
       if (GET_CODE (x) == REG)
-       fprintf (file, "%s", reg_names[REGNO (x) + 1]);
+       fputs (reg_names[REGNO (x) + 1], file);
       else if (GET_CODE (x) == MEM)
        {
          /* Handle possible auto-increment.  Since it is pre-increment and
@@ -10092,15 +9436,15 @@ print_operand (FILE *file, rtx x, int code)
          || REGNO (XEXP (x, 0)) >= 32)
        output_operand_lossage ("invalid %%P value");
       else
-       fprintf (file, "%s", reg_names[REGNO (XEXP (x, 0))]);
+       fputs (reg_names[REGNO (XEXP (x, 0))], file);
       return;
 
     case 'q':
       /* This outputs the logical code corresponding to a boolean
         expression.  The expression may have one or both operands
         negated (if one, only the first one).  For condition register
-         logical operations, it will also treat the negated
-         CR codes as NOTs, but not handle NOTs of them.  */
+        logical operations, it will also treat the negated
+        CR codes as NOTs, but not handle NOTs of them.  */
       {
        const char *const *t = 0;
        const char *s;
@@ -10327,7 +9671,7 @@ print_operand (FILE *file, rtx x, int code)
     case 'Y':
       /* Like 'L', for third word of TImode  */
       if (GET_CODE (x) == REG)
-       fprintf (file, "%s", reg_names[REGNO (x) + 2]);
+       fputs (reg_names[REGNO (x) + 2], file);
       else if (GET_CODE (x) == MEM)
        {
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
@@ -10350,9 +9694,10 @@ print_operand (FILE *file, rtx x, int code)
       if (GET_CODE (x) != SYMBOL_REF)
        abort ();
 
-      /* Mark the decl as referenced so that cgraph will output the function.  */
+      /* Mark the decl as referenced so that cgraph will output the
+        function.  */
       if (SYMBOL_REF_DECL (x))
-        mark_decl_referenced (SYMBOL_REF_DECL (x));
+       mark_decl_referenced (SYMBOL_REF_DECL (x));
 
       /* For macho, check to see if we need a stub.  */
       if (TARGET_MACHO)
@@ -10374,7 +9719,7 @@ print_operand (FILE *file, rtx x, int code)
     case 'Z':
       /* Like 'L', for last word of TImode.  */
       if (GET_CODE (x) == REG)
-       fprintf (file, "%s", reg_names[REGNO (x) + 3]);
+       fputs (reg_names[REGNO (x) + 3], file);
       else if (GET_CODE (x) == MEM)
        {
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
@@ -10422,6 +9767,11 @@ print_operand (FILE *file, rtx x, int code)
 
            /* Fall through.  Must be [reg+reg].  */
          }
+       if (TARGET_ALTIVEC
+           && GET_CODE (tmp) == AND
+           && GET_CODE (XEXP (tmp, 1)) == CONST_INT
+           && INTVAL (XEXP (tmp, 1)) == -16)
+         tmp = XEXP (tmp, 0);
        if (GET_CODE (tmp) == REG)
          fprintf (file, "0,%s", reg_names[REGNO (tmp)]);
        else if (GET_CODE (tmp) == PLUS && GET_CODE (XEXP (tmp, 1)) == REG)
@@ -10498,7 +9848,7 @@ print_operand_address (FILE *file, rtx x)
             INTVAL (XEXP (x, 1)), reg_names[ REGNO (XEXP (x, 0)) ]);
 #if TARGET_ELF
   else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
-           && CONSTANT_P (XEXP (x, 1)))
+          && CONSTANT_P (XEXP (x, 1)))
     {
       output_addr_const (file, XEXP (x, 1));
       fprintf (file, "@l(%s)", reg_names[ REGNO (XEXP (x, 0)) ]);
@@ -10506,7 +9856,7 @@ print_operand_address (FILE *file, rtx x)
 #endif
 #if TARGET_MACHO
   else if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == REG
-           && CONSTANT_P (XEXP (x, 1)))
+          && CONSTANT_P (XEXP (x, 1)))
     {
       fprintf (file, "lo16(");
       output_addr_const (file, XEXP (x, 1));
@@ -10563,7 +9913,7 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
 #ifdef RELOCATABLE_NEEDS_FIXUP
   /* Special handling for SI values.  */
-  if (size == 4 && aligned_p)
+  if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
     {
       extern int in_toc_section (void);
       static int recurse = 0;
@@ -10629,7 +9979,7 @@ rs6000_assemble_visibility (tree decl, int vis)
       && TREE_CODE (decl) == FUNCTION_DECL)
     {
       static const char * const visibility_types[] = {
-        NULL, "internal", "hidden", "protected"
+       NULL, "internal", "hidden", "protected"
       };
 
       const char *name, *type;
@@ -10672,7 +10022,17 @@ rs6000_generate_compare (enum rtx_code code)
   if (rs6000_compare_fp_p)
     comp_mode = CCFPmode;
   else if (code == GTU || code == LTU
-         || code == GEU || code == LEU)
+          || code == GEU || code == LEU)
+    comp_mode = CCUNSmode;
+  else if ((code == EQ || code == NE)
+          && GET_CODE (rs6000_compare_op0) == SUBREG
+          && GET_CODE (rs6000_compare_op1) == SUBREG
+          && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op0)
+          && SUBREG_PROMOTED_UNSIGNED_P (rs6000_compare_op1))
+    /* These are unsigned values, perhaps there will be a later
+       ordering compare that can be shared with this one.
+       Unfortunately we cannot detect the signedness of the operands
+       for non-subregs.  */
     comp_mode = CCUNSmode;
   else
     comp_mode = CCmode;
@@ -10684,7 +10044,11 @@ rs6000_generate_compare (enum rtx_code code)
   if ((TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT)
       && rs6000_compare_fp_p)
     {
-      rtx cmp, or1, or2, or_result, compare_result2;
+      rtx cmp, or_result, compare_result2;
+      enum machine_mode op_mode = GET_MODE (rs6000_compare_op0);
+
+      if (op_mode == VOIDmode)
+       op_mode = GET_MODE (rs6000_compare_op1);
 
       /* Note: The E500 comparison instructions set the GT bit (x +
         1), on success.  This explains the mess.  */
@@ -10692,28 +10056,52 @@ rs6000_generate_compare (enum rtx_code code)
       switch (code)
        {
        case EQ: case UNEQ: case NE: case LTGT:
-         cmp = flag_finite_math_only
-           ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1)
-           : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1);
+         if (op_mode == SFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstsfeq_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpsfeq_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else if (op_mode == DFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstdfeq_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpdfeq_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else abort ();
          break;
        case GT: case GTU: case UNGT: case UNGE: case GE: case GEU:
-         cmp = flag_finite_math_only
-           ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1)
-           : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1);
+         if (op_mode == SFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstsfgt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpsfgt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else if (op_mode == DFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstdfgt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpdfgt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else abort ();
          break;
        case LT: case LTU: case UNLT: case UNLE: case LE: case LEU:
-         cmp = flag_finite_math_only
-           ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1)
-           : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
-                              rs6000_compare_op1);
+         if (op_mode == SFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstsflt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpsflt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else if (op_mode == DFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstdflt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpdflt_gpr (compare_result, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else abort ();
          break;
-       default:
-         abort ();
+        default:
+          abort ();
        }
 
       /* Synthesize LE and GE from LT/GT || EQ.  */
@@ -10730,27 +10118,28 @@ rs6000_generate_compare (enum rtx_code code)
            default: abort ();
            }
 
-         or1 = gen_reg_rtx (SImode);
-         or2 = gen_reg_rtx (SImode);
-         or_result = gen_reg_rtx (CCEQmode);
          compare_result2 = gen_reg_rtx (CCFPmode);
 
          /* Do the EQ.  */
-         cmp = flag_finite_math_only
-           ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
-                              rs6000_compare_op1)
-           : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
-                              rs6000_compare_op1);
+         if (op_mode == SFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstsfeq_gpr (compare_result2, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpsfeq_gpr (compare_result2, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else if (op_mode == DFmode)
+           cmp = flag_unsafe_math_optimizations
+             ? gen_tstdfeq_gpr (compare_result2, rs6000_compare_op0,
+                                rs6000_compare_op1)
+             : gen_cmpdfeq_gpr (compare_result2, rs6000_compare_op0,
+                                rs6000_compare_op1);
+         else abort ();
          emit_insn (cmp);
 
-         or1 = gen_rtx_GT (SImode, compare_result, const0_rtx);
-         or2 = gen_rtx_GT (SImode, compare_result2, const0_rtx);
-
          /* OR them together.  */
-         cmp = gen_rtx_SET (VOIDmode, or_result,
-                            gen_rtx_COMPARE (CCEQmode,
-                                             gen_rtx_IOR (SImode, or1, or2),
-                                             const_true_rtx));
+         or_result = gen_reg_rtx (CCFPmode);
+         cmp = gen_e500_cr_ior_compare (or_result, compare_result,
+                                          compare_result2);
          compare_result = or_result;
          code = EQ;
        }
@@ -10765,16 +10154,40 @@ rs6000_generate_compare (enum rtx_code code)
       emit_insn (cmp);
     }
   else
-    emit_insn (gen_rtx_SET (VOIDmode, compare_result,
-                           gen_rtx_COMPARE (comp_mode,
-                                            rs6000_compare_op0,
-                                            rs6000_compare_op1)));
+    {
+      /* Generate XLC-compatible TFmode compare as PARALLEL with extra
+        CLOBBERs to match cmptf_internal2 pattern.  */
+      if (comp_mode == CCFPmode && TARGET_XL_COMPAT
+         && GET_MODE (rs6000_compare_op0) == TFmode
+         && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+         && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
+       emit_insn (gen_rtx_PARALLEL (VOIDmode,
+         gen_rtvec (9,
+                    gen_rtx_SET (VOIDmode,
+                                 compare_result,
+                                 gen_rtx_COMPARE (comp_mode,
+                                                  rs6000_compare_op0,
+                                                  rs6000_compare_op1)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)),
+                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (DFmode)))));
+      else
+       emit_insn (gen_rtx_SET (VOIDmode, compare_result,
+                               gen_rtx_COMPARE (comp_mode,
+                                                rs6000_compare_op0,
+                                                rs6000_compare_op1)));
+    }
 
   /* Some kinds of FP comparisons need an OR operation;
      under flag_finite_math_only we don't bother.  */
   if (rs6000_compare_fp_p
-      && ! flag_finite_math_only
-      && ! (TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
+      && !flag_finite_math_only
+      && !(TARGET_HARD_FLOAT && TARGET_E500 && !TARGET_FPRS)
       && (code == LE || code == GE
          || code == UNEQ || code == LTGT
          || code == UNGT || code == UNLT))
@@ -10836,9 +10249,9 @@ rs6000_emit_sCOND (enum rtx_code code, rtx result)
        abort ();
 
       if (cond_code == NE)
-       emit_insn (gen_e500_flip_eq_bit (t, t));
+       emit_insn (gen_e500_flip_gt_bit (t, t));
 
-      emit_insn (gen_move_from_CR_eq_bit (result, t));
+      emit_insn (gen_move_from_CR_gt_bit (result, t));
       return;
     }
 
@@ -10989,7 +10402,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
        {
          if (abs (prob) > REG_BR_PROB_BASE / 20
              && ((prob > 0) ^ need_longbranch))
-              pred = "+";
+           pred = "+";
          else
            pred = "-";
        }
@@ -11019,9 +10432,9 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
   return string;
 }
 
-/* Return the string to flip the EQ bit on a CR.  */
+/* Return the string to flip the GT bit on a CR.  */
 char *
-output_e500_flip_eq_bit (rtx dst, rtx src)
+output_e500_flip_gt_bit (rtx dst, rtx src)
 {
   static char string[64];
   int a, b;
@@ -11030,14 +10443,279 @@ output_e500_flip_eq_bit (rtx dst, rtx src)
       || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
     abort ();
 
-  /* EQ bit.  */
-  a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
-  b = 4 * (REGNO (src) - CR0_REGNO) + 2;
+  /* GT bit.  */
+  a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
+  b = 4 * (REGNO (src) - CR0_REGNO) + 1;
 
   sprintf (string, "crnot %d,%d", a, b);
   return string;
 }
 
+/* Return insn index for the vector compare instruction for given CODE,
+   and DEST_MODE, OP_MODE. Return INSN_NOT_AVAILABLE if valid insn is
+   not available.  */
+
+static int
+get_vec_cmp_insn (enum rtx_code code,
+                 enum machine_mode dest_mode,
+                 enum machine_mode op_mode)
+{
+  if (!TARGET_ALTIVEC)
+    return INSN_NOT_AVAILABLE;
+
+  switch (code)
+    {
+    case EQ:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPEQUB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPEQUH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPEQUW;
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPEQFP;
+      break;
+    case GE:
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPGEFP;
+    case GT:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPGTSB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPGTSH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPGTSW;
+      if (dest_mode == V4SImode && op_mode == V4SFmode)
+       return UNSPEC_VCMPGTFP;
+      break;
+    case GTU:
+      if (dest_mode == V16QImode && op_mode == V16QImode)
+       return UNSPEC_VCMPGTUB;
+      if (dest_mode == V8HImode && op_mode == V8HImode)
+       return UNSPEC_VCMPGTUH;
+      if (dest_mode == V4SImode && op_mode == V4SImode)
+       return UNSPEC_VCMPGTUW;
+      break;
+    default:
+      break;
+    }
+  return INSN_NOT_AVAILABLE;
+}
+
+/* Emit vector compare for operands OP0 and OP1 using code RCODE.
+   DMODE is expected destination mode. This is a recursive function.  */
+
+static rtx
+rs6000_emit_vector_compare (enum rtx_code rcode,
+                           rtx op0, rtx op1,
+                           enum machine_mode dmode)
+{
+  int vec_cmp_insn;
+  rtx mask;
+  enum machine_mode dest_mode;
+  enum machine_mode op_mode = GET_MODE (op1);
+
+#ifdef ENABLE_CHECKING
+  if (!TARGET_ALTIVEC)
+    abort ();
+
+  if (GET_MODE (op0) != GET_MODE (op1))
+    abort ();
+#endif
+
+  /* Floating point vector compare instructions uses destination V4SImode.
+     Move destination to appropriate mode later.  */
+  if (dmode == V4SFmode)
+    dest_mode = V4SImode;
+  else
+    dest_mode = dmode;
+
+  mask = gen_reg_rtx (dest_mode);
+  vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
+
+  if (vec_cmp_insn == INSN_NOT_AVAILABLE)
+    {
+      bool swap_operands = false;
+      bool try_again = false;
+      switch (rcode)
+       {
+       case LT:
+         rcode = GT;
+         swap_operands = true;
+         try_again = true;
+         break;
+       case LTU:
+         rcode = GTU;
+         swap_operands = true;
+         try_again = true;
+         break;
+       case NE:
+         /* Treat A != B as ~(A==B).  */
+         {
+           enum insn_code nor_code;
+           rtx eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
+                                                    dest_mode);
+
+           nor_code = one_cmpl_optab->handlers[(int)dest_mode].insn_code;
+           if (nor_code == CODE_FOR_nothing)
+             abort ();
+           emit_insn (GEN_FCN (nor_code) (mask, eq_rtx));
+
+           if (dmode != dest_mode)
+             {
+               rtx temp = gen_reg_rtx (dest_mode);
+               convert_move (temp, mask, 0);
+               return temp;
+             }
+           return mask;
+         }
+         break;
+       case GE:
+       case GEU:
+       case LE:
+       case LEU:
+         /* Try GT/GTU/LT/LTU OR EQ */
+         {
+           rtx c_rtx, eq_rtx;
+           enum insn_code ior_code;
+           enum rtx_code new_code;
+
+           if (rcode == GE)
+             new_code = GT;
+           else if (rcode == GEU)
+             new_code = GTU;
+           else if (rcode == LE)
+             new_code = LT;
+           else if (rcode == LEU)
+             new_code = LTU;
+           else
+             abort ();
+
+           c_rtx = rs6000_emit_vector_compare (new_code,
+                                               op0, op1, dest_mode);
+           eq_rtx = rs6000_emit_vector_compare (EQ, op0, op1,
+                                                dest_mode);
+
+           ior_code = ior_optab->handlers[(int)dest_mode].insn_code;
+           if (ior_code == CODE_FOR_nothing)
+             abort ();
+           emit_insn (GEN_FCN (ior_code) (mask, c_rtx, eq_rtx));
+           if (dmode != dest_mode)
+             {
+               rtx temp = gen_reg_rtx (dest_mode);
+               convert_move (temp, mask, 0);
+               return temp;
+             }
+           return mask;
+         }
+         break;
+       default:
+         abort ();
+       }
+
+      if (try_again)
+       {
+         vec_cmp_insn = get_vec_cmp_insn (rcode, dest_mode, op_mode);
+         if (vec_cmp_insn == INSN_NOT_AVAILABLE)
+           /* You only get two chances.  */
+           abort ();
+       }
+
+      if (swap_operands)
+       {
+         rtx tmp;
+         tmp = op0;
+         op0 = op1;
+         op1 = tmp;
+       }
+    }
+
+  emit_insn (gen_rtx_fmt_ee (SET,
+                            VOIDmode,
+                            mask,
+                            gen_rtx_fmt_Ei (UNSPEC, dest_mode,
+                                            gen_rtvec (2, op0, op1),
+                                            vec_cmp_insn)));
+  if (dmode != dest_mode)
+    {
+      rtx temp = gen_reg_rtx (dest_mode);
+      convert_move (temp, mask, 0);
+      return temp;
+    }
+  return mask;
+}
+
+/* Return vector select instruction for MODE. Return INSN_NOT_AVAILABLE, if
+   valid insn doesn exist for given mode.  */
+
+static int
+get_vsel_insn (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case V4SImode:
+      return UNSPEC_VSEL4SI;
+      break;
+    case V4SFmode:
+      return UNSPEC_VSEL4SF;
+      break;
+    case V8HImode:
+      return UNSPEC_VSEL8HI;
+      break;
+    case V16QImode:
+      return UNSPEC_VSEL16QI;
+      break;
+    default:
+      return INSN_NOT_AVAILABLE;
+      break;
+    }
+  return INSN_NOT_AVAILABLE;
+}
+
+/* Emit vector select insn where DEST is destination using
+   operands OP1, OP2 and MASK.  */
+
+static void
+rs6000_emit_vector_select (rtx dest, rtx op1, rtx op2, rtx mask)
+{
+  rtx t, temp;
+  enum machine_mode dest_mode = GET_MODE (dest);
+  int vsel_insn_index  = get_vsel_insn (GET_MODE (dest));
+
+  temp = gen_reg_rtx (dest_mode);
+
+  t = gen_rtx_fmt_ee (SET, VOIDmode, temp,
+                     gen_rtx_fmt_Ei (UNSPEC, dest_mode,
+                                     gen_rtvec (3, op1, op2, mask),
+                                     vsel_insn_index));
+  emit_insn (t);
+  emit_move_insn (dest, temp);
+  return;
+}
+
+/* Emit vector conditional expression.
+   DEST is destination. OP1 and OP2 are two VEC_COND_EXPR operands.
+   CC_OP0 and CC_OP1 are the two operands for the relation operation COND.  */
+
+int
+rs6000_emit_vector_cond_expr (rtx dest, rtx op1, rtx op2,
+                             rtx cond, rtx cc_op0, rtx cc_op1)
+{
+  enum machine_mode dest_mode = GET_MODE (dest);
+  enum rtx_code rcode = GET_CODE (cond);
+  rtx mask;
+
+  if (!TARGET_ALTIVEC)
+    return 0;
+
+  /* Get the vector mask for the given relational operations.  */
+  mask = rs6000_emit_vector_compare (rcode, cc_op0, cc_op1, dest_mode);
+
+  rs6000_emit_vector_select (dest, op1, op2, mask);
+
+  return 1;
+}
+
 /* Emit a conditional move: move TRUE_COND to DEST if OP of the
    operands of the last comparison is nonzero/true, FALSE_COND if it
    is zero/false.  Return 0 if the hardware has no such operation.  */
@@ -11052,6 +10730,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
   enum machine_mode compare_mode = GET_MODE (op0);
   enum machine_mode result_mode = GET_MODE (dest);
   rtx temp;
+  bool is_against_zero;
 
   /* These modes should always match.  */
   if (GET_MODE (op1) != compare_mode
@@ -11076,6 +10755,17 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
           && GET_MODE_CLASS (compare_mode) == MODE_FLOAT)
     return 0;
 
+  is_against_zero = op1 == CONST0_RTX (compare_mode);
+
+  /* A floating-point subtract might overflow, underflow, or produce
+     an inexact result, thus changing the floating-point flags, so it
+     can't be generated if we care about that.  It's safe if one side
+     of the construct is zero, since then no subtract will be
+     generated.  */
+  if (GET_MODE_CLASS (compare_mode) == MODE_FLOAT
+      && flag_trapping_math && ! is_against_zero)
+    return 0;
+
   /* Eliminate half of the comparisons by switching operands, this
      makes the remaining code simpler.  */
   if (code == UNLT || code == UNGT || code == UNORDERED || code == NE
@@ -11108,14 +10798,18 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
          || (! rtx_equal_p (op0, true_cond)
              && ! rtx_equal_p (op1, true_cond))))
     return 0;
+
   /* At this point we know we can use fsel.  */
 
   /* Reduce the comparison to a comparison against zero.  */
-  temp = gen_reg_rtx (compare_mode);
-  emit_insn (gen_rtx_SET (VOIDmode, temp,
-                         gen_rtx_MINUS (compare_mode, op0, op1)));
-  op0 = temp;
-  op1 = CONST0_RTX (compare_mode);
+  if (! is_against_zero)
+    {
+      temp = gen_reg_rtx (compare_mode);
+      emit_insn (gen_rtx_SET (VOIDmode, temp,
+                             gen_rtx_MINUS (compare_mode, op0, op1)));
+      op0 = temp;
+      op1 = CONST0_RTX (compare_mode);
+    }
 
   /* If we don't care about NaNs we can reduce some of the comparisons
      down to faster ones.  */
@@ -11326,17 +11020,17 @@ rs6000_split_multireg_move (rtx dst, rtx src)
       bool used_update = false;
 
       if (MEM_P (src) && INT_REGNO_P (reg))
-        {
-          rtx breg;
+       {
+         rtx breg;
 
          if (GET_CODE (XEXP (src, 0)) == PRE_INC
              || GET_CODE (XEXP (src, 0)) == PRE_DEC)
            {
              rtx delta_rtx;
              breg = XEXP (XEXP (src, 0), 0);
-             delta_rtx =  GET_CODE (XEXP (src, 0)) == PRE_INC
-                 ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
-                 : GEN_INT (-GET_MODE_SIZE (GET_MODE (src)));
+             delta_rtx = (GET_CODE (XEXP (src, 0)) == PRE_INC
+                          ? GEN_INT (GET_MODE_SIZE (GET_MODE (src)))
+                          : GEN_INT (-GET_MODE_SIZE (GET_MODE (src))));
              emit_insn (TARGET_32BIT
                         ? gen_addsi3 (breg, breg, delta_rtx)
                         : gen_adddi3 (breg, breg, delta_rtx));
@@ -11352,21 +11046,17 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              src = newsrc;
            }
 
-         /* We have now address involving an base register only.
-            If we use one of the registers to address memory,
-            we have change that register last.  */
-
-         breg = (GET_CODE (XEXP (src, 0)) == PLUS
-                 ? XEXP (XEXP (src, 0), 0)
-                 : XEXP (src, 0));
-
-         if (!REG_P (breg))
-             abort();
+         breg = XEXP (src, 0);
+         if (GET_CODE (breg) == PLUS || GET_CODE (breg) == LO_SUM)
+           breg = XEXP (breg, 0);
 
-         if (REGNO (breg) >= REGNO (dst)
+         /* If the base register we are using to address memory is
+            also a destination reg, then change that register last.  */
+         if (REG_P (breg)
+             && REGNO (breg) >= REGNO (dst)
              && REGNO (breg) < REGNO (dst) + nregs)
            j = REGNO (breg) - REGNO (dst);
-        }
+       }
 
       if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
        {
@@ -11377,9 +11067,9 @@ rs6000_split_multireg_move (rtx dst, rtx src)
            {
              rtx delta_rtx;
              breg = XEXP (XEXP (dst, 0), 0);
-             delta_rtx = GET_CODE (XEXP (dst, 0)) == PRE_INC
-               ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
-               : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst)));
+             delta_rtx = (GET_CODE (XEXP (dst, 0)) == PRE_INC
+                          ? GEN_INT (GET_MODE_SIZE (GET_MODE (dst)))
+                          : GEN_INT (-GET_MODE_SIZE (GET_MODE (dst))));
 
              /* We have to update the breg before doing the store.
                 Use store with update, if available.  */
@@ -11388,8 +11078,10 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                {
                  rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0);
                  emit_insn (TARGET_32BIT
-                            ? gen_movsi_update (breg, breg, delta_rtx, nsrc)
-                            : gen_movdi_update (breg, breg, delta_rtx, nsrc));
+                            ? (TARGET_POWERPC64
+                               ? gen_movdi_si_update (breg, breg, delta_rtx, nsrc)
+                               : gen_movsi_update (breg, breg, delta_rtx, nsrc))
+                            : gen_movdi_di_update (breg, breg, delta_rtx, nsrc));
                  used_update = true;
                }
              else
@@ -11409,7 +11101,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
          if (j == nregs)
            j = 0;
 
-         /* If compiler already emited move of first word by
+         /* If compiler already emitted move of first word by
             store with update, no need to do anything.  */
          if (j == 0 && used_update)
            continue;
@@ -11526,51 +11218,53 @@ compute_vrsave_mask (void)
 }
 
 /* For a very restricted set of circumstances, we can cut down the
-   size of prologs/epilogs by calling our own save/restore-the-world
-   routines. */
+   size of prologues/epilogues by calling our own save/restore-the-world
+   routines.  */
 
 static void
-compute_save_world_info(rs6000_stack_t *info_ptr)
-{
-  info_ptr->world_save_p =
-    (DEFAULT_ABI == ABI_DARWIN)
-    && ! (current_function_calls_setjmp && flag_exceptions)
-    && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
-    && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
-    && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
-    && info_ptr->cr_save_p;
+compute_save_world_info (rs6000_stack_t *info_ptr)
+{
+  info_ptr->world_save_p = 1;
+  info_ptr->world_save_p
+    = (WORLD_SAVE_P (info_ptr)
+       && DEFAULT_ABI == ABI_DARWIN
+       && ! (current_function_calls_setjmp && flag_exceptions)
+       && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
+       && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
+       && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
+       && info_ptr->cr_save_p);
 
   /* This will not work in conjunction with sibcalls.  Make sure there
      are none.  (This check is expensive, but seldom executed.) */
-  if ( info_ptr->world_save_p )
+  if (WORLD_SAVE_P (info_ptr))
     {
       rtx insn;
       for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
-        if ( GET_CODE (insn) == CALL_INSN
-             && SIBLING_CALL_P (insn))
-          {
-            info_ptr->world_save_p = 0;
-            break;
-          }
+       if ( GET_CODE (insn) == CALL_INSN
+            && SIBLING_CALL_P (insn))
+         {
+           info_ptr->world_save_p = 0;
+           break;
+         }
     }
 
-  if (info_ptr->world_save_p)
+  if (WORLD_SAVE_P (info_ptr))
     {
       /* Even if we're not touching VRsave, make sure there's room on the
         stack for it, if it looks like we're calling SAVE_WORLD, which
-         will attempt to save it. */
+        will attempt to save it. */
       info_ptr->vrsave_size  = 4;
 
       /* "Save" the VRsave register too if we're saving the world.  */
       if (info_ptr->vrsave_mask == 0)
-        info_ptr->vrsave_mask = compute_vrsave_mask ();
+       info_ptr->vrsave_mask = compute_vrsave_mask ();
 
       /* Because the Darwin register save/restore routines only handle
-         F14 .. F31 and V20 .. V31 as per the ABI, perform a consistancy
-         check and abort if there's something worng.  */
+        F14 .. F31 and V20 .. V31 as per the ABI, perform a consistency
+        check and abort if there's something worng.  */
       if (info_ptr->first_fp_reg_save < FIRST_SAVED_FP_REGNO
-          || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO)
-        abort ();
+         || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO)
+       abort ();
     }
   return;
 }
@@ -11652,10 +11346,10 @@ is_altivec_return_reg (rtx reg, void *xyes)
                +---------------------------------------+
                | Save area for VRSAVE register (Z)     | 8+P+A+V+L+X+W+Y
                +---------------------------------------+
-                | SPE: area for 64-bit GP registers     |
-                +---------------------------------------+
-                | SPE alignment padding                 |
-                +---------------------------------------+
+               | SPE: area for 64-bit GP registers     |
+               +---------------------------------------+
+               | SPE alignment padding                 |
+               +---------------------------------------+
                | saved CR (C)                          | 8+P+A+V+L+X+W+Y+Z
                +---------------------------------------+
                | Save area for GP registers (G)        | 8+P+A+V+L+X+W+Y+Z+C
@@ -11689,6 +11383,7 @@ rs6000_stack_info (void)
   rs6000_stack_t *info_ptr = &info;
   int reg_size = TARGET_32BIT ? 4 : 8;
   int ehrd_size;
+  int save_align;
   HOST_WIDE_INT non_fixed_size;
 
   /* Zero all fields portably.  */
@@ -11698,10 +11393,9 @@ rs6000_stack_info (void)
     {
       /* 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 ();
-       }
+       cfun->machine->insn_chain_scanned_p
+         = spe_func_has_64bit_regs_p () + 1;
+      info_ptr->spe_64bit_regs_used = cfun->machine->insn_chain_scanned_p - 1;
     }
 
   /* Select which calling sequence.  */
@@ -11862,24 +11556,24 @@ rs6000_stack_info (void)
       info_ptr->cr_save_offset   = info_ptr->gp_save_offset - info_ptr->cr_size;
 
       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.  */
-        if (info_ptr->spe_gp_size != 0)
-          info_ptr->spe_padding_size
-            = 8 - (-info_ptr->cr_save_offset % 8);
-        else
-          info_ptr->spe_padding_size = 0;
-
-        info_ptr->spe_gp_save_offset
-          = info_ptr->cr_save_offset
-          - info_ptr->spe_padding_size
-          - info_ptr->spe_gp_size;
-
-        /* Adjust for SPE case.  */
-        info_ptr->toc_save_offset
-          = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
-      }
+       {
+         /* Align stack so SPE GPR save area is aligned on a
+            double-word boundary.  */
+         if (info_ptr->spe_gp_size != 0)
+           info_ptr->spe_padding_size
+             = 8 - (-info_ptr->cr_save_offset % 8);
+         else
+           info_ptr->spe_padding_size = 0;
+
+         info_ptr->spe_gp_save_offset
+           = info_ptr->cr_save_offset
+           - info_ptr->spe_padding_size
+           - info_ptr->spe_gp_size;
+
+         /* Adjust for SPE case.  */
+         info_ptr->toc_save_offset
+           = info_ptr->spe_gp_save_offset - info_ptr->toc_size;
+       }
       else if (TARGET_ALTIVEC_ABI)
        {
          info_ptr->vrsave_save_offset
@@ -11908,6 +11602,7 @@ rs6000_stack_info (void)
       break;
     }
 
+  save_align = (TARGET_ALTIVEC_ABI || DEFAULT_ABI == ABI_DARWIN) ? 16 : 8;
   info_ptr->save_size    = RS6000_ALIGN (info_ptr->fp_size
                                         + info_ptr->gp_size
                                         + info_ptr->altivec_size
@@ -11919,8 +11614,7 @@ rs6000_stack_info (void)
                                         + info_ptr->lr_size
                                         + info_ptr->vrsave_size
                                         + info_ptr->toc_size,
-                                        (TARGET_ALTIVEC_ABI || ABI_DARWIN)
-                                        ? 16 : 8);
+                                        save_align);
 
   non_fixed_size        = (info_ptr->vars_size
                            + info_ptr->parm_size
@@ -12010,10 +11704,23 @@ spe_func_has_64bit_regs_p (void)
        {
          rtx i;
 
+         /* FIXME: This should be implemented with attributes...
+
+                (set_attr "spe64" "true")....then,
+                if (get_spe64(insn)) return true;
+
+            It's the only reliable way to do the stuff below.  */
+
          i = PATTERN (insn);
-         if (GET_CODE (i) == SET
-             && SPE_VECTOR_MODE (GET_MODE (SET_SRC (i))))
-           return true;
+         if (GET_CODE (i) == SET)
+           {
+             enum machine_mode mode = GET_MODE (SET_SRC (i));
+
+             if (SPE_VECTOR_MODE (mode))
+               return true;
+             if (TARGET_E500_DOUBLE && mode == DFmode)
+               return true;
+           }
        }
     }
 
@@ -12205,14 +11912,14 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   if (decl)
     {
       if (TARGET_ALTIVEC_VRSAVE)
-        {
+       {
          for (type = TYPE_ARG_TYPES (TREE_TYPE (decl));
               type; type = TREE_CHAIN (type))
            {
              if (TREE_CODE (TREE_VALUE (type)) == VECTOR_TYPE)
                return false;
            }
-        }
+       }
       if (DEFAULT_ABI == ABI_DARWIN
          || (*targetm.binds_local_p) (decl))
        {
@@ -12316,13 +12023,6 @@ rs6000_emit_load_toc_table (int fromprolog)
                   : 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;
@@ -12532,7 +12232,14 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
   rtx insn;
   rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
   rtx tmp_reg = gen_rtx_REG (Pmode, 0);
-  rtx todec = GEN_INT (-size);
+  rtx todec = gen_int_mode (-size, Pmode);
+
+  if (INTVAL (todec) != -size)
+    {
+      warning ("stack frame too large");
+      emit_insn (gen_trap ());
+      return;
+    }
 
   if (current_function_limit_stack)
     {
@@ -12577,7 +12284,7 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
       if (size > 32767)
        {
          /* Need a note here so that try_split doesn't get confused.  */
-         if (get_last_insn() == NULL_RTX)
+         if (get_last_insn () == NULL_RTX)
            emit_note (NOTE_INSN_DELETED);
          insn = emit_move_insn (tmp_reg, todec);
          try_split (PATTERN (insn), insn, 0);
@@ -12587,7 +12294,7 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, int copy_r12)
       insn = emit_insn (TARGET_32BIT
                        ? gen_movsi_update (stack_reg, stack_reg,
                                            todec, stack_reg)
-                       : gen_movdi_update (stack_reg, stack_reg,
+                       : gen_movdi_di_update (stack_reg, stack_reg,
                                            todec, stack_reg));
     }
   else
@@ -12830,12 +12537,13 @@ emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode,
 
   /* Some cases that need register indexed addressing.  */
   if ((TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+      || (TARGET_E500_DOUBLE && mode == DFmode)
       || (TARGET_SPE_ABI
          && SPE_VECTOR_MODE (mode)
          && !SPE_CONST_OFFSET_OK (offset)))
     {
       /* Whomever calls us must make sure r11 is available in the
-         flow path of instructions in the prologue.  */
+        flow path of instructions in the prologue.  */
       offset_rtx = gen_rtx_REG (Pmode, 11);
       emit_move_insn (offset_rtx, int_rtx);
 
@@ -12869,7 +12577,8 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
 
   int_rtx = GEN_INT (offset);
 
-  if (TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
+  if ((TARGET_SPE_ABI && SPE_VECTOR_MODE (mode))
+      || (TARGET_E500_DOUBLE && mode == DFmode))
     {
       offset_rtx = gen_rtx_REG (Pmode, FIXED_SCRATCH);
       emit_move_insn (offset_rtx, int_rtx);
@@ -12950,7 +12659,7 @@ rs6000_emit_prologue (void)
     }
 
   /* Handle world saves specially here.  */
-  if (info->world_save_p)
+  if (WORLD_SAVE_P (info))
     {
       int i, j, sz;
       rtx treg;
@@ -12958,31 +12667,31 @@ rs6000_emit_prologue (void)
 
       /* save_world expects lr in r0. */
       if (info->lr_save_p)
-        {
-          insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
-                                gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
-          RTX_FRAME_RELATED_P (insn) = 1;
-        }
+       {
+         insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+                                gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
 
       /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
-         assumptions about the offsets of various bits of the stack
-         frame.  Abort if things aren't what they should be.  */
+        assumptions about the offsets of various bits of the stack
+        frame.  Abort if things aren't what they should be.  */
       if (info->gp_save_offset != -220
-          || info->fp_save_offset != -144
-          || info->lr_save_offset != 8
-          || info->cr_save_offset != 4
-          || !info->push_p
-          || !info->lr_save_p
-          || (current_function_calls_eh_return && info->ehrd_offset != -432)
-          || (info->vrsave_save_offset != -224
-              || info->altivec_save_offset != (-224 -16 -192)))
-        abort ();
+         || info->fp_save_offset != -144
+         || info->lr_save_offset != 8
+         || info->cr_save_offset != 4
+         || !info->push_p
+         || !info->lr_save_p
+         || (current_function_calls_eh_return && info->ehrd_offset != -432)
+         || (info->vrsave_save_offset != -224
+             || info->altivec_save_offset != (-224 -16 -192)))
+       abort ();
 
       treg = gen_rtx_REG (SImode, 11);
       emit_move_insn (treg, GEN_INT (-info->total_size));
 
       /* SAVE_WORLD takes the caller's LR in R0 and the frame size
-         in R11.  It also clobbers R12, so beware!  */
+        in R11.  It also clobbers R12, so beware!  */
 
       /* Preserve CR2 for save_world prologues */
       sz = 6;
@@ -12992,58 +12701,58 @@ rs6000_emit_prologue (void)
       p = rtvec_alloc (sz);
       j = 0;
       RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
-                                            gen_rtx_REG (Pmode,
-                                                         LINK_REGISTER_REGNUM));
+                                           gen_rtx_REG (Pmode,
+                                                        LINK_REGISTER_REGNUM));
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
-                                        gen_rtx_SYMBOL_REF (Pmode,
-                                                            "*save_world"));
+                                       gen_rtx_SYMBOL_REF (Pmode,
+                                                           "*save_world"));
       /* We do floats first so that the instruction pattern matches
-         properly.  */
-     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-        {
-          rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->fp_save_offset
-                                            + sp_offset + 8 * i));
-          rtx mem = gen_rtx_MEM (DFmode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-        }
+        properly.  */
+      for (i = 0; i < 64 - info->first_fp_reg_save; i++)
+       {
+         rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->fp_save_offset
+                                           + sp_offset + 8 * i));
+         rtx mem = gen_rtx_MEM (DFmode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+       }
       for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
-        {
-          rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->altivec_save_offset
-                                            + sp_offset + 16 * i));
-          rtx mem = gen_rtx_MEM (V4SImode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-        }
+       {
+         rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->altivec_save_offset
+                                           + sp_offset + 16 * i));
+         rtx mem = gen_rtx_MEM (V4SImode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+       }
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-        {
-          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->gp_save_offset
-                                            + sp_offset + reg_size * i));
-          rtx mem = gen_rtx_MEM (reg_mode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-        }
-
-        {
-          /* CR register traditionally saved as CR2.  */
-          rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->cr_save_offset
-                                            + sp_offset));
-          rtx mem = gen_rtx_MEM (reg_mode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
-        }
+       {
+         rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->gp_save_offset
+                                           + sp_offset + reg_size * i));
+         rtx mem = gen_rtx_MEM (reg_mode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+       }
+
+      {
+       /* CR register traditionally saved as CR2.  */
+       rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                GEN_INT (info->cr_save_offset
+                                         + sp_offset));
+       rtx mem = gen_rtx_MEM (reg_mode, addr);
+       set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+       RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+      }
       /* Prevent any attempt to delete the setting of r0 and treg!  */
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, treg);
@@ -13051,26 +12760,26 @@ rs6000_emit_prologue (void)
 
       insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                            NULL_RTX, NULL_RTX);
+                           NULL_RTX, NULL_RTX);
 
       if (current_function_calls_eh_return)
-        {
-          unsigned int i;
-          for (i = 0; ; ++i)
-            {
-              unsigned int regno = EH_RETURN_DATA_REGNO (i);
-              if (regno == INVALID_REGNUM)
-                break;
-              emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
-                               info->ehrd_offset + sp_offset
-                               + reg_size * (int) i,
-                               info->total_size);
-            }
-        }
+       {
+         unsigned int i;
+         for (i = 0; ; ++i)
+           {
+             unsigned int regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+             emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
+                              info->ehrd_offset + sp_offset
+                              + reg_size * (int) i,
+                              info->total_size);
+           }
+       }
     }
 
   /* Save AltiVec registers if needed.  */
-  if (! info->world_save_p && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
     {
       int i;
 
@@ -13111,13 +12820,15 @@ rs6000_emit_prologue (void)
      epilogue.  */
 
   if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && ! info->world_save_p && info->vrsave_mask != 0)
+      && !WORLD_SAVE_P (info) && info->vrsave_mask != 0)
     {
       rtx reg, mem, vrsave;
       int offset;
 
-      /* Get VRSAVE onto a GPR.  */
-      reg = gen_rtx_REG (SImode, 12);
+      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
+        as frame_reg_rtx and r11 as the static chain pointer for
+        nested functions.  */
+      reg = gen_rtx_REG (SImode, 0);
       vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
       if (TARGET_MACHO)
        emit_insn (gen_get_vrsave_internal (reg));
@@ -13139,7 +12850,7 @@ rs6000_emit_prologue (void)
     }
 
   /* If we use the link register, get it into r0.  */
-  if (! info->world_save_p && info->lr_save_p)
+  if (!WORLD_SAVE_P (info) && info->lr_save_p)
     {
       insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
                             gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
@@ -13147,7 +12858,7 @@ rs6000_emit_prologue (void)
     }
 
   /* If we need to save CR, put it into r12.  */
-  if (! info->world_save_p && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
+  if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
     {
       rtx set;
 
@@ -13169,7 +12880,7 @@ rs6000_emit_prologue (void)
 
   /* Do any required saving of fpr's.  If only one or two to save, do
      it ourselves.  Otherwise, call function.  */
-  if (! info->world_save_p && saving_FPRs_inline)
+  if (!WORLD_SAVE_P (info) && saving_FPRs_inline)
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
@@ -13180,7 +12891,7 @@ rs6000_emit_prologue (void)
                           info->fp_save_offset + sp_offset + 8 * i,
                           info->total_size);
     }
-  else if (! info->world_save_p && info->first_fp_reg_save != 64)
+  else if (!WORLD_SAVE_P (info) && info->first_fp_reg_save != 64)
     {
       int i;
       char rname[30];
@@ -13216,7 +12927,7 @@ rs6000_emit_prologue (void)
 
   /* Save GPRs.  This is done as a PARALLEL if we are using
      the store-multiple instructions.  */
-  if (! info->world_save_p && using_store_multiple)
+  if (!WORLD_SAVE_P (info) && using_store_multiple)
     {
       rtvec p;
       int i;
@@ -13238,7 +12949,7 @@ rs6000_emit_prologue (void)
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
-  else if (! info->world_save_p)
+  else if (!WORLD_SAVE_P (info))
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
@@ -13297,7 +13008,7 @@ rs6000_emit_prologue (void)
 
   /* ??? There's no need to emit actual instructions here, but it's the
      easiest way to get the frame unwind information emitted.  */
-  if (! info->world_save_p && current_function_calls_eh_return)
+  if (!WORLD_SAVE_P (info) && current_function_calls_eh_return)
     {
       unsigned int i, regno;
 
@@ -13332,7 +13043,7 @@ rs6000_emit_prologue (void)
     }
 
   /* Save lr if we used it.  */
-  if (! info->world_save_p && info->lr_save_p)
+  if (!WORLD_SAVE_P (info) && info->lr_save_p)
     {
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                               GEN_INT (info->lr_save_offset + sp_offset));
@@ -13347,7 +13058,7 @@ rs6000_emit_prologue (void)
     }
 
   /* Save CR if we use any that must be preserved.  */
-  if (! info->world_save_p && info->cr_save_p)
+  if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                               GEN_INT (info->cr_save_offset + sp_offset));
@@ -13380,7 +13091,7 @@ rs6000_emit_prologue (void)
 
   /* Update stack and set back pointer unless this is V.4,
      for which it was done previously.  */
-  if (! info->world_save_p && info->push_p
+  if (!WORLD_SAVE_P (info) && info->push_p
       && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
     rs6000_emit_allocate_stack (info->total_size, FALSE);
 
@@ -13396,33 +13107,33 @@ rs6000_emit_prologue (void)
   if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
       || (DEFAULT_ABI == ABI_V4 && flag_pic == 1
          && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
-  {
-    /* If emit_load_toc_table will use the link register, we need to save
-       it.  We use R12 for this purpose because emit_load_toc_table
-       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
-                                   && DEFAULT_ABI != ABI_AIX
-                                   && flag_pic
-                                   && ! info->lr_save_p
-                                   && EXIT_BLOCK_PTR->pred != NULL);
-    if (save_LR_around_toc_setup)
-      {
-       rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+    {
+      /* If emit_load_toc_table will use the link register, we need to save
+        it.  We use R12 for this purpose because emit_load_toc_table
+        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
+                                     && DEFAULT_ABI != ABI_AIX
+                                     && flag_pic
+                                     && ! info->lr_save_p
+                                     && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
+      if (save_LR_around_toc_setup)
+       {
+         rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
 
-       insn = emit_move_insn (frame_ptr_rtx, lr);
-       rs6000_maybe_dead (insn);
-       RTX_FRAME_RELATED_P (insn) = 1;
+         insn = emit_move_insn (frame_ptr_rtx, lr);
+         rs6000_maybe_dead (insn);
+         RTX_FRAME_RELATED_P (insn) = 1;
 
-       rs6000_emit_load_toc_table (TRUE);
+         rs6000_emit_load_toc_table (TRUE);
 
-       insn = emit_move_insn (lr, frame_ptr_rtx);
-       rs6000_maybe_dead (insn);
-       RTX_FRAME_RELATED_P (insn) = 1;
-      }
-    else
-      rs6000_emit_load_toc_table (TRUE);
-  }
+         insn = emit_move_insn (lr, frame_ptr_rtx);
+         rs6000_maybe_dead (insn);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+      else
+       rs6000_emit_load_toc_table (TRUE);
+    }
 
 #if TARGET_MACHO
   if (DEFAULT_ABI == ABI_DARWIN
@@ -13549,7 +13260,7 @@ rs6000_emit_epilogue (int sibcall)
                         || rs6000_cpu == PROCESSOR_PPC750
                         || optimize_size);
 
-  if (info->world_save_p)
+  if (WORLD_SAVE_P (info))
     {
       int i, j;
       char rname[30];
@@ -13557,88 +13268,88 @@ rs6000_emit_epilogue (int sibcall)
       rtvec p;
 
       /* eh_rest_world_r10 will return to the location saved in the LR
-         stack slot (which is not likely to be our caller.)
-         Input: R10 -- stack adjustment.  Clobbers R0, R11, R12, R7, R8.
-         rest_world is similar, except any R10 parameter is ignored.
-         The exception-handling stuff that was here in 2.95 is no
-         longer necessary.  */
+        stack slot (which is not likely to be our caller.)
+        Input: R10 -- stack adjustment.  Clobbers R0, R11, R12, R7, R8.
+        rest_world is similar, except any R10 parameter is ignored.
+        The exception-handling stuff that was here in 2.95 is no
+        longer necessary.  */
 
       p = rtvec_alloc (9
                       + 1
                       + 32 - info->first_gp_reg_save
-                       + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
-                       + 63 + 1 - info->first_fp_reg_save);
+                      + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
+                      + 63 + 1 - info->first_fp_reg_save);
 
-      strcpy (rname, (current_function_calls_eh_return) ?
-                        "*eh_rest_world_r10" : "*rest_world");
+      strcpy (rname, ((current_function_calls_eh_return) ?
+                     "*eh_rest_world_r10" : "*rest_world"));
       alloc_rname = ggc_strdup (rname);
 
       j = 0;
       RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
-                                        gen_rtx_REG (Pmode,
-                                                     LINK_REGISTER_REGNUM));
+                                       gen_rtx_REG (Pmode,
+                                                    LINK_REGISTER_REGNUM));
       RTVEC_ELT (p, j++)
-        = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
+       = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
       /* The instruction pattern requires a clobber here;
-         it is shared with the restVEC helper. */
+        it is shared with the restVEC helper. */
       RTVEC_ELT (p, j++)
-        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
 
       {
-        /* CR register traditionally saved as CR2.  */
-        rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
-        rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                 GEN_INT (info->cr_save_offset));
-        rtx mem = gen_rtx_MEM (reg_mode, addr);
-        set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-        RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+       /* CR register traditionally saved as CR2.  */
+       rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                GEN_INT (info->cr_save_offset));
+       rtx mem = gen_rtx_MEM (reg_mode, addr);
+       set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+       RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
       }
 
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-        {
-          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->gp_save_offset
-                                            + reg_size * i));
-          rtx mem = gen_rtx_MEM (reg_mode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
-      }
+       {
+         rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->gp_save_offset
+                                           + reg_size * i));
+         rtx mem = gen_rtx_MEM (reg_mode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+       }
       for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
-        {
-          rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->altivec_save_offset
-                                            + 16 * i));
-          rtx mem = gen_rtx_MEM (V4SImode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
-        }
+       {
+         rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->altivec_save_offset
+                                           + 16 * i));
+         rtx mem = gen_rtx_MEM (V4SImode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+       }
       for (i = 0; info->first_fp_reg_save + i <= 63; i++)
-        {
-          rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
-          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                   GEN_INT (info->fp_save_offset
-                                            + 8 * i));
-          rtx mem = gen_rtx_MEM (DFmode, addr);
-          set_mem_alias_set (mem, rs6000_sr_alias_set);
-
-          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
-        }
+       {
+         rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->fp_save_offset
+                                           + 8 * i));
+         rtx mem = gen_rtx_MEM (DFmode, addr);
+         set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+       }
       RTVEC_ELT (p, j++)
-        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
       RTVEC_ELT (p, j++)
-        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
       RTVEC_ELT (p, j++)
-        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
       RTVEC_ELT (p, j++)
-        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
+       = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
       RTVEC_ELT (p, j++)
-        = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
+       = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
       emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
 
       return;
@@ -13915,7 +13626,7 @@ rs6000_emit_epilogue (int sibcall)
       || current_function_calls_eh_return)
     {
       if (frame_reg_rtx != sp_reg_rtx)
-         rs6000_emit_stack_tie ();
+       rs6000_emit_stack_tie ();
 
       if (use_backchain_to_restore_sp)
        {
@@ -14492,7 +14203,7 @@ rs6000_hash_constant (rtx k)
        else
          {
            size_t i;
-           for (i = 0; i < sizeof(HOST_WIDE_INT)/sizeof(unsigned); i++)
+           for (i = 0; i < sizeof (HOST_WIDE_INT) / sizeof (unsigned); i++)
              result = result * 613 + (unsigned) (XWINT (k, fidx)
                                                  >> CHAR_BIT * i);
          }
@@ -14535,7 +14246,7 @@ toc_hash_eq (const void *h1, const void *h2)
    to whether or not an object is a vtable.  */
 
 #define VTABLE_NAME_P(NAME)                            \
-  (strncmp ("_vt.", name, strlen("_vt.")) == 0         \
+  (strncmp ("_vt.", name, strlen ("_vt.")) == 0                \
   || strncmp ("_ZTV", name, strlen ("_ZTV")) == 0      \
   || strncmp ("_ZTT", name, strlen ("_ZTT")) == 0      \
   || strncmp ("_ZTI", name, strlen ("_ZTI")) == 0      \
@@ -14585,7 +14296,7 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
       void * * found;
 
       /* Create toc_hash_table.  This can't be done at OVERRIDE_OPTIONS
-         time because GGC is not initialized at that point.  */
+        time because GGC is not initialized at that point.  */
       if (toc_hash_table == NULL)
        toc_hash_table = htab_create_ggc (1021, toc_hash_function,
                                          toc_hash_eq, NULL);
@@ -14737,8 +14448,8 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
        }
 #else
        {
-          low = INTVAL (x) & 0xffffffff;
-          high = (HOST_WIDE_INT) INTVAL (x) >> 32;
+         low = INTVAL (x) & 0xffffffff;
+         high = (HOST_WIDE_INT) INTVAL (x) >> 32;
        }
 #endif
 
@@ -14936,7 +14647,7 @@ output_ascii (FILE *file, const char *p, int n)
 
 void
 rs6000_gen_section_name (char **buf, const char *filename,
-                        const char *section_desc)
+                        const char *section_desc)
 {
   const char *q, *after_last_slash, *last_period = 0;
   char *p;
@@ -14960,14 +14671,14 @@ rs6000_gen_section_name (char **buf, const char *filename,
   for (q = after_last_slash; *q; q++)
     {
       if (q == last_period)
-        {
+       {
          strcpy (p, section_desc);
          p += strlen (section_desc);
          break;
-        }
+       }
 
       else if (ISALNUM (*q))
-        *p++ = *q;
+       *p++ = *q;
     }
 
   if (last_period == 0)
@@ -15137,9 +14848,9 @@ rs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
   if (rs6000_sched_groups)
     {
       if (is_microcoded_insn (insn))
-        return 0;
+       return 0;
       else if (is_cracked_insn (insn))
-        return more > 2 ? more - 2 : 0;
+       return more > 2 ? more - 2 : 0;
     }
 
   return more - 1;
@@ -15149,8 +14860,7 @@ rs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
 
 static int
-rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
-                   int cost)
+rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 {
   if (! recog_memoized (insn))
     return 0;
@@ -15162,6 +14872,17 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
     {
       /* Data dependency; DEP_INSN writes a register that INSN reads
         some cycles later.  */
+
+      /* Separate a load from a narrower, dependent store.  */
+      if (rs6000_sched_groups
+         && GET_CODE (PATTERN (insn)) == SET
+         && GET_CODE (PATTERN (dep_insn)) == SET
+         && GET_CODE (XEXP (PATTERN (insn), 1)) == MEM
+         && GET_CODE (XEXP (PATTERN (dep_insn), 0)) == MEM
+         && (GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (insn), 1)))
+             > GET_MODE_SIZE (GET_MODE (XEXP (PATTERN (dep_insn), 0)))))
+       return cost + 14;
+
       switch (get_attr_type (insn))
        {
        case TYPE_JMPREG:
@@ -15223,7 +14944,7 @@ is_microcoded_insn (rtx insn)
          || type == TYPE_LOAD_UX
          || type == TYPE_STORE_UX
          || type == TYPE_MFCR)
-        return true;
+       return true;
     }
 
   return false;
@@ -15288,14 +15009,14 @@ is_cracked_insn (rtx insn)
     {
       enum attr_type type = get_attr_type (insn);
       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
-              || type == TYPE_INSERT_WORD)
-        return true;
+         || 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
+         || type == TYPE_INSERT_WORD)
+       return true;
     }
 
   return false;
@@ -15368,7 +15089,8 @@ rs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
       && rs6000_sched_restricted_insns_priority)
     {
 
-      /* Prioritize insns that can be dispatched only in the first dispatch slot.  */
+      /* Prioritize insns that can be dispatched only in the first
+        dispatch slot.  */
       if (rs6000_sched_restricted_insns_priority == 1)
        /* Attach highest priority to insn. This means that in
           haifa-sched.c:ready_sort(), dispatch-slot restriction considerations
@@ -15376,8 +15098,8 @@ rs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
        return current_sched_info->sched_max_insns_priority;
       else if (rs6000_sched_restricted_insns_priority == 2)
        /* Increase priority of insn by a minimal amount. This means that in
-          haifa-sched.c:ready_sort(), only 'priority' (critical path) considerations
-          precede dispatch-slot restriction considerations.  */
+          haifa-sched.c:ready_sort(), only 'priority' (critical path)
+          considerations precede dispatch-slot restriction considerations.  */
        return (priority + 1);
     }
 
@@ -15532,7 +15254,8 @@ is_store_insn (rtx insn)
    costly by the given target.  */
 
 static bool
-rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distance)
+rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
+                            int distance)
 {
   /* If the flag is not enbled - no dependence is considered costly;
      allow all dependent insns in the same group.
@@ -15556,7 +15279,8 @@ rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost, int distanc
       && is_load_insn (next)
       && is_store_insn (insn)
       && (!link || (int) REG_NOTE_KIND (link) == 0))
-     /* Prevent load after store in the same group if it is a true dependence.  */
+     /* Prevent load after store in the same group if it is a true
+       dependence.  */
      return true;
 
   /* The flag is set to X; dependences with latency >= X are considered costly,
@@ -15584,7 +15308,7 @@ get_next_active_insn (rtx insn, rtx tail)
 
   while (next_insn
         && next_insn != tail
-        && (GET_CODE(next_insn) == NOTE
+        && (GET_CODE (next_insn) == NOTE
             || GET_CODE (PATTERN (next_insn)) == USE
             || GET_CODE (PATTERN (next_insn)) == CLOBBER))
     {
@@ -15626,13 +15350,13 @@ insn_terminates_group_p (rtx insn, enum group_termination which_group)
   if (which_group == current_group)
     {
       if (is_branch_slot_insn (insn))
-        return true;
+       return true;
       return false;
     }
   else if (which_group == previous_group)
     {
       if (is_dispatch_slot_restricted (insn))
-        return true;
+       return true;
       return false;
     }
 
@@ -15654,17 +15378,17 @@ is_costly_group (rtx *group_insns, rtx next_insn)
     {
       rtx insn = group_insns[i];
       if (!insn)
-        continue;
+       continue;
       for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
-        {
-          rtx next = XEXP (link, 0);
-          if (next == next_insn)
-            {
-              cost = insn_cost (insn, link, next_insn);
-              if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
-                return true;
-            }
-        }
+       {
+         rtx next = XEXP (link, 0);
+         if (next == next_insn)
+           {
+             cost = insn_cost (insn, link, next_insn);
+             if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
+               return true;
+           }
+       }
     }
 
   return false;
@@ -15684,8 +15408,9 @@ is_costly_group (rtx *group_insns, rtx next_insn)
    last group, and how many dispatch groups were encountered so far).  */
 
 static int
-force_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
-                bool *group_end, int can_issue_more, int *group_count)
+force_new_group (int sched_verbose, FILE *dump, rtx *group_insns,
+                rtx next_insn, bool *group_end, int can_issue_more,
+                int *group_count)
 {
   rtx nop;
   bool force;
@@ -15705,27 +15430,27 @@ force_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
 
   if (sched_verbose > 6)
     fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
-                       *group_count ,can_issue_more);
+            *group_count ,can_issue_more);
 
   if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
     {
       if (*group_end)
-        can_issue_more = 0;
+       can_issue_more = 0;
 
       /* Since only a branch can be issued in the last issue_slot, it is
         sufficient to insert 'can_issue_more - 1' nops if next_insn is not
         a branch. If next_insn is a branch, we insert 'can_issue_more' nops;
-        in this case the last nop will start a new group and the branch will be
-        forced to the new group.  */
+        in this case the last nop will start a new group and the branch
+        will be forced to the new group.  */
       if (can_issue_more && !is_branch_slot_insn (next_insn))
-        can_issue_more--;
+       can_issue_more--;
 
       while (can_issue_more > 0)
-        {
-          nop = gen_nop();
-          emit_insn_before (nop, next_insn);
-          can_issue_more--;
-        }
+       {
+         nop = gen_nop ();
+         emit_insn_before (nop, next_insn);
+         can_issue_more--;
+       }
 
       *group_end = true;
       return 0;
@@ -15736,56 +15461,57 @@ force_new_group (int sched_verbose, FILE *dump, rtx *group_insns, rtx next_insn,
       int n_nops = rs6000_sched_insert_nops;
 
       /* Nops can't be issued from the branch slot, so the effective
-         issue_rate for nops is 'issue_rate - 1'.  */
+        issue_rate for nops is 'issue_rate - 1'.  */
       if (can_issue_more == 0)
-        can_issue_more = issue_rate;
+       can_issue_more = issue_rate;
       can_issue_more--;
       if (can_issue_more == 0)
-        {
-          can_issue_more = issue_rate - 1;
-          (*group_count)++;
-          end = true;
-          for (i = 0; i < issue_rate; i++)
-            {
-              group_insns[i] = 0;
-            }
-        }
+       {
+         can_issue_more = issue_rate - 1;
+         (*group_count)++;
+         end = true;
+         for (i = 0; i < issue_rate; i++)
+           {
+             group_insns[i] = 0;
+           }
+       }
 
       while (n_nops > 0)
-        {
-          nop = gen_nop ();
-          emit_insn_before (nop, next_insn);
-          if (can_issue_more == issue_rate - 1) /* new group begins */
-            end = false;
-          can_issue_more--;
-          if (can_issue_more == 0)
-            {
-              can_issue_more = issue_rate - 1;
-              (*group_count)++;
-              end = true;
-              for (i = 0; i < issue_rate; i++)
-                {
-                  group_insns[i] = 0;
-                }
-            }
-          n_nops--;
-        }
+       {
+         nop = gen_nop ();
+         emit_insn_before (nop, next_insn);
+         if (can_issue_more == issue_rate - 1) /* new group begins */
+           end = false;
+         can_issue_more--;
+         if (can_issue_more == 0)
+           {
+             can_issue_more = issue_rate - 1;
+             (*group_count)++;
+             end = true;
+             for (i = 0; i < issue_rate; i++)
+               {
+                 group_insns[i] = 0;
+               }
+           }
+         n_nops--;
+       }
 
       /* Scale back relative to 'issue_rate' (instead of 'issue_rate - 1').  */
       can_issue_more++;
 
-      *group_end = /* Is next_insn going to start a new group?  */
-         (end
+      /* Is next_insn going to start a new group?  */
+      *group_end
+       = (end
           || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
           || (can_issue_more <= 2 && is_cracked_insn (next_insn))
           || (can_issue_more < issue_rate &&
-             insn_terminates_group_p (next_insn, previous_group)));
+              insn_terminates_group_p (next_insn, previous_group)));
       if (*group_end && end)
-        (*group_count)--;
+       (*group_count)--;
 
       if (sched_verbose > 6)
-        fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
-                       *group_count, can_issue_more);
+       fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
+                *group_count, can_issue_more);
       return can_issue_more;
     }
 
@@ -15848,43 +15574,45 @@ redefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
       slot = (issue_rate - can_issue_more);
       group_insns[slot] = insn;
       can_issue_more =
-        rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
+       rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
       if (insn_terminates_group_p (insn, current_group))
-        can_issue_more = 0;
+       can_issue_more = 0;
 
       next_insn = get_next_active_insn (insn, tail);
       if (next_insn == NULL_RTX)
-        return group_count + 1;
+       return group_count + 1;
 
-      group_end = /* Is next_insn going to start a new group?  */
-        (can_issue_more == 0
-         || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
-         || (can_issue_more <= 2 && is_cracked_insn (next_insn))
-         || (can_issue_more < issue_rate &&
-             insn_terminates_group_p (next_insn, previous_group)));
+      /* Is next_insn going to start a new group?  */
+      group_end
+       = (can_issue_more == 0
+          || (can_issue_more == 1 && !is_branch_slot_insn (next_insn))
+          || (can_issue_more <= 2 && is_cracked_insn (next_insn))
+          || (can_issue_more < issue_rate &&
+              insn_terminates_group_p (next_insn, previous_group)));
 
       can_issue_more = force_new_group (sched_verbose, dump, group_insns,
-                       next_insn, &group_end, can_issue_more, &group_count);
+                                       next_insn, &group_end, can_issue_more,
+                                       &group_count);
 
       if (group_end)
-        {
-          group_count++;
-          can_issue_more = 0;
-          for (i = 0; i < issue_rate; i++)
-            {
-              group_insns[i] = 0;
-            }
-        }
+       {
+         group_count++;
+         can_issue_more = 0;
+         for (i = 0; i < issue_rate; i++)
+           {
+             group_insns[i] = 0;
+           }
+       }
 
       if (GET_MODE (next_insn) == TImode && can_issue_more)
-        PUT_MODE(next_insn, VOIDmode);
+       PUT_MODE (next_insn, VOIDmode);
       else if (!can_issue_more && GET_MODE (next_insn) != TImode)
-        PUT_MODE (next_insn, TImode);
+       PUT_MODE (next_insn, TImode);
 
       insn = next_insn;
       if (can_issue_more == 0)
-        can_issue_more = issue_rate;
-   } /* while */
+       can_issue_more = issue_rate;
+    } /* while */
 
   return group_count;
 }
@@ -15920,33 +15648,33 @@ pad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
       group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
 
       if (next_insn == NULL_RTX)
-        break;
+       break;
 
       if (group_end)
-        {
-          /* If the scheduler had marked group termination at this location
-             (between insn and next_indn), and neither insn nor next_insn will
-             force group termination, pad the group with nops to force group
-             termination.  */
-          if (can_issue_more
-              && (rs6000_sched_insert_nops == sched_finish_pad_groups)
-              && !insn_terminates_group_p (insn, current_group)
-              && !insn_terminates_group_p (next_insn, previous_group))
-            {
-              if (!is_branch_slot_insn(next_insn))
-                can_issue_more--;
-
-              while (can_issue_more)
-                {
-                  nop = gen_nop ();
-                  emit_insn_before (nop, next_insn);
-                  can_issue_more--;
-                }
-            }
-
-          can_issue_more = issue_rate;
-          group_count++;
-        }
+       {
+         /* If the scheduler had marked group termination at this location
+            (between insn and next_indn), and neither insn nor next_insn will
+            force group termination, pad the group with nops to force group
+            termination.  */
+         if (can_issue_more
+             && (rs6000_sched_insert_nops == sched_finish_pad_groups)
+             && !insn_terminates_group_p (insn, current_group)
+             && !insn_terminates_group_p (next_insn, previous_group))
+           {
+             if (!is_branch_slot_insn (next_insn))
+               can_issue_more--;
+
+             while (can_issue_more)
+               {
+                 nop = gen_nop ();
+                 emit_insn_before (nop, next_insn);
+                 can_issue_more--;
+               }
+           }
+
+         can_issue_more = issue_rate;
+         group_count++;
+       }
 
       insn = next_insn;
       next_insn = get_next_active_insn (insn, tail);
@@ -15969,16 +15697,16 @@ rs6000_sched_finish (FILE *dump, int sched_verbose)
   if (reload_completed && rs6000_sched_groups)
     {
       if (rs6000_sched_insert_nops == sched_finish_none)
-        return;
+       return;
 
       if (rs6000_sched_insert_nops == sched_finish_pad_groups)
-        n_groups = pad_groups (dump, sched_verbose,
-                               current_sched_info->prev_head,
-                               current_sched_info->next_tail);
+       n_groups = pad_groups (dump, sched_verbose,
+                              current_sched_info->prev_head,
+                              current_sched_info->next_tail);
       else
-        n_groups = redefine_groups (dump, sched_verbose,
-                               current_sched_info->prev_head,
-                               current_sched_info->next_tail);
+       n_groups = redefine_groups (dump, sched_verbose,
+                                   current_sched_info->prev_head,
+                                   current_sched_info->next_tail);
 
       if (sched_verbose >= 6)
        {
@@ -16072,6 +15800,9 @@ const struct attribute_spec rs6000_attribute_table[] =
   { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
   { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
   { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+  SUBTARGET_ATTRIBUTE_TABLE,
+#endif
   { NULL,        0, 0, false, false, false, NULL }
 };
 
@@ -16086,7 +15817,9 @@ const struct attribute_spec rs6000_attribute_table[] =
   given declaration.  */
 
 static tree
-rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
+rs6000_handle_altivec_attribute (tree *node,
+                                tree name ATTRIBUTE_UNUSED,
+                                tree args,
                                 int flags ATTRIBUTE_UNUSED,
                                 bool *no_add_attrs)
 {
@@ -16107,9 +15840,25 @@ rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
 
   mode = TYPE_MODE (type);
 
-  if (rs6000_warn_altivec_long
-      && (type == long_unsigned_type_node || type == long_integer_type_node))
-    warning ("use of 'long' in AltiVec types is deprecated; use 'int'");
+  /* Check for invalid AltiVec type qualifiers.  */
+  if (type == long_unsigned_type_node || type == long_integer_type_node)
+    {
+    if (TARGET_64BIT)
+      error ("use of %<long%> in AltiVec types is invalid for 64-bit code");
+    else if (rs6000_warn_altivec_long)
+      warning ("use of %<long%> in AltiVec types is deprecated; use %<int%>");
+    }
+  else if (type == long_long_unsigned_type_node
+           || type == long_long_integer_type_node)
+    error ("use of %<long long%> in AltiVec types is invalid");
+  else if (type == double_type_node)
+    error ("use of %<double%> in AltiVec types is invalid");
+  else if (type == long_double_type_node)
+    error ("use of %<long double%> in AltiVec types is invalid");
+  else if (type == boolean_type_node)
+    error ("use of boolean types in AltiVec types is invalid");
+  else if (TREE_CODE (type) == COMPLEX_TYPE)
+    error ("use of %<complex%> in AltiVec types is invalid");
 
   switch (altivec_type)
     {
@@ -16117,37 +15866,38 @@ rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
       unsigned_p = TYPE_UNSIGNED (type);
       switch (mode)
        {
-         case SImode:
-           result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
-           break;
-         case HImode:
-           result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
-           break;
-         case QImode:
-           result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
-           break;
-         case SFmode: result = V4SF_type_node; break;
-           /* If the user says 'vector int bool', we may be handed the 'bool'
-              attribute _before_ the 'vector' attribute, and so select the proper
-              type in the 'b' case below.  */
-         case V4SImode: case V8HImode: case V16QImode: result = type;
-         default: break;
+       case SImode:
+         result = (unsigned_p ? unsigned_V4SI_type_node : V4SI_type_node);
+         break;
+       case HImode:
+         result = (unsigned_p ? unsigned_V8HI_type_node : V8HI_type_node);
+         break;
+       case QImode:
+         result = (unsigned_p ? unsigned_V16QI_type_node : V16QI_type_node);
+         break;
+       case SFmode: result = V4SF_type_node; break;
+         /* If the user says 'vector int bool', we may be handed the 'bool'
+            attribute _before_ the 'vector' attribute, and so select the
+            proper type in the 'b' case below.  */
+       case V4SImode: case V8HImode: case V16QImode: case V4SFmode:
+         result = type;
+       default: break;
        }
       break;
     case 'b':
       switch (mode)
        {
-         case SImode: case V4SImode: result = bool_V4SI_type_node; break;
-         case HImode: case V8HImode: result = bool_V8HI_type_node; break;
-         case QImode: case V16QImode: result = bool_V16QI_type_node;
-         default: break;
+       case SImode: case V4SImode: result = bool_V4SI_type_node; break;
+       case HImode: case V8HImode: result = bool_V8HI_type_node; break;
+       case QImode: case V16QImode: result = bool_V16QI_type_node;
+       default: break;
        }
       break;
     case 'p':
       switch (mode)
        {
-         case V8HImode: result = pixel_V8HI_type_node;
-         default: break;
+       case V8HImode: result = pixel_V8HI_type_node;
+       default: break;
        }
     default: break;
     }
@@ -16157,9 +15907,7 @@ rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
 
   *no_add_attrs = true;  /* No need to hang on to the attribute.  */
 
-  if (!result)
-    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-  else
+  if (result)
     *node = reconstruct_complex_type (*node, result);
 
   return NULL_TREE;
@@ -16193,7 +15941,7 @@ rs6000_handle_longcall_attribute (tree *node, tree name,
       && TREE_CODE (*node) != FIELD_DECL
       && TREE_CODE (*node) != TYPE_DECL)
     {
-      warning ("`%s' attribute only applies to functions",
+      warning ("%qs attribute only applies to functions",
               IDENTIFIER_POINTER (name));
       *no_add_attrs = true;
     }
@@ -16217,7 +15965,7 @@ rs6000_set_default_type_attributes (tree type)
 /* Return a reference suitable for calling a function with the
    longcall attribute.  */
 
-struct rtx_def *
+rtx
 rs6000_longcall_ref (rtx call_ref)
 {
   const char *call_name;
@@ -16328,6 +16076,14 @@ rs6000_elf_in_small_data_p (tree decl)
   if (rs6000_sdata == SDATA_NONE)
     return false;
 
+  /* We want to merge strings, so we never consider them small data.  */
+  if (TREE_CODE (decl) == STRING_CST)
+    return false;
+
+  /* Functions are never in the small data area.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    return false;
+
   if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
     {
       const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
@@ -16364,7 +16120,7 @@ rs6000_elf_in_small_data_p (tree decl)
    register by this routine since our caller will try to
    increment the returned register via an "la" instruction.  */
 
-struct rtx_def *
+rtx
 find_addr_reg (rtx addr)
 {
   while (GET_CODE (addr) == PLUS)
@@ -16395,39 +16151,14 @@ rs6000_fatal_bad_address (rtx op)
 
 #if TARGET_MACHO
 
-#if 0
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
-   reference and a constant.  */
-
-int
-symbolic_operand (rtx op)
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-    case CONST:
-      op = XEXP (op, 0);
-      return (GET_CODE (op) == SYMBOL_REF ||
-             (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
-             && GET_CODE (XEXP (op, 1)) == CONST_INT);
-    default:
-      return 0;
-    }
-}
-#endif
-
-#if TARGET_MACHO
-
 static tree branch_island_list = 0;
 
 /* Remember to generate a branch island for far calls to the given
    function.  */
 
 static void
-add_compiler_branch_island (tree label_name, tree function_name, int line_number)
+add_compiler_branch_island (tree label_name, tree function_name,
+                           int line_number)
 {
   tree branch_island = build_tree_list (function_name, label_name);
   TREE_TYPE (branch_island) = build_int_cst (NULL_TREE, line_number);
@@ -16473,8 +16204,7 @@ macho_branch_islands (void)
       strcat (tmp_buf, label);
 #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
       if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
-       fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
-                BRANCH_ISLAND_LINE_NUMBER(branch_island));
+       dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
 #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
       if (flag_pic)
        {
@@ -16511,8 +16241,7 @@ macho_branch_islands (void)
       output_asm_insn (tmp_buf, 0);
 #if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
       if (write_symbols == DBX_DEBUG || write_symbols == XCOFF_DEBUG)
-       fprintf(asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
-               BRANCH_ISLAND_LINE_NUMBER (branch_island));
+       dbxout_stabd (N_SLINE, BRANCH_ISLAND_LINE_NUMBER (branch_island));
 #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
     }
 
@@ -16555,7 +16284,8 @@ get_prev_label (tree function_name)
    CALL_DEST is the routine we are calling.  */
 
 char *
-output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
+output_call (rtx insn, rtx *operands, int dest_operand_number,
+            int cookie_operand_number)
 {
   static char buf[256];
   if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
@@ -16594,8 +16324,6 @@ output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operan
   return buf;
 }
 
-#endif /* TARGET_MACHO */
-
 /* Generate PIC and indirect symbol stubs.  */
 
 void
@@ -16630,7 +16358,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
 
       label++;
-      local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
+      local_label_0 = alloca (sizeof ("\"L0000000000$spb\""));
       sprintf (local_label_0, "\"L%011d$spb\"", label);
 
       fprintf (file, "\tmflr r0\n");
@@ -16639,7 +16367,8 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\taddis r11,r11,ha16(%s-%s)\n",
               lazy_ptr_name, local_label_0);
       fprintf (file, "\tmtlr r0\n");
-      fprintf (file, "\tlwzu r12,lo16(%s-%s)(r11)\n",
+      fprintf (file, "\t%s r12,lo16(%s-%s)(r11)\n",
+              (TARGET_64BIT ? "ldu" : "lwzu"),
               lazy_ptr_name, local_label_0);
       fprintf (file, "\tmtctr r12\n");
       fprintf (file, "\tbctr\n");
@@ -16652,7 +16381,9 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
 
       fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
-      fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
+      fprintf (file, "\t%s r12,lo16(%s)(r11)\n",
+              (TARGET_64BIT ? "ldu" : "lwzu"),
+              lazy_ptr_name);
       fprintf (file, "\tmtctr r12\n");
       fprintf (file, "\tbctr\n");
     }
@@ -16669,7 +16400,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
    position-independent addresses go into a reg.  This is REG if non
    zero, otherwise we allocate register(s) as necessary.  */
 
-#define SMALL_INT(X) ((unsigned) (INTVAL(X) + 0x8000) < 0x10000)
+#define SMALL_INT(X) ((unsigned) (INTVAL (X) + 0x8000) < 0x10000)
 
 rtx
 rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
@@ -16731,6 +16462,58 @@ toc_section (void)
 {
 }
 
+/* Output a .machine directive for the Darwin assembler, and call
+   the generic start_file routine.  */
+
+static void
+rs6000_darwin_file_start (void)
+{
+  static const struct
+  {
+    const char *arg;
+    const char *name;
+    int if_set;
+  } mapping[] = {
+    { "ppc64", "ppc64", MASK_64BIT },
+    { "970", "ppc970", MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64 },
+    { "power4", "ppc970", 0 },
+    { "G5", "ppc970", 0 },
+    { "7450", "ppc7450", 0 },
+    { "7400", "ppc7400", MASK_ALTIVEC },
+    { "G4", "ppc7400", 0 },
+    { "750", "ppc750", 0 },
+    { "740", "ppc750", 0 },
+    { "G3", "ppc750", 0 },
+    { "604e", "ppc604e", 0 },
+    { "604", "ppc604", 0 },
+    { "603e", "ppc603", 0 },
+    { "603", "ppc603", 0 },
+    { "601", "ppc601", 0 },
+    { NULL, "ppc", 0 } };
+  const char *cpu_id = "";
+  size_t i;
+
+  rs6000_file_start ();
+
+  /* Determine the argument to -mcpu=.  Default to G3 if not specified.  */
+  for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
+    if (rs6000_select[i].set_arch_p && rs6000_select[i].string
+       && rs6000_select[i].string[0] != '\0')
+      cpu_id = rs6000_select[i].string;
+
+  /* Look through the mapping array.  Pick the first name that either
+     matches the argument, has a bit set in IF_SET that is also set
+     in the target flags, or has a NULL name.  */
+
+  i = 0;
+  while (mapping[i].arg != NULL
+        && strcmp (mapping[i].arg, cpu_id) != 0
+        && (mapping[i].if_set & target_flags) == 0)
+    i++;
+
+  fprintf (asm_out_file, "\t.machine %s\n", mapping[i].name);
+}
+
 #endif /* TARGET_MACHO */
 
 #if TARGET_ELF
@@ -16757,10 +16540,10 @@ rs6000_elf_asm_out_constructor (rtx symbol, int priority)
   if (priority != DEFAULT_INIT_PRIORITY)
     {
       sprintf (buf, ".ctors.%.5u",
-               /* Invert the numbering so the linker puts us in the proper
-                  order; constructors are run from right to left, and the
-                  linker sorts in increasing order.  */
-               MAX_INIT_PRIORITY - priority);
+              /* Invert the numbering so the linker puts us in the proper
+                 order; constructors are run from right to left, and the
+                 linker sorts in increasing order.  */
+              MAX_INIT_PRIORITY - priority);
       section = buf;
     }
 
@@ -16786,10 +16569,10 @@ rs6000_elf_asm_out_destructor (rtx symbol, int priority)
   if (priority != DEFAULT_INIT_PRIORITY)
     {
       sprintf (buf, ".dtors.%.5u",
-               /* Invert the numbering so the linker puts us in the proper
-                  order; constructors are run from right to left, and the
-                  linker sorts in increasing order.  */
-               MAX_INIT_PRIORITY - priority);
+              /* Invert the numbering so the linker puts us in the proper
+                 order; constructors are run from right to left, and the
+                 linker sorts in increasing order.  */
+              MAX_INIT_PRIORITY - priority);
       section = buf;
     }
 
@@ -16892,7 +16675,8 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
 }
 
 static void
-rs6000_xcoff_asm_named_section (const char *name, unsigned int flags)
+rs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
+                               tree decl ATTRIBUTE_UNUSED)
 {
   int smclass;
   static const char * const suffix[3] = { "PR", "RO", "RW" };
@@ -16911,21 +16695,21 @@ rs6000_xcoff_asm_named_section (const char *name, unsigned int flags)
 
 static void
 rs6000_xcoff_select_section (tree decl, int reloc,
-                           unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+                            unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   if (decl_readonly_section_1 (decl, reloc, 1))
     {
       if (TREE_PUBLIC (decl))
-        read_only_data_section ();
+       read_only_data_section ();
       else
-        read_only_private_data_section ();
+       read_only_private_data_section ();
     }
   else
     {
       if (TREE_PUBLIC (decl))
-        data_section ();
+       data_section ();
       else
-        private_data_section ();
+       private_data_section ();
     }
 }
 
@@ -16956,7 +16740,7 @@ rs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
 
 static void
 rs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
-                               unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
+                                unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
     toc_section ();
@@ -17024,7 +16808,6 @@ rs6000_xcoff_file_start (void)
   fputs ("\t.file\t", asm_out_file);
   output_quoted_string (asm_out_file, main_input_filename);
   fputc ('\n', asm_out_file);
-  toc_section ();
   if (write_symbols != NO_DEBUG)
     private_data_section ();
   text_section ();
@@ -17064,8 +16847,7 @@ rs6000_binds_local_p (tree decl)
    scanned.  In either case, *TOTAL contains the cost result.  */
 
 static bool
-rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
-                 int *total)
+rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
   enum machine_mode mode = GET_MODE (x);
 
@@ -17078,16 +16860,15 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
            || outer_code == MINUS)
           && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
               || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
-         || ((outer_code == IOR || outer_code == XOR)
-             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
-         || ((outer_code == DIV || outer_code == UDIV
-              || outer_code == MOD || outer_code == UMOD)
-             && exact_log2 (INTVAL (x)) >= 0)
          || (outer_code == AND
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
+                                            mode == SImode ? 'L' : 'J'))
                  || mask_operand (x, VOIDmode)))
+         || ((outer_code == IOR || outer_code == XOR)
+             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
+                                            mode == SImode ? 'L' : 'J'))))
          || outer_code == ASHIFT
          || outer_code == ASHIFTRT
          || outer_code == LSHIFTRT
@@ -17096,9 +16877,21 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
          || outer_code == ZERO_EXTRACT
          || (outer_code == MULT
              && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+         || ((outer_code == DIV || outer_code == UDIV
+              || outer_code == MOD || outer_code == UMOD)
+             && exact_log2 (INTVAL (x)) >= 0)
          || (outer_code == COMPARE
              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
-                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))))
+                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')))
+         || (outer_code == EQ
+             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
+                                            mode == SImode ? 'L' : 'J'))))
+         || (outer_code == GTU
+             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+         || (outer_code == LTU
+             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'P')))
        {
          *total = 0;
          return true;
@@ -17149,7 +16942,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
     case MEM:
       /* When optimizing for size, MEM should be slightly more expensive
         than generating address, e.g., (plus (reg) (const)).
-        L1 cache latecy is about two instructions.  */
+        L1 cache latency is about two instructions.  */
       *total = optimize_size ? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (2);
       return true;
 
@@ -17218,11 +17011,12 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
          *total += COSTS_N_INSNS (1);
        }
       else
-        *total = COSTS_N_INSNS (1);
+       *total = COSTS_N_INSNS (1);
       return false;
 
     case MULT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I'))
        {
          if (INTVAL (XEXP (x, 1)) >= -256
              && INTVAL (XEXP (x, 1)) <= 255)
@@ -17266,7 +17060,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
            /* Shift */
            *total = COSTS_N_INSNS (1);
        }
-      else 
+      else
        {
          if (GET_MODE (XEXP (x, 1)) == DImode)
            *total = rs6000_cost->divdi;
@@ -17370,7 +17164,48 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
          *total = rs6000_cost->fp;
          return false;
        }
+      break;
+
+    case EQ:
+    case GTU:
+    case LTU:
+      /* Carry bit requires mode == Pmode.
+        NEG or PLUS already counted so only add one.  */
+      if (mode == Pmode
+         && (outer_code == NEG || outer_code == PLUS))
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+      if (outer_code == SET)
+       {
+         if (XEXP (x, 1) == const0_rtx)
+           {
+             *total = COSTS_N_INSNS (2);
+             return true;
+           }
+         else if (mode == Pmode)
+           {
+             *total = COSTS_N_INSNS (3);
+             return false;
+           }
+       }
+      /* FALLTHRU */
 
+    case GT:
+    case LT:
+    case UNORDERED:
+      if (outer_code == SET && (XEXP (x, 1) == const0_rtx))
+       {
+         *total = COSTS_N_INSNS (2);
+         return true;
+       }
+      /* CC COMPARE.  */
+      if (outer_code == COMPARE)
+       {
+         *total = 0;
+         return true;
+       }
       break;
 
     default:
@@ -17398,20 +17233,21 @@ rs6000_register_move_cost (enum machine_mode mode,
        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....  */
+      /* 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.  */
+       /* 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.  */
+  /* 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.  */
+  /* 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));
@@ -17481,6 +17317,26 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
   enum machine_mode mode;
   unsigned int regno;
 
+  /* Special handling for structs in darwin64.  */
+  if (rs6000_darwin64_abi
+      && TYPE_MODE (valtype) == BLKmode
+      && TREE_CODE (valtype) == RECORD_TYPE
+      && int_size_in_bytes (valtype) > 0)
+    {
+      CUMULATIVE_ARGS valcum;
+      rtx valret;
+
+      valcum.words = 0;
+      valcum.fregno = FP_ARG_MIN_REG;
+      valcum.vregno = ALTIVEC_ARG_MIN_REG;
+      /* Do a trial code generation as if this were going to be passed as
+        an argument; if any part goes in memory, we return NULL.  */
+      valret = rs6000_darwin64_record_arg (&valcum, valtype, 1, true);
+      if (valret)
+       return valret;
+      /* Otherwise fall through to standard ABI rules.  */
+    }
+
   if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == DImode)
     {
       /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
@@ -17509,8 +17365,11 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
     return rs6000_complex_function_value (mode);
   else if (TREE_CODE (valtype) == VECTOR_TYPE
           && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
-          && ALTIVEC_VECTOR_MODE(mode))
+          && ALTIVEC_VECTOR_MODE (mode))
     regno = ALTIVEC_ARG_RETURN;
+  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
+          && (mode == DFmode || mode == DCmode))
+    return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
 
@@ -17524,6 +17383,20 @@ rs6000_libcall_value (enum machine_mode mode)
 {
   unsigned int regno;
 
+  if (TARGET_32BIT && TARGET_POWERPC64 && mode == DImode)
+    {
+      /* Long long return value need be split in -mpowerpc64, 32bit ABI.  */
+      return gen_rtx_PARALLEL (DImode,
+       gen_rtvec (2,
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode, GP_ARG_RETURN),
+                                     const0_rtx),
+                  gen_rtx_EXPR_LIST (VOIDmode,
+                                     gen_rtx_REG (SImode,
+                                                  GP_ARG_RETURN + 1),
+                                     GEN_INT (4))));
+    }
+
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
           && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
@@ -17532,6 +17405,9 @@ rs6000_libcall_value (enum machine_mode mode)
     regno = ALTIVEC_ARG_RETURN;
   else if (COMPLEX_MODE_P (mode) && targetm.calls.split_complex_arg)
     return rs6000_complex_function_value (mode);
+  else if (TARGET_E500_DOUBLE && TARGET_HARD_FLOAT
+          && (mode == DFmode || mode == DCmode))
+    return spe_build_register_parallel (mode, GP_ARG_RETURN);
   else
     regno = GP_ARG_RETURN;
 
@@ -17576,7 +17452,11 @@ rs6000_dwarf_register_span (rtx reg)
 {
   unsigned regno;
 
-  if (!TARGET_SPE || !SPE_VECTOR_MODE (GET_MODE (reg)))
+  if (TARGET_SPE
+      && (SPE_VECTOR_MODE (GET_MODE (reg))
+         || (TARGET_E500_DOUBLE && GET_MODE (reg) == DFmode)))
+    ;
+  else
     return NULL_RTX;
 
   regno = REGNO (reg);
@@ -17652,4 +17532,18 @@ rs6000_vector_mode_supported_p (enum machine_mode mode)
     return false;
 }
 
+/* Target hook for invalid_arg_for_unprototyped_fn. */ 
+static const char * 
+invalid_arg_for_unprototyped_fn (tree typelist, tree funcdecl, tree val)
+{
+  return (!rs6000_darwin64_abi
+         && typelist == 0
+          && TREE_CODE (TREE_TYPE (val)) == VECTOR_TYPE
+          && (funcdecl == NULL_TREE
+              || (TREE_CODE (funcdecl) == FUNCTION_DECL
+                  && DECL_BUILT_IN_CLASS (funcdecl) != BUILT_IN_MD)))
+         ? N_("AltiVec argument passed to unprototyped function")
+         : NULL;
+}
+
 #include "gt-rs6000.h"