rs6000.c (rs6000_emit_move): #if 0 splitting slow, unaligned loads and stores while...
[platform/upstream/gcc.git] / gcc / config / rs6000 / rs6000.c
index ae702fc..4969cd1 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 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
    This file is part of GCC.
@@ -51,6 +51,7 @@
 #include "langhooks.h"
 #include "reload.h"
 #include "cfglayout.h"
+#include "sched-int.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
 #define min(A,B)       ((A) < (B) ? (A) : (B))
 #define max(A,B)       ((A) > (B) ? (A) : (B))
 
+/* Structure used to define the rs6000 stack */
+typedef struct rs6000_stack {
+  int first_gp_reg_save;       /* first callee saved GP register used */
+  int first_fp_reg_save;       /* first callee saved FP register used */
+  int first_altivec_reg_save;  /* first callee saved AltiVec register used */
+  int lr_save_p;               /* true if the link reg needs to be saved */
+  int cr_save_p;               /* true if the CR reg needs to be saved */
+  unsigned int vrsave_mask;    /* mask of vec registers to save */
+  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 */
+  enum rs6000_abi abi;         /* which ABI to use */
+  int gp_save_offset;          /* offset to save GP regs from initial SP */
+  int fp_save_offset;          /* offset to save FP regs from initial SP */
+  int altivec_save_offset;     /* offset to save AltiVec regs from initial SP */
+  int lr_save_offset;          /* offset to save LR from initial SP */
+  int cr_save_offset;          /* offset to save CR from initial SP */
+  int vrsave_save_offset;      /* offset to save VRSAVE from initial SP */
+  int spe_gp_save_offset;      /* offset to save spe 64-bit gprs  */
+  int toc_save_offset;         /* offset to save the TOC pointer */
+  int varargs_save_offset;     /* offset to save the varargs registers */
+  int ehrd_offset;             /* offset to EH return data */
+  int reg_size;                        /* register size (4 or 8) */
+  int varargs_size;            /* size to hold V.4 args passed in regs */
+  HOST_WIDE_INT vars_size;     /* variable save area size */
+  int parm_size;               /* outgoing parameter size */
+  int save_size;               /* save area size */
+  int fixed_size;              /* fixed size of stack frame */
+  int gp_size;                 /* size of saved GP registers */
+  int fp_size;                 /* size of saved FP registers */
+  int altivec_size;            /* size of saved AltiVec registers */
+  int cr_size;                 /* size to hold CR if not in save_size */
+  int lr_size;                 /* size to hold LR if not in save_size */
+  int vrsave_size;             /* size to hold VRSAVE if not in save_size */
+  int altivec_padding_size;    /* size of altivec alignment padding if
+                                  not in save_size */
+  int spe_gp_size;             /* size of 64-bit GPR save size for SPE */
+  int spe_padding_size;
+  int toc_size;                        /* size to hold TOC if not in save_size */
+  HOST_WIDE_INT total_size;    /* total bytes allocated for stack */
+  int spe_64bit_regs_used;
+} rs6000_stack_t;
+
 /* Target cpu type */
 
 enum processor_type rs6000_cpu;
@@ -80,6 +124,19 @@ struct rs6000_cpu_select rs6000_select[3] =
   { (const char *)0,   "-mtune=",              1,      0 },
 };
 
+/* Support adjust_priority scheduler hook 
+   and -mprioritize-restricted-insns= option.  */
+const char *rs6000_sched_restricted_insns_priority_str;
+int rs6000_sched_restricted_insns_priority;
+
+/* Support for -msched-costly-dep option.  */
+const char *rs6000_sched_costly_dep_str;
+enum rs6000_dependence_cost rs6000_sched_costly_dep;
+
+/* Support for -minsert-sched-nops option.  */
+const char *rs6000_sched_insert_nops_str;
+enum rs6000_nop_insertion rs6000_sched_insert_nops;
+
 /* Size of long double */
 const char *rs6000_long_double_size_string;
 int rs6000_long_double_type_size;
@@ -173,7 +230,7 @@ int toc_initialized;
 char toc_label_name[10];
 
 /* Alias set for saves and restores from the rs6000 stack.  */
-static int rs6000_sr_alias_set;
+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;
@@ -182,8 +239,8 @@ static int rs6000_sr_alias_set;
 int rs6000_default_long_calls;
 const char *rs6000_longcall_switch;
 
-/* Control alignment for fields within structures. */
-/* String from -malign-XXXXX. */
+/* Control alignment for fields within structures.  */
+/* String from -malign-XXXXX.  */
 const char *rs6000_alignment_string;
 int rs6000_alignment_flags;
 
@@ -207,8 +264,8 @@ static void rs6000_emit_stack_tie (void);
 static void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
 static rtx spe_synthesize_frame_save (rtx);
 static bool spe_func_has_64bit_regs_p (void);
-static void emit_frame_save (rtx, rtx, enum machine_mode,
-                                    unsigned int, int, int);
+static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
+                            int, HOST_WIDE_INT);
 static rtx gen_frame_mem_offset (enum machine_mode, rtx, int);
 static void rs6000_emit_allocate_stack (HOST_WIDE_INT, int);
 static unsigned rs6000_hash_constant (rtx);
@@ -221,6 +278,7 @@ static bool legitimate_small_data_p (enum machine_mode, rtx);
 static bool legitimate_offset_address_p (enum machine_mode, rtx, int);
 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);
@@ -233,9 +291,10 @@ extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes (tree);
 static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
-static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
-                                           HOST_WIDE_INT, tree);
+static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
+                                   tree);
 static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
+static bool rs6000_return_in_memory (tree, tree);
 static void rs6000_file_start (void);
 #if TARGET_ELF
 static unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
@@ -244,7 +303,7 @@ static void rs6000_elf_asm_out_destructor (rtx, int);
 static void rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
 static void rs6000_elf_unique_section (tree, int);
 static void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
-                                                  unsigned HOST_WIDE_INT);
+                                          unsigned HOST_WIDE_INT);
 static void rs6000_elf_encode_section_info (tree, rtx, int)
      ATTRIBUTE_UNUSED;
 static bool rs6000_elf_in_small_data_p (tree);
@@ -255,7 +314,7 @@ static void rs6000_xcoff_asm_named_section (const char *, unsigned int);
 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,
-                                                    unsigned HOST_WIDE_INT);
+                                            unsigned HOST_WIDE_INT);
 static const char * rs6000_xcoff_strip_name_encoding (const char *);
 static unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
 static void rs6000_xcoff_file_start (void);
@@ -268,8 +327,20 @@ static int rs6000_use_dfa_pipeline_interface (void);
 static int rs6000_variable_issue (FILE *, int, rtx, int);
 static bool rs6000_rtx_costs (rtx, int, int, int *);
 static int rs6000_adjust_cost (rtx, rtx, rtx, int);
+static bool is_microcoded_insn (rtx);
+static int is_dispatch_slot_restricted (rtx);
+static bool is_cracked_insn (rtx);
+static bool is_branch_slot_insn (rtx);
 static int rs6000_adjust_priority (rtx, int);
 static int rs6000_issue_rate (void);
+static bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
+static rtx get_next_active_insn (rtx, rtx);
+static bool insn_terminates_group_p (rtx , enum group_termination);
+static bool is_costly_group (rtx *, rtx);
+static int force_new_group (int, FILE *, rtx *, rtx, bool *, int, int *);
+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 void rs6000_init_builtins (void);
@@ -279,15 +350,18 @@ static rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
 static void altivec_init_builtins (void);
 static void rs6000_common_init_builtins (void);
+static void rs6000_init_libfuncs (void);
 
-static void enable_mask_for_builtins (struct builtin_description *,
-                                             int, enum rs6000_builtins,
-                                             enum rs6000_builtins);
+static void enable_mask_for_builtins (struct builtin_description *, int,
+                                     enum rs6000_builtins,
+                                     enum rs6000_builtins);
 static void spe_init_builtins (void);
 static rtx spe_expand_builtin (tree, rtx, bool *);
 static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
 static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
 static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
+static rs6000_stack_t *rs6000_stack_info (void);
+static void debug_stack_info (rs6000_stack_t *);
 
 static rtx altivec_expand_builtin (tree, rtx, bool *);
 static rtx altivec_expand_ld_builtin (tree, rtx, bool *);
@@ -296,6 +370,7 @@ 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);
+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);
@@ -316,8 +391,22 @@ static inline 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 *, 
+static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree);
+static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
+                                     enum machine_mode, tree, int);
+static void rs6000_move_block_from_reg(int regno, rtx x, int nregs);
+static void setup_incoming_varargs (CUMULATIVE_ARGS *,
+                                   enum machine_mode, tree,
+                                   int *, int);
+#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);
+#endif
+
+static tree rs6000_build_builtin_va_list (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -457,6 +546,10 @@ static const char alt_reg_names[][8] =
 #define TARGET_SCHED_ADJUST_COST rs6000_adjust_cost
 #undef TARGET_SCHED_ADJUST_PRIORITY
 #define TARGET_SCHED_ADJUST_PRIORITY rs6000_adjust_priority
+#undef TARGET_SCHED_IS_COSTLY_DEPENDENCE      
+#define TARGET_SCHED_IS_COSTLY_DEPENDENCE rs6000_is_costly_dependence
+#undef TARGET_SCHED_FINISH
+#define TARGET_SCHED_FINISH rs6000_sched_finish
 
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD rs6000_use_sched_lookahead
@@ -467,6 +560,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
 
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
+
 #if TARGET_MACHO
 #undef TARGET_BINDS_LOCAL_P
 #define TARGET_BINDS_LOCAL_P rs6000_binds_local_p
@@ -492,6 +588,32 @@ static const char alt_reg_names[][8] =
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
 
+/* On rs6000, function arguments are promoted, as are function return
+   values.  */
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
+/* Structure return values are passed as an extra parameter.  */
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX hook_rtx_tree_int_null
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY rs6000_return_in_memory
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
+
+/* Always strict argument naming on rs6000.  */
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
+#undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
+#define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
+
+#undef TARGET_BUILD_BUILTIN_VA_LIST
+#define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Override command line options.  Mostly we process the processor
@@ -502,138 +624,83 @@ rs6000_override_options (const char *default_cpu)
 {
   size_t i, j;
   struct rs6000_cpu_select *ptr;
+  int set_masks;
 
-  /* Simplify the entries below by making a mask for any POWER
-     variant and any PowerPC variant.  */
+  /* Simplifications for entries below.  */
 
-#define POWER_MASKS (MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING)
-#define POWERPC_MASKS (MASK_POWERPC | MASK_PPC_GPOPT \
-                      | MASK_PPC_GFXOPT | MASK_POWERPC64)
-#define POWERPC_OPT_MASKS (MASK_PPC_GPOPT | MASK_PPC_GFXOPT)
+  enum {
+    POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
+    POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
+  };
 
+  /* This table occasionally claims that a processor does not support
+     a particular feature even though it does, but the feature is slower
+     than the alternative.  Thus, it shouldn't be relied on as a
+     complete description of the processor's support.  
+
+     Please keep this list in order, and don't forget to update the
+     documentation in invoke.texi when adding a new processor or
+     flag.  */
   static struct ptt
     {
       const char *const name;          /* Canonical processor name.  */
       const enum processor_type processor; /* Processor type enum value.  */
       const int target_enable; /* Target flags to enable.  */
-      const int target_disable;        /* Target flags to disable.  */
     } const processor_target_table[]
-      = {{"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_MASKS},
-        {"power", PROCESSOR_POWER,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"power2", PROCESSOR_POWER,
-           MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
-           POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"power3", PROCESSOR_PPC630,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS},
-        {"power4", PROCESSOR_POWER4,
-            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-            POWER_MASKS},
-        {"powerpc", PROCESSOR_POWERPC,
-           MASK_POWERPC | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"powerpc64", PROCESSOR_POWERPC64,
-           MASK_POWERPC | MASK_POWERPC64 | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS},
-        {"rios", PROCESSOR_RIOS1,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"rios1", PROCESSOR_RIOS1,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"rsc", PROCESSOR_PPC601,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"rsc1", PROCESSOR_PPC601,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"rios2", PROCESSOR_RIOS2,
-           MASK_POWER | MASK_MULTIPLE | MASK_STRING | MASK_POWER2,
-           POWERPC_MASKS | MASK_NEW_MNEMONICS},
-        {"rs64a", PROCESSOR_RS64A,
-           MASK_POWERPC | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS},
-        {"401", PROCESSOR_PPC403,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+      = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"403", PROCESSOR_PPC403,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS | MASK_STRICT_ALIGN,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"405", PROCESSOR_PPC405,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"405fp", PROCESSOR_PPC405,
-           MASK_POWERPC | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"440", PROCESSOR_PPC440,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"440fp", PROCESSOR_PPC440,
-           MASK_POWERPC | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"505", PROCESSOR_MPCCORE,
-           MASK_POWERPC | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
+        {"405", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK},
+        {"440", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK},
+        {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
         {"601", PROCESSOR_PPC601,
-           MASK_POWER | MASK_POWERPC | MASK_NEW_MNEMONICS | MASK_MULTIPLE | MASK_STRING,
-           MASK_POWER2 | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"602", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"603", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"603e", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"ec603e", PROCESSOR_PPC603,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"604", PROCESSOR_PPC604,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"604e", PROCESSOR_PPC604e,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
+         MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
+        {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
         {"620", PROCESSOR_PPC620,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS},
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
         {"630", PROCESSOR_PPC630,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS},
-        {"740", PROCESSOR_PPC750,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"750", PROCESSOR_PPC750,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"7400", PROCESSOR_PPC7400,
-            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"7450", PROCESSOR_PPC7450,
-            MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-            POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"8540", PROCESSOR_PPC8540,
-           MASK_POWERPC | MASK_PPC_GFXOPT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | MASK_PPC_GPOPT | MASK_POWERPC64},
-        {"801", PROCESSOR_MPCCORE,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"821", PROCESSOR_MPCCORE,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"823", PROCESSOR_MPCCORE,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
-        {"860", PROCESSOR_MPCCORE,
-           MASK_POWERPC | MASK_SOFT_FLOAT | MASK_NEW_MNEMONICS,
-           POWER_MASKS | POWERPC_OPT_MASKS | MASK_POWERPC64},
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+        {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK},
+        {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK},
+        {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
-           MASK_POWERPC | POWERPC_OPT_MASKS | MASK_NEW_MNEMONICS,
-           POWER_MASKS}};
+         POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
+        {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS},
+        {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT},
+        {"G4",  PROCESSOR_PPC7450, POWERPC_7400_MASK},
+        {"G5", PROCESSOR_POWER4,
+         POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
+        {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+        {"power2", PROCESSOR_POWER,
+         MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
+        {"power3", PROCESSOR_PPC630,
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+        {"power4", PROCESSOR_POWER4,
+         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
+        {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
+        {"powerpc64", PROCESSOR_POWERPC64,
+         POWERPC_BASE_MASK | MASK_POWERPC64},
+        {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+        {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+        {"rios2", PROCESSOR_RIOS2,
+         MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING},
+        {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+        {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING},
+        {"rs64a", PROCESSOR_RS64A, POWERPC_BASE_MASK | MASK_POWERPC64},
+      };
 
   const size_t ptt_size = ARRAY_SIZE (processor_target_table);
 
@@ -642,6 +709,28 @@ rs6000_override_options (const char *default_cpu)
   /* Save current -mstring/-mno-string status.  */
   int string = TARGET_STRING;
 
+  /* Some OSs don't support saving the high part of 64-bit registers on
+     context switch.  Other OSs don't support saving Altivec registers.
+     On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC
+     settings; if the user wants either, the user must explicitly specify
+     them and we won't interfere with the user's specification.  */
+
+  enum {
+    POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
+    POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT 
+                    | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
+                    | MASK_MFCRF)
+  };
+ set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
+#ifdef OS_MISSING_POWERPC64
+  if (OS_MISSING_POWERPC64)
+    set_masks &= ~MASK_POWERPC64;
+#endif
+#ifdef OS_MISSING_ALTIVEC
+  if (OS_MISSING_ALTIVEC)
+    set_masks &= ~MASK_ALTIVEC;
+#endif
+
   /* Identify the processor type.  */
   rs6000_select[0].string = default_cpu;
   rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
@@ -659,8 +748,9 @@ rs6000_override_options (const char *default_cpu)
 
                if (ptr->set_arch_p)
                  {
-                   target_flags |= processor_target_table[j].target_enable;
-                   target_flags &= ~processor_target_table[j].target_disable;
+                   target_flags &= ~set_masks;
+                   target_flags |= (processor_target_table[j].target_enable
+                                    & set_masks);
                  }
                break;
              }
@@ -820,6 +910,42 @@ rs6000_override_options (const char *default_cpu)
       rs6000_default_long_calls = (base[0] != 'n');
     }
 
+  /* Handle -mprioritize-restricted-insns option.  */
+  rs6000_sched_restricted_insns_priority = DEFAULT_RESTRICTED_INSNS_PRIORITY;
+  if (rs6000_sched_restricted_insns_priority_str)
+    rs6000_sched_restricted_insns_priority =
+      atoi (rs6000_sched_restricted_insns_priority_str);
+
+  /* Handle -msched-costly-dep option.  */
+  rs6000_sched_costly_dep = DEFAULT_SCHED_COSTLY_DEP;
+  if (rs6000_sched_costly_dep_str)
+    {
+      if (! strcmp (rs6000_sched_costly_dep_str, "no"))  
+        rs6000_sched_costly_dep = no_dep_costly;
+      else if (! strcmp (rs6000_sched_costly_dep_str, "all"))
+        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;
+      else if (! strcmp (rs6000_sched_costly_dep_str, "store_to_load"))
+        rs6000_sched_costly_dep = store_to_load_dep_costly;
+      else 
+        rs6000_sched_costly_dep = atoi (rs6000_sched_costly_dep_str);
+    }
+
+  /* Handle -minsert-sched-nops option.  */
+  rs6000_sched_insert_nops = DEFAULT_SCHED_FINISH_NOP_INSERTION_SCHEME;
+  if (rs6000_sched_insert_nops_str)
+    {
+      if (! strcmp (rs6000_sched_insert_nops_str, "no"))
+        rs6000_sched_insert_nops = sched_finish_none;
+      else if (! strcmp (rs6000_sched_insert_nops_str, "pad"))
+        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;
+      else
+        rs6000_sched_insert_nops = atoi (rs6000_sched_insert_nops_str);
+    }
+
 #ifdef TARGET_REGNAMES
   /* If the user desires alternate register names, copy in the
      alternate names now.  */
@@ -840,7 +966,7 @@ rs6000_override_options (const char *default_cpu)
 
   if (TARGET_LONG_DOUBLE_128
       && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
-    real_format_for_mode[TFmode - QFmode] = &ibm_extended_format;
+    REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
 
   /* Allocate an alias set for register saves & restores from stack.  */
   rs6000_sr_alias_set = new_alias_set ();
@@ -909,8 +1035,9 @@ rs6000_parse_abi_options (void)
 static void
 rs6000_parse_alignment_option (void)
 {
-  if (rs6000_alignment_string == 0
-      || ! strcmp (rs6000_alignment_string, "power"))
+  if (rs6000_alignment_string == 0)
+    return;
+  else if (! strcmp (rs6000_alignment_string, "power"))
     rs6000_alignment_flags = MASK_ALIGN_POWER;
   else if (! strcmp (rs6000_alignment_string, "natural"))
     rs6000_alignment_flags = MASK_ALIGN_NATURAL;
@@ -1553,8 +1680,27 @@ easy_vector_constant (rtx op, enum machine_mode mode)
       && cst2 >= -0x7fff && cst2 <= 0x7fff)
     return 1;
 
-  if (TARGET_ALTIVEC && EASY_VECTOR_15 (cst, op, mode))
-    return 1;
+  if (TARGET_ALTIVEC)
+    switch (mode) 
+      {
+      case V4SImode:
+       if (EASY_VECTOR_15 (cst, op, mode))
+         return 1;
+       if ((cst & 0xffff) != ((cst >> 16) & 0xffff))
+         break;
+       cst = cst >> 16;
+      case V8HImode:
+       if (EASY_VECTOR_15 (cst, op, mode))
+         return 1;
+       if ((cst & 0xff) != ((cst >> 8) & 0xff))
+         break;
+       cst = cst >> 8;
+      case V16QImode:
+       if (EASY_VECTOR_15 (cst, op, mode))
+         return 1;
+      default: 
+       break;
+      }
 
   if (TARGET_ALTIVEC && EASY_VECTOR_15_ADD_SELF (cst, op, mode))
     return 1;
@@ -1595,23 +1741,37 @@ output_vec_const_move (rtx *operands)
     {
       if (zero_constant (vec, mode))
        return "vxor %0,%0,%0";
-      else if (EASY_VECTOR_15 (cst, vec, mode))
+      else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
+       return "#";
+      else if (easy_vector_constant (vec, mode))
        {
          operands[1] = GEN_INT (cst);
          switch (mode)
            {
            case V4SImode:
-             return "vspltisw %0,%1";
+             if (EASY_VECTOR_15 (cst, vec, mode))
+               {
+                 operands[1] = GEN_INT (cst);
+                 return "vspltisw %0,%1";
+               }
+             cst = cst >> 16;
            case V8HImode:
-             return "vspltish %0,%1";
+             if (EASY_VECTOR_15 (cst, vec, mode))
+               {
+                 operands[1] = GEN_INT (cst);
+                 return "vspltish %0,%1";
+               }
+             cst = cst >> 8;
            case V16QImode:
-             return "vspltisb %0,%1";
+             if (EASY_VECTOR_15 (cst, vec, mode))
+               {
+                 operands[1] = GEN_INT (cst);
+                 return "vspltisb %0,%1";
+               }
            default:
              abort ();
            }
        }
-      else if (EASY_VECTOR_15_ADD_SELF (cst, vec, mode))
-       return "#";
       else
        abort ();
     }
@@ -2006,7 +2166,7 @@ and64_operand (rtx op, enum machine_mode mode)
 int
 and64_2_operand (rtx op, enum machine_mode mode)
 {
-  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis. */
+  if (fixed_regs[CR0_REGNO])   /* CR0 not available, don't do andi./andis.  */
     return gpc_reg_operand (op, mode) || mask64_2_operand (op, mode);
 
   return logical_operand (op, mode) || mask64_2_operand (op, mode);
@@ -2031,6 +2191,7 @@ 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));
 }
 
@@ -2156,6 +2317,26 @@ input_operand (rtx op, enum machine_mode mode)
   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
@@ -2200,18 +2381,34 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
 #endif
 }
 
-/* Return 1 for all valid move insn operand combination involving altivec      
-   vectors in gprs.  */
+/* Return true, if operand is a memory operand and has a
+   displacement divisible by 4.  */
 
 int
-altivec_in_gprs_p (rtx op0, rtx op1)
+word_offset_memref_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  if (REG_P (op0) && REGNO_REG_CLASS (REGNO (op0)) == GENERAL_REGS)
-    return 1;
+  rtx addr;
+  int off = 0;
 
-  if (REG_P (op1) && REGNO_REG_CLASS (REGNO (op1)) == GENERAL_REGS) 
-    return 1;
-  return 0;
+  if (!memory_operand (op, mode))
+    return 0;
+
+  addr = XEXP (op, 0);
+  if (GET_CODE (addr) == PLUS
+      && GET_CODE (XEXP (addr, 0)) == REG
+      && GET_CODE (XEXP (addr, 1)) == CONST_INT)
+    off = INTVAL (XEXP (addr, 1));
+
+  return (off % 4) == 0;
+}
+
+/* Return true if either operand is a general purpose register.  */
+
+bool
+gpr_or_gpr_p (rtx op0, rtx op1)
+{
+  return ((REG_P (op0) && INT_REGNO_P (REGNO (op0)))
+         || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
 }
 
 \f
@@ -2329,7 +2526,7 @@ legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
 
     case DFmode:
     case DImode:
-      if (TARGET_32BIT)
+      if (mode == DFmode || !TARGET_POWERPC64)
        extra = 4;
       else if (offset & 3)
        return false;
@@ -2337,7 +2534,7 @@ legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
 
     case TFmode:
     case TImode:
-      if (TARGET_32BIT)
+      if (mode == TFmode || !TARGET_POWERPC64)
        extra = 12;
       else if (offset & 3)
        return false;
@@ -2378,6 +2575,25 @@ legitimate_indirect_address_p (rtx x, int strict)
 }
 
 static 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 (GET_CODE (x) != LO_SUM)
+    return false;
+  if (GET_CODE (XEXP (x, 0)) != REG)
+    return false;
+  if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), 0))
+    return false;
+  x = XEXP (x, 1);
+
+  return CONSTANT_P (x);
+}
+
+static bool
 legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
 {
   if (GET_CODE (x) != LO_SUM)
@@ -2388,9 +2604,9 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   x = XEXP (x, 1);
 
-  if (TARGET_ELF)
+  if (TARGET_ELF || TARGET_MACHO)
     {
-      if (DEFAULT_ABI != ABI_AIX && flag_pic)
+      if (DEFAULT_ABI != ABI_AIX && DEFAULT_ABI != ABI_DARWIN && flag_pic)
        return false;
       if (TARGET_TOC)
        return false;
@@ -2512,8 +2728,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
               || ((TARGET_HARD_FLOAT && TARGET_FPRS) && mode == DFmode)))
     {
       rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_elf_high (reg, (x)));
-      return gen_rtx_LO_SUM (Pmode, reg, (x));
+      emit_insn (gen_elf_high (reg, x));
+      return gen_rtx_LO_SUM (Pmode, reg, x);
     }
   else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
           && ! flag_pic
@@ -2528,8 +2744,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && mode != TImode)
     {
       rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_macho_high (reg, (x)));
-      return gen_rtx_LO_SUM (Pmode, reg, (x));
+      emit_insn (gen_macho_high (reg, x));
+      return gen_rtx_LO_SUM (Pmode, reg, x);
     }
   else if (TARGET_TOC 
           && constant_pool_expr_p (x)
@@ -2769,6 +2985,9 @@ rs6000_tls_symbol_ref (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
 bool
 rs6000_tls_referenced_p (rtx x)
 {
+  if (! TARGET_HAVE_TLS)
+    return false;
+
   return for_each_rtx (&x, &rs6000_tls_symbol_ref_1, 0);
 }
 
@@ -2878,36 +3097,30 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
   if (GET_CODE (x) == SYMBOL_REF
       && DEFAULT_ABI == ABI_DARWIN
       && !ALTIVEC_VECTOR_MODE (mode)
-      && flag_pic)
-    {
-      /* Darwin load of floating point constant.  */
-      rtx offset = gen_rtx (CONST, Pmode,
-                   gen_rtx (MINUS, Pmode, x,
-                   gen_rtx (SYMBOL_REF, Pmode,
-                       machopic_function_base_name ())));
-      x = gen_rtx (LO_SUM, GET_MODE (x),
-           gen_rtx (PLUS, Pmode, pic_offset_table_rtx,
-               gen_rtx (HIGH, Pmode, offset)), offset);
+      && (flag_pic || MACHO_DYNAMIC_NO_PIC_P)
+      /* Don't do this for TFmode, since the result isn't offsettable.  */
+      && mode != TFmode)
+    {
+      if (flag_pic)
+       {
+         rtx offset = gen_rtx_CONST (Pmode,
+                        gen_rtx_MINUS (Pmode, x,
+                          gen_rtx_SYMBOL_REF (Pmode,
+                            machopic_function_base_name ())));
+         x = gen_rtx_LO_SUM (GET_MODE (x),
+               gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
+                 gen_rtx_HIGH (Pmode, offset)), offset);
+       }
+      else
+       x = gen_rtx_LO_SUM (GET_MODE (x),
+              gen_rtx_HIGH (Pmode, x), x);
+
       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-               BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-               opnum, (enum reload_type)type);
+                  BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
       *win = 1;
       return x;
     }
-   if (GET_CODE (x) == SYMBOL_REF
-       && DEFAULT_ABI == ABI_DARWIN
-       && !ALTIVEC_VECTOR_MODE (mode)
-       && MACHO_DYNAMIC_NO_PIC_P)
-     {
-       /* Darwin load of floating point constant.  */
-       x = gen_rtx (LO_SUM, GET_MODE (x),
-               gen_rtx (HIGH, Pmode, x), x);
-       push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-               BASE_REG_CLASS, Pmode, VOIDmode, 0, 0,
-               opnum, (enum reload_type)type);
-       *win = 1;
-       return x;
-     }
 #endif
   if (TARGET_TOC
       && constant_pool_expr_p (x)
@@ -3113,7 +3326,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
          || (ud4 == 0 && ud3 == 0 && ud2 == 0 && ! (ud1 & 0x8000)))
        {
          if (ud1 & 0x8000)
-           emit_move_insn (dest, GEN_INT (((ud1  ^ 0x8000) -  0x8000)));
+           emit_move_insn (dest, GEN_INT (((ud1 ^ 0x8000) -  0x8000)));
          else
            emit_move_insn (dest, GEN_INT (ud1));
        }
@@ -3213,6 +3426,47 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                      adjust_address (operands[1], SImode, 4));
       return;
     }
+#if 0
+    else if (mode == DImode && TARGET_POWERPC64
+               && GET_CODE (operands[0]) == REG
+               && GET_CODE (operands[1]) == MEM && optimize > 0
+               && SLOW_UNALIGNED_ACCESS (DImode,
+                                         MEM_ALIGN (operands[1]) > 32
+                                         ? 32
+                                         : MEM_ALIGN (operands[1]))
+               && !no_new_pseudos)
+      {
+        rtx reg = gen_reg_rtx (SImode);
+       emit_insn (gen_rtx_SET (SImode, reg,
+                               adjust_address (operands[1], SImode, 0)));
+        reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+        emit_insn (gen_insvdi (operands[0], GEN_INT (32), const0_rtx, reg));
+        reg = gen_reg_rtx (SImode);
+       emit_insn (gen_rtx_SET (SImode, reg,
+                               adjust_address (operands[1], SImode, 4)));
+        reg = simplify_gen_subreg (DImode, reg, SImode, 0);
+        emit_insn (gen_insvdi (operands[0], GEN_INT (32), GEN_INT (32), reg));
+        return;
+      }
+      else if (mode == DImode && TARGET_POWERPC64
+               && GET_CODE (operands[1]) == REG
+               && GET_CODE (operands[0]) == MEM && optimize > 0
+               && SLOW_UNALIGNED_ACCESS (DImode,
+                                         MEM_ALIGN (operands[0]) > 32
+                                         ? 32
+                                         : MEM_ALIGN (operands[0]))
+               && !no_new_pseudos)
+      {
+        rtx reg = gen_reg_rtx (DImode);
+        emit_move_insn (reg,
+                       gen_rtx_LSHIFTRT (DImode, operands[1], GEN_INT (32)));
+        emit_move_insn (adjust_address (operands[0], SImode, 0),
+                       simplify_gen_subreg (SImode, reg, DImode, 0));
+        emit_move_insn (adjust_address (operands[0], SImode, 4),
+                       simplify_gen_subreg (SImode, operands[1], DImode, 0));
+        return;
+      }
+#endif
   
   if (!no_new_pseudos)
     {
@@ -3274,7 +3528,26 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
   /* Handle the case of CONSTANT_P_RTX.  */
   if (GET_CODE (operands[1]) == CONSTANT_P_RTX)
     goto emit_set;
-  
+
+  /* 128-bit constant floating-point values on Darwin should really be
+     loaded as two parts.  */
+  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
+      && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
+    {
+      /* DImode is used, not DFmode, because simplify_gen_subreg doesn't
+        know how to get a DFmode SUBREG of a TFmode.  */
+      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode, 0),
+                       simplify_gen_subreg (DImode, operands[1], mode, 0),
+                       DImode);
+      rs6000_emit_move (simplify_gen_subreg (DImode, operands[0], mode,
+                                            GET_MODE_SIZE (DImode)),
+                       simplify_gen_subreg (DImode, operands[1], mode,
+                                            GET_MODE_SIZE (DImode)),
+                       DImode);
+      return;
+    }
+
   /* FIXME:  In the long term, this switch statement should go away
      and be replaced by a sequence of tests based on things like
      mode == Pmode.  */
@@ -3509,6 +3782,52 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
 }
 \f
+/* Nonzero if we can use a floating-point register to pass this arg.  */
+#define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
+  (GET_MODE_CLASS (MODE) == MODE_FLOAT         \
+   && (CUM)->fregno <= FP_ARG_MAX_REG          \
+   && TARGET_HARD_FLOAT && TARGET_FPRS)
+
+/* Nonzero if we can use an AltiVec register to pass this arg.  */
+#define USE_ALTIVEC_FOR_ARG_P(CUM,MODE,TYPE,NAMED)     \
+  (ALTIVEC_VECTOR_MODE (MODE)                          \
+   && (CUM)->vregno <= ALTIVEC_ARG_MAX_REG             \
+   && TARGET_ALTIVEC_ABI                               \
+   && (NAMED))
+
+/* Return a nonzero value to say to return the function value in
+   memory, just as large structures are always returned.  TYPE will be
+   the data type of the value, and FNTYPE will be the type of the
+   function doing the returning, or @code{NULL} for libcalls.
+
+   The AIX ABI for the RS/6000 specifies that all structures are
+   returned in memory.  The Darwin ABI does the same.  The SVR4 ABI
+   specifies that structures <= 8 bytes are returned in r3/r4, but a
+   draft put them in memory, and GCC used to implement the draft
+   instead of the final standard.  Therefore, TARGET_AIX_STRUCT_RET
+   controls this instead of DEFAULT_ABI; V.4 targets needing backward
+   compatibility can change DRAFT_V4_STRUCT_RET to override the
+   default, and -m switches get the final word.  See
+   rs6000_override_options for more details.
+
+   The PPC32 SVR4 ABI uses IEEE double extended for long double, if 128-bit
+   long double support is enabled.  These values are returned in memory.
+
+   int_size_in_bytes returns -1 for variable size objects, which go in
+   memory always.  The cast to unsigned makes -1 > 8.  */
+
+static bool
+rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  if (AGGREGATE_TYPE_P (type)
+      && (TARGET_AIX_STRUCT_RET
+         || (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8))
+    return true;
+  if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
+    return true;
+  return false;
+}
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is 0.
@@ -3541,7 +3860,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
   else if (cum->prototype)
     cum->nargs_prototype = (list_length (TYPE_ARG_TYPES (fntype)) - 1
                            + (TYPE_MODE (TREE_TYPE (fntype)) == BLKmode
-                              || RETURN_IN_MEMORY (TREE_TYPE (fntype))));
+                              || rs6000_return_in_memory (TREE_TYPE (fntype),
+                                                          fntype)));
 
   else
     cum->nargs_prototype = 0;
@@ -3659,10 +3979,39 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
-      if (cum->vregno <= ALTIVEC_ARG_MAX_REG && cum->nargs_prototype >= 0)
+      if (USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
        cum->vregno++;
-      else
-       cum->words += RS6000_ARG_SIZE (mode, type);
+      
+      /* PowerPC64 Linux and AIX allocates GPRs for a vector argument
+        even if it is going to be passed in a vector register.  
+        Darwin does the same for variable-argument functions.  */
+      if ((DEFAULT_ABI == ABI_AIX && TARGET_64BIT)
+                  || (cum->stdarg && DEFAULT_ABI != ABI_V4))
+        {
+         int align;
+         
+         /* Vector parameters must be 16-byte aligned.  This places
+            them at 2 mod 4 in terms of words in 32-bit mode, since
+            the parameter save area starts at offset 24 from the
+            stack.  In 64-bit mode, they just have to start on an
+            even word, since the parameter save area is 16-byte
+            aligned.  Space for GPRs is reserved even if the argument
+            will be passed in memory.  */
+         if (TARGET_32BIT)
+           align = ((6 - (cum->words & 3)) & 3);
+         else
+           align = cum->words & 1;
+         cum->words += align + RS6000_ARG_SIZE (mode, type);
+         
+         if (TARGET_DEBUG_ARG)
+           {
+             fprintf (stderr, "function_adv: words = %2d, align=%d, ", 
+                      cum->words, align);
+             fprintf (stderr, "nargs = %4d, proto = %d, mode = %4s\n",
+                      cum->nargs_prototype, cum->prototype, 
+                      GET_MODE_NAME (mode));
+           }
+       }
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode)
           && !cum->stdarg
@@ -3747,6 +4096,7 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 }
 
 /* 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)
@@ -3772,17 +4122,121 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
        }
       else
-       return NULL;
+       return NULL_RTX;
     }
   else
     {
       if (cum->sysv_gregno <= GP_ARG_MAX_REG)
        return gen_rtx_REG (mode, cum->sysv_gregno);
       else
-       return NULL;
+       return NULL_RTX;
     }
 }
 
+/* Determine where to place an argument in 64-bit mode with 32-bit ABI.  */
+
+static rtx
+rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
+                          tree type, int align_words)
+{
+  if (mode == DFmode)
+    {
+      /* -mpowerpc64 with 32bit ABI splits up a DFmode argument
+        in vararg list into zero, one or two GPRs */
+      if (align_words >= GP_ARG_NUM_REG)
+       return gen_rtx_PARALLEL (DFmode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              NULL_RTX, const0_rtx), 
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (mode,
+                                                           cum->fregno),
+                                              const0_rtx)));
+      else if (align_words + RS6000_ARG_SIZE (mode, type)
+              > GP_ARG_NUM_REG)
+       /* If this is partially on the stack, then we only
+          include the portion actually in registers here.  */
+       return gen_rtx_PARALLEL (DFmode,
+                gen_rtvec (2,   
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (SImode,
+                                                           GP_ARG_MIN_REG
+                                                           + align_words),
+                                              const0_rtx),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (mode,
+                                                           cum->fregno),
+                                              const0_rtx)));
+
+      /* split a DFmode arg into two GPRs */
+      return gen_rtx_PARALLEL (DFmode,
+              gen_rtvec (3,
+                         gen_rtx_EXPR_LIST (VOIDmode,       
+                                            gen_rtx_REG (SImode,
+                                                         GP_ARG_MIN_REG
+                                                         + align_words),
+                                            const0_rtx),
+                         gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_REG (SImode,
+                                                         GP_ARG_MIN_REG
+                                                         + align_words + 1),
+                                            GEN_INT (4)),
+                         gen_rtx_EXPR_LIST (VOIDmode,
+                                            gen_rtx_REG (mode, cum->fregno),
+                                            const0_rtx)));
+    }
+  /* -mpowerpc64 with 32bit ABI splits up a DImode argument into one
+     or two GPRs */
+  else if (mode == DImode)
+    {
+      if (align_words < GP_ARG_NUM_REG - 1)
+       return gen_rtx_PARALLEL (DImode,
+                gen_rtvec (2,
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (SImode,
+                                                           GP_ARG_MIN_REG
+                                                           + align_words),
+                                              const0_rtx),
+                           gen_rtx_EXPR_LIST (VOIDmode,
+                                              gen_rtx_REG (SImode,
+                                                           GP_ARG_MIN_REG
+                                                           + align_words + 1),
+                                              GEN_INT (4))));
+      else if (align_words == GP_ARG_NUM_REG - 1)
+         return gen_rtx_PARALLEL (DImode,
+                  gen_rtvec (2,
+                             gen_rtx_EXPR_LIST (VOIDmode,
+                                                NULL_RTX, const0_rtx),
+                             gen_rtx_EXPR_LIST (VOIDmode,
+                                                gen_rtx_REG (SImode,
+                                                             GP_ARG_MIN_REG
+                                                             + align_words),
+                                                const0_rtx)));
+    }
+  else if (mode == BLKmode && align_words <= (GP_ARG_NUM_REG - 1))
+    {
+      int k;
+      int size = int_size_in_bytes (type);
+      int no_units = ((size - 1) / 4) + 1;
+      int max_no_words = GP_ARG_NUM_REG - align_words;
+      int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
+      rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
+
+      memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
+
+      for (k=0; k < rtlvec_len; k++)
+       rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
+                                      gen_rtx_REG (SImode,
+                                                   GP_ARG_MIN_REG
+                                                   + align_words + k),
+                                      k == 0 ? const0_rtx : GEN_INT (k*4));
+
+      return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k, rtlvec));
+  }
+
+  return NULL_RTX;
+}
+
 /* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
@@ -3836,12 +4290,69 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       return GEN_INT (cum->call_cookie);
     }
 
-  if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
+  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)));
+      }
+    else
+      return gen_rtx_REG (mode, cum->vregno);
+  else if (TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (mode))
     {
-      if (named && cum->vregno <= ALTIVEC_ARG_MAX_REG)
-       return gen_rtx_REG (mode, cum->vregno);
+      if (named || abi == ABI_V4)
+       return NULL_RTX;
       else
-       return NULL;
+       {
+         /* Vector parameters to varargs functions under AIX or Darwin
+            get passed in memory and possibly also in GPRs.  */
+         int align, align_words;
+         enum machine_mode part_mode = mode;
+
+         /* Vector parameters must be 16-byte aligned.  This places them at
+            2 mod 4 in terms of words in 32-bit mode, since the parameter
+            save area starts at offset 24 from the stack.  In 64-bit mode,
+            they just have to start on an even word, since the parameter
+            save area is 16-byte aligned.  */
+         if (TARGET_32BIT)
+           align = ((6 - (cum->words & 3)) & 3);
+         else
+           align = cum->words & 1;
+         align_words = cum->words + align;
+
+         /* Out of registers?  Memory, then.  */
+         if (align_words >= GP_ARG_NUM_REG)
+           return NULL_RTX;
+         
+         /* The vector value goes in GPRs.  Only the part of the
+            value in GPRs is reported here.  */
+         if (align_words + CLASS_MAX_NREGS (mode, GENERAL_REGS)
+             > GP_ARG_NUM_REG)
+           /* Fortunately, there are only two possibilities, the value
+              is either wholly in GPRs or half in GPRs and half not.  */
+           part_mode = DImode;
+         
+         return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
+       }
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
     return rs6000_spe_function_arg (cum, mode, type);
@@ -3853,7 +4364,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          if (cum->fregno <= FP_ARG_V4_MAX_REG)
            return gen_rtx_REG (mode, cum->fregno);
          else
-           return NULL;
+           return NULL_RTX;
        }
       else
        {
@@ -3875,7 +4386,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
            return gen_rtx_REG (mode, gregno);
          else
-           return NULL;
+           return NULL_RTX;
        }
     }
   else
@@ -3887,7 +4398,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       if (type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
         return NULL_RTX;
 
-      if (USE_FP_FOR_ARG_P (*cum, mode, type))
+      if (TARGET_32BIT && TARGET_POWERPC64
+         && (mode == DFmode || mode == DImode || mode == BLKmode))
+       return rs6000_mixed_function_arg (cum, mode, type, align_words);
+
+      if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
          if (! type
              || ((cum->nargs_prototype > 0)
@@ -3932,13 +4447,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 int
 function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
-                           tree type, int named ATTRIBUTE_UNUSED)
+                           tree type, int named)
 {
   if (DEFAULT_ABI == ABI_V4)
     return 0;
 
-  if (USE_FP_FOR_ARG_P (*cum, mode, type)
-      || USE_ALTIVEC_FOR_ARG_P (*cum, mode, type))
+  if (USE_FP_FOR_ARG_P (cum, mode, type)
+      || USE_ALTIVEC_FOR_ARG_P (cum, mode, type, named))
     {
       if (cum->nargs_prototype >= 0)
        return 0;
@@ -3982,8 +4497,39 @@ function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
 
       return 1;
     }
-  return type && int_size_in_bytes (type) <= 0;
+  return type && int_size_in_bytes (type) < 0;
+}
+
+static void
+rs6000_move_block_from_reg (int regno, rtx x, int nregs)
+{
+  int i;
+  enum machine_mode reg_mode = TARGET_32BIT ? SImode : DImode;
+
+  if (nregs == 0)
+    return;
+
+    for (i = 0; i < nregs; i++)
+    {
+      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));
+      }
+      else
+       tem = replace_equiv_address (tem, XEXP (tem, 0));
+
+      if (tem == NULL_RTX)
+        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. 
@@ -3999,7 +4545,7 @@ function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
    Normally, this macro will push all remaining incoming registers on the
    stack and set PRETEND_SIZE to the length of the registers pushed.  */
 
-void
+static void
 setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
                tree type, int *pretend_size ATTRIBUTE_UNUSED, int no_rtl)
 {
@@ -4007,19 +4553,10 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   int reg_size = TARGET_32BIT ? 4 : 8;
   rtx save_area = NULL_RTX, mem;
   int first_reg_offset, set;
-  tree fntype;
-  int stdarg_p;
 
-  fntype = TREE_TYPE (current_function_decl);
-  stdarg_p = (TYPE_ARG_TYPES (fntype) != 0
-             && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
-                 != void_type_node));
-
-  /* For varargs, we do not want to skip the dummy va_dcl argument.
-     For stdargs, we do want to skip the last named argument.  */
+  /* Skip the last named argument.  */
   next_cum = *cum;
-  if (stdarg_p)
-    function_arg_advance (&next_cum, mode, type, 1);
+  function_arg_advance (&next_cum, mode, type, 1);
 
   if (DEFAULT_ABI == ABI_V4)
     {
@@ -4050,8 +4587,8 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       set_mem_alias_set (mem, set);
       set_mem_align (mem, BITS_PER_WORD);
 
-      move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem,
-                          GP_ARG_NUM_REG - first_reg_offset);
+      rs6000_move_block_from_reg (GP_ARG_MIN_REG + first_reg_offset, mem, 
+                                 GP_ARG_NUM_REG - first_reg_offset);
     }
 
   /* Save FP registers if needed.  */
@@ -4088,8 +4625,8 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 /* Create the va_list data type.  */
 
-tree
-rs6000_build_va_list (void)
+static tree
+rs6000_build_builtin_va_list (void)
 {
   tree f_gpr, f_fpr, f_res, f_ovf, f_sav, record, type_decl;
 
@@ -4211,7 +4748,7 @@ rs6000_va_arg (tree valist, tree type)
   if (DEFAULT_ABI != ABI_V4)
     {
       /* Variable sized types are passed by reference.  */
-      if (int_size_in_bytes (type) <= 0)
+      if (int_size_in_bytes (type) < 0)
        {
          u = build_pointer_type (type);
 
@@ -4277,7 +4814,7 @@ rs6000_va_arg (tree valist, tree type)
       sav_scale = 4;
     }
 
-  /* Pull the value out of the saved registers ...  */
+  /* Pull the value out of the saved registers....  */
 
   lab_false = gen_label_rtx ();
   lab_over = gen_label_rtx ();
@@ -5063,6 +5600,52 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
 }
 
 static rtx
+altivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
+{
+  rtx pat, addr;
+  tree arg0 = TREE_VALUE (arglist);
+  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = Pmode;
+  enum machine_mode mode1 = Pmode;
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+
+  if (icode == CODE_FOR_nothing)
+    /* Builtin not supported on this processor.  */
+    return 0;
+
+  /* If we got invalid arguments bail out before generating bad rtl.  */
+  if (arg0 == error_mark_node || arg1 == error_mark_node)
+    return const0_rtx;
+
+  if (target == 0
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  op1 = copy_to_mode_reg (mode1, op1); 
+
+  if (op0 == const0_rtx)
+    {
+      addr = gen_rtx_MEM (tmode, op1);
+    }
+  else
+    {
+      op0 = copy_to_mode_reg (mode0, op0);
+      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op0, op1));
+    }
+
+  pat = GEN_FCN (icode) (target, addr);
+
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+
+  return target;
+}
+
+static rtx
 altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
 {
   tree arg0 = TREE_VALUE (arglist);
@@ -5071,10 +5654,10 @@ altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
   rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
   rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
   rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
-  rtx pat;
-  enum machine_mode mode0 = insn_data[icode].operand[0].mode;
-  enum machine_mode mode1 = insn_data[icode].operand[1].mode;
-  enum machine_mode mode2 = insn_data[icode].operand[2].mode;
+  rtx pat, addr;
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode1 = Pmode;
+  enum machine_mode mode2 = Pmode;
 
   /* Invalid arguments.  Bail before doing anything stoopid!  */
   if (arg0 == error_mark_node
@@ -5082,14 +5665,22 @@ altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
       || arg2 == error_mark_node)
     return const0_rtx;
 
-  if (! (*insn_data[icode].operand[2].predicate) (op0, mode2))
-    op0 = copy_to_mode_reg (mode2, op0);
-  if (! (*insn_data[icode].operand[0].predicate) (op1, mode0))
-    op1 = copy_to_mode_reg (mode0, op1);
-  if (! (*insn_data[icode].operand[1].predicate) (op2, mode1))
-    op2 = copy_to_mode_reg (mode1, op2);
+  if (! (*insn_data[icode].operand[1].predicate) (op0, tmode))
+    op0 = copy_to_mode_reg (tmode, op0);
+
+  op2 = copy_to_mode_reg (mode2, op2); 
+
+  if (op1 == const0_rtx)
+    {
+      addr = gen_rtx_MEM (tmode, op2);
+    }
+  else
+    {
+      op1 = copy_to_mode_reg (mode1, op1);
+      addr = gen_rtx_MEM (tmode, gen_rtx_PLUS (Pmode, op1, op2));
+    }
 
-  pat = GEN_FCN (icode) (op1, op2, op0);
+  pat = GEN_FCN (icode) (addr, op0);
   if (pat)
     emit_insn (pat);
   return NULL_RTX;
@@ -5304,7 +5895,7 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
          }
 
        if (! (*insn_data[d->icode].operand[0].predicate) (op0, mode0))
-         op0 = copy_to_mode_reg (mode0, op0);
+         op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
        if (! (*insn_data[d->icode].operand[1].predicate) (op1, mode1))
          op1 = copy_to_mode_reg (mode1, op1);
 
@@ -5439,25 +6030,25 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LVSL:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsl,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
                                           arglist, target);
     case ALTIVEC_BUILTIN_LVSR:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvsr,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
                                          arglist, target);
     case ALTIVEC_BUILTIN_LVEBX:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvebx,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
                                          arglist, target);
     case ALTIVEC_BUILTIN_LVEHX:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvehx,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
                                          arglist, target);
     case ALTIVEC_BUILTIN_LVEWX:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvewx,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
                                          arglist, target);
     case ALTIVEC_BUILTIN_LVXL:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvxl,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
                                          arglist, target);
     case ALTIVEC_BUILTIN_LVX:
-      return rs6000_expand_binop_builtin (CODE_FOR_altivec_lvx,
+      return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
                                          arglist, target);
     default:
       break;
@@ -6168,27 +6759,27 @@ altivec_init_builtins (void)
   tree void_ftype_qi
     = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
 
-  tree v16qi_ftype_int_pcvoid
+  tree v16qi_ftype_long_pcvoid
     = build_function_type_list (V16QI_type_node,
-                               integer_type_node, pcvoid_type_node, NULL_TREE);
-  tree v8hi_ftype_int_pcvoid
+                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+  tree v8hi_ftype_long_pcvoid
     = build_function_type_list (V8HI_type_node,
-                               integer_type_node, pcvoid_type_node, NULL_TREE);
-  tree v4si_ftype_int_pcvoid
+                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
+  tree v4si_ftype_long_pcvoid
     = build_function_type_list (V4SI_type_node,
-                               integer_type_node, pcvoid_type_node, NULL_TREE);
+                               long_integer_type_node, pcvoid_type_node, NULL_TREE);
 
-  tree void_ftype_v4si_int_pvoid
+  tree void_ftype_v4si_long_pvoid
     = build_function_type_list (void_type_node,
-                               V4SI_type_node, integer_type_node,
+                               V4SI_type_node, long_integer_type_node,
                                pvoid_type_node, NULL_TREE);
-  tree void_ftype_v16qi_int_pvoid
+  tree void_ftype_v16qi_long_pvoid
     = build_function_type_list (void_type_node,
-                               V16QI_type_node, integer_type_node,
+                               V16QI_type_node, long_integer_type_node,
                                pvoid_type_node, NULL_TREE);
-  tree void_ftype_v8hi_int_pvoid
+  tree void_ftype_v8hi_long_pvoid
     = build_function_type_list (void_type_node,
-                               V8HI_type_node, integer_type_node,
+                               V8HI_type_node, long_integer_type_node,
                                pvoid_type_node, NULL_TREE);
   tree int_ftype_int_v8hi_v8hi
     = build_function_type_list (integer_type_node,
@@ -6235,18 +6826,18 @@ altivec_init_builtins (void)
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVSR);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEHX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVXL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_int_pcvoid, ALTIVEC_BUILTIN_LVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVEWX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_int_pvoid, ALTIVEC_BUILTIN_STVXL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_int_pvoid, ALTIVEC_BUILTIN_STVEBX);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_int_pvoid, ALTIVEC_BUILTIN_STVEHX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsl", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvsr", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVSR);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvebx", v16qi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvehx", v8hi_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEHX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvewx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvxl", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVXL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_lvx", v4si_ftype_long_pcvoid, ALTIVEC_BUILTIN_LVX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvewx", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVEWX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvxl", void_ftype_v4si_long_pvoid, ALTIVEC_BUILTIN_STVXL);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvebx", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_STVEBX);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_stvehx", void_ftype_v8hi_long_pvoid, ALTIVEC_BUILTIN_STVEHX);
 
   /* Add the DST variants.  */
   d = (struct builtin_description *) bdesc_dst;
@@ -6773,6 +7364,57 @@ rs6000_common_init_builtins (void)
     }
 }
 
+static void
+rs6000_init_libfuncs (void)
+{
+  if (!TARGET_HARD_FLOAT)
+    return;
+
+  if (DEFAULT_ABI != ABI_V4)
+    {
+      if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC)
+       {
+         /* AIX library routines for float->int conversion.  */
+         set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
+         set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
+         set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
+         set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
+       }
+
+      /* 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");
+    }
+  else
+    {
+      /* 32-bit SVR4 quad floating point routines.  */
+
+      set_optab_libfunc (add_optab, TFmode, "_q_add");
+      set_optab_libfunc (sub_optab, TFmode, "_q_sub");
+      set_optab_libfunc (neg_optab, TFmode, "_q_neg");
+      set_optab_libfunc (smul_optab, TFmode, "_q_mul");
+      set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
+      if (TARGET_PPC_GPOPT || TARGET_POWER2)
+       set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
+
+      set_optab_libfunc (eq_optab, TFmode, "_q_feq");
+      set_optab_libfunc (ne_optab, TFmode, "_q_fne");
+      set_optab_libfunc (gt_optab, TFmode, "_q_fgt");
+      set_optab_libfunc (ge_optab, TFmode, "_q_fge");
+      set_optab_libfunc (lt_optab, TFmode, "_q_flt");
+      set_optab_libfunc (le_optab, TFmode, "_q_fle");
+
+      set_conv_libfunc (sext_optab, TFmode, SFmode, "_q_stoq");
+      set_conv_libfunc (sext_optab, TFmode, DFmode, "_q_dtoq");
+      set_conv_libfunc (trunc_optab, SFmode, TFmode, "_q_qtos");
+      set_conv_libfunc (trunc_optab, DFmode, TFmode, "_q_qtod");
+      set_conv_libfunc (sfix_optab, SImode, TFmode, "_q_qtoi");
+      set_conv_libfunc (ufix_optab, SImode, TFmode, "_q_qtou");
+      set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
+    }
+}
 \f
 /* Expand a block move operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
@@ -7757,7 +8399,8 @@ addrs_ok_for_quad_peep (rtx addr1, rtx addr2)
 
 enum reg_class
 secondary_reload_class (enum reg_class class, 
-               enum machine_mode mode ATTRIBUTE_UNUSED, rtx in)
+                       enum machine_mode mode ATTRIBUTE_UNUSED,
+                       rtx in)
 {
   int regno;
 
@@ -9211,7 +9854,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
     s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
 
   /* We need to escape any '%' characters in the reg_names string.
-     Assume they'd only be the first character...  */
+     Assume they'd only be the first character....  */
   if (reg_names[cc_regno + CR0_REGNO][0] == '%')
     *s++ = '%';
   s += sprintf (s, "%s", reg_names[cc_regno + CR0_REGNO]);
@@ -9244,7 +9887,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
   enum machine_mode result_mode = GET_MODE (dest);
   rtx temp;
 
-  /* These modes should always match. */
+  /* These modes should always match.  */
   if (GET_MODE (op1) != compare_mode
       /* In the isel case however, we can use a compare immediate, so
         op1 may be a small constant.  */
@@ -9256,7 +9899,7 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
     return 0;
 
   /* First, work out if the hardware can do this at all, or
-     if it's too slow...  */
+     if it's too slow....  */
   if (! rs6000_compare_fp_p)
     {
       if (TARGET_ISEL)
@@ -9462,79 +10105,141 @@ rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
     emit_move_insn (dest, target);
 }
 
-/* Called by altivec splitter.
-   Input: 
-          operands[0] : Destination of move
-          operands[1] : Source of move
-         noperands   : Size of operands vector
-   Output:
-         operands[2-5] ([2-3] in 64 bit) : Destination slots
-         operands[6-9] ([4-5] in 64 bit) : Source slots
-
-   Splits the move of operands[1] to operands[0].
-   This is done, if GPRs are one of the operands.  In this case
-   a sequence of simple move insns has to be issued.  The sequence of these
-   move insns has to be done in correct order to avoid early clobber of the
-   base register or destructive overlap of registers. 
-*/
-         
+/* Emit instructions to move SRC to DST.  Called by splitters for
+   multi-register moves.  It will emit at most one instruction for
+   each register that is accessed; that is, it won't emit li/lis pairs
+   (or equivalent for 64-bit code).  One of SRC or DST must be a hard
+   register.  */
+
 void
-rs6000_split_altivec_in_gprs (rtx *operands)
+rs6000_split_multireg_move (rtx dst, rtx src)
 {
-    int nregs, reg, i, j;
-  enum machine_mode mode; 
-
-  /* Calculate number to move (2/4 for 32/64 bit mode).  */ 
-
-  reg = REG_P (operands[0]) ? REGNO (operands[0]) : REGNO (operands[1]); 
-  mode = GET_MODE (operands[0]);
-  nregs = HARD_REGNO_NREGS (reg, mode);                                  
-  
-  if (REG_P (operands[1]) 
-      && REG_P (operands[0]) 
-      && (REGNO (operands[1]) < REGNO (operands[0])))
-    {  
-      /* Move register range backwards, if we have destructive overlap.  */
-
-      j = nregs;
-      for (i = 0; i < nregs; i++)
-        {
-          j--;
-          operands[i + 2] = operand_subword (operands[0], j, 0, mode);
-          operands[i + 2 + nregs] = 
-            operand_subword (operands[1], j, 0, mode);   
-        }
-    }     
+  /* The register number of the first register being moved.  */
+  int reg;
+  /* The mode that is to be moved.  */
+  enum machine_mode mode;
+  /* The mode that the move is being done in, and its size.  */
+  enum machine_mode reg_mode;
+  int reg_mode_size;
+  /* The number of registers that will be moved.  */
+  int nregs;
+
+  reg = REG_P (dst) ? REGNO (dst) : REGNO (src);
+  mode = GET_MODE (dst);
+  nregs = HARD_REGNO_NREGS (reg, mode);
+  if (FP_REGNO_P (reg))
+    reg_mode = DFmode;
+  else if (ALTIVEC_REGNO_P (reg))
+    reg_mode = V16QImode;
+  else
+    reg_mode = word_mode;
+  reg_mode_size = GET_MODE_SIZE (reg_mode);
+  
+  if (reg_mode_size * nregs != GET_MODE_SIZE (mode))
+    abort ();
+  
+  if (REG_P (src) && REG_P (dst) && (REGNO (src) < REGNO (dst)))
+    {
+      /* Move register range backwards, if we might have destructive
+        overlap.  */
+      int i;
+      for (i = nregs - 1; i >= 0; i--)
+       emit_insn (gen_rtx_SET (VOIDmode, 
+                               simplify_gen_subreg (reg_mode, dst, mode,
+                                                    i * reg_mode_size),
+                               simplify_gen_subreg (reg_mode, src, mode,
+                                                    i * reg_mode_size)));
+    }
   else
     {
-      j = -1;
+      int i;
+      int j = -1;
+      bool used_update = false;
 
-      if (GET_CODE (operands[1]) == MEM)
+      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
         {
           rtx breg;
-          /* We have offsettable addresses only. If we use one of the
-             registers to address memory, we have change that register last.  */            
-          breg = GET_CODE (XEXP (operands[1], 0)) == PLUS ?
-              XEXP (XEXP (operands[1], 0), 0) :
-              XEXP (operands[1], 0);
-
-          if (REGNO (breg) >= REGNO (operands[0]) 
-              && REGNO (breg) < REGNO (operands[0]) + nregs)
-              j = REGNO (breg) - REGNO (operands[0]);
-        }
 
-      for (i = 0; i < nregs; i++)
-        { 
-          /* Calculate index to next subword.  */
-          j++;
-          if (j == nregs) 
-            j = 0;
+         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))); 
+             emit_insn (TARGET_32BIT
+                        ? gen_addsi3 (breg, breg, delta_rtx)
+                        : gen_adddi3 (breg, breg, delta_rtx));
+             src = gen_rtx_MEM (mode, breg);
+           }
+
+         /* 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.  */
 
-          operands[i + 2] = operand_subword (operands[0], j, 0, mode);
-          operands[i + 2 + nregs] = 
-            operand_subword (operands[1], j, 0, mode);
+         breg = (GET_CODE (XEXP (src, 0)) == PLUS
+                 ? XEXP (XEXP (src, 0), 0)
+                 : XEXP (src, 0));
 
+         if (!REG_P (breg))
+             abort();
+
+         if (REGNO (breg) >= REGNO (dst) 
+             && REGNO (breg) < REGNO (dst) + nregs)
+           j = REGNO (breg) - REGNO (dst);
         }
+
+      if (GET_CODE (dst) == MEM && INT_REGNO_P (reg))
+       {
+         rtx breg;
+
+         if (GET_CODE (XEXP (dst, 0)) == PRE_INC
+             || GET_CODE (XEXP (dst, 0)) == PRE_DEC)
+           {
+             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))); 
+
+             /* We have to update the breg before doing the store.
+                Use store with update, if available.  */
+
+             if (TARGET_UPDATE)
+               {
+                 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));
+                 used_update = true;
+               }
+             else
+               emit_insn (TARGET_32BIT
+                          ? gen_addsi3 (breg, breg, delta_rtx)
+                          : gen_adddi3 (breg, breg, delta_rtx));
+             dst = gen_rtx_MEM (mode, breg);
+           }
+       }
+
+      for (i = 0; i < nregs; i++)
+       {  
+         /* Calculate index to next subword.  */
+         ++j;
+         if (j == nregs) 
+           j = 0;
+
+         /* If compiler already emited move of first word by 
+            store with update, no need to do anything.  */
+         if (j == 0 && used_update)
+           continue;
+         
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 simplify_gen_subreg (reg_mode, dst, mode,
+                                                      j * reg_mode_size),
+                                 simplify_gen_subreg (reg_mode, src, mode,
+                                                      j * reg_mode_size)));
+       }
     }
 }
 
@@ -9625,7 +10330,7 @@ compute_vrsave_mask (void)
      them in again.  More importantly, the mask we compute here is
      used to generate CLOBBERs in the set_vrsave insn, and we do not
      wish the argument registers to die.  */
-  for (i = cfun->args_info.vregno; i >= ALTIVEC_ARG_MIN_REG; --i)
+  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
     mask &= ~ALTIVEC_REG_BIT (i);
 
   /* Similarly, remove the return value from the set.  */
@@ -9745,14 +10450,14 @@ is_altivec_return_reg (rtx reg, void *xyes)
 #define ABI_STACK_BOUNDARY STACK_BOUNDARY
 #endif
 
-rs6000_stack_t *
+static rs6000_stack_t *
 rs6000_stack_info (void)
 {
   static rs6000_stack_t info, zero_info;
   rs6000_stack_t *info_ptr = &info;
   int reg_size = TARGET_POWERPC64 ? 8 : 4;
   int ehrd_size;
-  int total_raw_size;
+  HOST_WIDE_INT total_raw_size;
 
   /* Zero all fields portably.  */
   info = zero_info;
@@ -9869,16 +10574,15 @@ rs6000_stack_info (void)
   else
     info_ptr->spe_gp_size = 0;
 
-  if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE)
-    {
-      info_ptr->vrsave_mask = compute_vrsave_mask ();
-      info_ptr->vrsave_size  = info_ptr->vrsave_mask ? 4 : 0;
-    }
+  if (TARGET_ALTIVEC_ABI)
+    info_ptr->vrsave_mask = compute_vrsave_mask ();
   else
-    {
-      info_ptr->vrsave_mask = 0;
-      info_ptr->vrsave_size = 0;
-    }
+    info_ptr->vrsave_mask = 0;
+
+  if (TARGET_ALTIVEC_VRSAVE && info_ptr->vrsave_mask)
+    info_ptr->vrsave_size  = 4;
+  else
+    info_ptr->vrsave_size  = 0;
 
   /* Calculate the offsets.  */
   switch (DEFAULT_ABI)
@@ -10084,7 +10788,7 @@ spe_func_has_64bit_regs_p (void)
   return false;
 }
 
-void
+static void
 debug_stack_info (rs6000_stack_t *info)
 {
   const char *abi_string;
@@ -10173,13 +10877,15 @@ debug_stack_info (rs6000_stack_t *info)
     fprintf (stderr, "\tvarargs_save_offset = %5d\n", info->varargs_save_offset);
 
   if (info->total_size)
-    fprintf (stderr, "\ttotal_size          = %5d\n", info->total_size);
+    fprintf (stderr, "\ttotal_size          = "HOST_WIDE_INT_PRINT_DEC"\n",
+            info->total_size);
 
   if (info->varargs_size)
     fprintf (stderr, "\tvarargs_size        = %5d\n", info->varargs_size);
 
   if (info->vars_size)
-    fprintf (stderr, "\tvars_size           = %5d\n", info->vars_size);
+    fprintf (stderr, "\tvars_size           = "HOST_WIDE_INT_PRINT_DEC"\n",
+            info->vars_size);
 
   if (info->parm_size)
     fprintf (stderr, "\tparm_size           = %5d\n", info->parm_size);
@@ -10305,7 +11011,7 @@ rs6000_ra_ever_killed (void)
   /* regs_ever_live has LR marked as used if any sibcalls are present,
      but this should not force saving and restoring in the
      pro/epilogue.  Likewise, reg_set_between_p thinks a sibcall
-     clobbers LR, so that is inappropriate. */
+     clobbers LR, so that is inappropriate.  */
 
   /* Also, the prologue can generate a store into LR that
      doesn't really count, like this:
@@ -10452,22 +11158,58 @@ rs6000_emit_load_toc_table (int fromprolog)
     abort ();
 }
 
+/* Emit instructions to restore the link register after determining where
+   its value has been stored.  */
+
+void
+rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
+{
+  rs6000_stack_t *info = rs6000_stack_info ();
+  rtx operands[2];
+
+  operands[0] = source;
+  operands[1] = scratch;
+
+  if (info->lr_save_p)
+    {
+      rtx frame_rtx = stack_pointer_rtx;
+      HOST_WIDE_INT sp_offset = 0;
+      rtx tmp;
+
+      if (frame_pointer_needed
+         || current_function_calls_alloca
+         || info->total_size > 32767)
+       {
+         emit_move_insn (operands[1], gen_rtx_MEM (Pmode, frame_rtx));
+         frame_rtx = operands[1];
+       }
+      else if (info->push_p)
+       sp_offset = info->total_size;
+
+      tmp = plus_constant (frame_rtx, info->lr_save_offset + sp_offset);
+      tmp = gen_rtx_MEM (Pmode, tmp);
+      emit_move_insn (tmp, operands[0]);
+    }
+  else
+    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
+}
+
+static GTY(()) int set = -1;
+
 int   
 get_TOC_alias_set (void)
 {
-    static int set = -1;
-    if (set == -1)
-      set = new_alias_set ();
-    return set;
+  if (set == -1)
+    set = new_alias_set ();
+  return set;
 }   
 
 /* This returns nonzero if the current function uses the TOC.  This is
-   determined by the presence of (unspec ... UNSPEC_TOC) or
-   use (unspec ... UNSPEC_TOC), which are generated by the various
-   load_toc_* patterns.  */
-
-int
-uses_TOC () 
+   determined by the presence of (use (unspec ... UNSPEC_TOC)), which
+   is generated by the ABI_V4 load_toc_* patterns.  */
+#if TARGET_ELF
+static int
+uses_TOC (void) 
 {
   rtx insn;
 
@@ -10492,6 +11234,7 @@ uses_TOC ()
       }
   return 0;
 }
+#endif
 
 rtx
 create_TOC_reference (rtx symbol) 
@@ -10850,7 +11593,7 @@ generate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
 
 static void
 emit_frame_save (rtx frame_reg, rtx frame_ptr, enum machine_mode mode, 
-                unsigned int regno, int offset, int total_size)
+                unsigned int regno, int offset, HOST_WIDE_INT total_size)
 {
   rtx reg, offset_rtx, insn, mem, addr, int_rtx;
   rtx replacea, replaceb;
@@ -10915,12 +11658,12 @@ void
 rs6000_emit_prologue (void)
 {
   rs6000_stack_t *info = rs6000_stack_info ();
-  enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
-  int reg_size = TARGET_POWERPC64 ? 8 : 4;
+  enum machine_mode reg_mode = Pmode;
+  int reg_size = UNITS_PER_WORD;
   rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
   rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
   rtx frame_reg_rtx = sp_reg_rtx;
-  rtx cr_save_rtx = NULL;
+  rtx cr_save_rtx = NULL_RTX;
   rtx insn;
   int saving_FPRs_inline;
   int using_store_multiple;
@@ -11002,7 +11745,8 @@ rs6000_emit_prologue (void)
      used in this function, and do the corresponding magic in the
      epilogue.  */
 
-  if (TARGET_ALTIVEC && info->vrsave_mask != 0)
+  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0)
     {
       rtx reg, mem, vrsave;
       int offset;
@@ -11343,7 +12087,7 @@ rs6000_output_function_prologue (FILE *file,
       rs6000_emit_prologue ();
       emit_note (NOTE_INSN_DELETED);
 
-      /* Expand INSN_ADDRESSES so final() doesn't crash. */
+      /* Expand INSN_ADDRESSES so final() doesn't crash.  */
       {
        rtx insn;
        unsigned addr = 0;
@@ -11381,8 +12125,8 @@ rs6000_emit_epilogue (int sibcall)
   int sp_offset = 0;
   rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
   rtx frame_reg_rtx = sp_reg_rtx;
-  enum machine_mode reg_mode = TARGET_POWERPC64 ? DImode : SImode;
-  int reg_size = TARGET_POWERPC64 ? 8 : 4;
+  enum machine_mode reg_mode = Pmode;
+  int reg_size = UNITS_PER_WORD;
   int i;
 
   info = rs6000_stack_info ();
@@ -11464,7 +12208,8 @@ rs6000_emit_epilogue (int sibcall)
     }
 
   /* Restore VRSAVE if needed.  */
-  if (TARGET_ALTIVEC_ABI && info->vrsave_mask != 0)
+  if (TARGET_ALTIVEC_ABI && TARGET_ALTIVEC_VRSAVE 
+      && info->vrsave_mask != 0)
     {
       rtx addr, mem, reg;
 
@@ -11775,7 +12520,7 @@ rs6000_output_function_epilogue (FILE *file,
          rs6000_emit_epilogue (FALSE);
          emit_note (NOTE_INSN_DELETED);
 
-         /* Expand INSN_ADDRESSES so final() doesn't crash. */
+         /* Expand INSN_ADDRESSES so final() doesn't crash.  */
          {
            rtx insn;
            unsigned addr = 0;
@@ -11793,7 +12538,8 @@ rs6000_output_function_epilogue (FILE *file,
        }
     }
 
-#if TARGET_OBJECT_FORMAT == OBJECT_MACHO
+#if TARGET_MACHO
+  macho_branch_islands ();
   /* Mach-O doesn't support labels at the end of objects, so if
      it looks like we might want one, insert a NOP.  */
   {
@@ -11868,27 +12614,25 @@ rs6000_output_function_epilogue (FILE *file,
       /* Tbtab format type.  Use format type 0.  */
       fputs ("\t.byte 0,", file);
 
-      /* Language type.  Unfortunately, there doesn't seem to be any
-        official way to get this info, so we use language_string.  C
-        is 0.  C++ is 9.  No number defined for Obj-C, so use the
-        value for C for now.  There is no official value for Java,
-         although IBM appears to be using 13.  There is no official value
-        for Chill, so we've chosen 44 pseudo-randomly.  */
-      if (! strcmp (language_string, "GNU C")
-         || ! strcmp (language_string, "GNU Objective-C"))
+      /* Language type.  Unfortunately, there does not seem to be any
+        official way to discover the language being compiled, so we
+        use language_string.
+        C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
+        Java is 13.  Objective-C is 14.  */
+      if (! strcmp (language_string, "GNU C"))
        i = 0;
       else if (! strcmp (language_string, "GNU F77"))
        i = 1;
-      else if (! strcmp (language_string, "GNU Ada"))
-       i = 3;
       else if (! strcmp (language_string, "GNU Pascal"))
        i = 2;
+      else if (! strcmp (language_string, "GNU Ada"))
+       i = 3;
       else if (! strcmp (language_string, "GNU C++"))
        i = 9;
       else if (! strcmp (language_string, "GNU Java"))
        i = 13;
-      else if (! strcmp (language_string, "GNU CHILL"))
-       i = 44;
+      else if (! strcmp (language_string, "GNU Objective-C"))
+       i = 14;
       else
        abort ();
       fprintf (file, "%d,", i);
@@ -12860,7 +13604,7 @@ output_function_profiler (FILE *file, int labelno)
     case ABI_DARWIN:
       if (!TARGET_PROFILE_KERNEL)
        {
-         /* Don't do anything, done in output_profile_hook (). */
+         /* Don't do anything, done in output_profile_hook ().  */
        }
       else
        {
@@ -12909,20 +13653,10 @@ rs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED,
 
   if (rs6000_cpu == PROCESSOR_POWER4)
     {
-      enum attr_type type = get_attr_type (insn);
-      if (type == TYPE_LOAD_EXT_U || type == TYPE_LOAD_EXT_UX
-         || type == TYPE_LOAD_UX || type == TYPE_STORE_UX
-         || type == TYPE_MFCR)
-       return 0;
-      else if (type == TYPE_LOAD_U || type == TYPE_STORE_U
-              || type == TYPE_FPLOAD_U || type == TYPE_FPSTORE_U
-              || type == TYPE_FPLOAD_UX || type == TYPE_FPSTORE_UX
-              || type == TYPE_LOAD_EXT || type == TYPE_DELAYED_CR
-              || type == TYPE_COMPARE || type == TYPE_DELAYED_COMPARE
-              || type == TYPE_IMUL_COMPARE || type == TYPE_LMUL_COMPARE
-              || type == TYPE_IDIV || type == TYPE_LDIV
-              || type == TYPE_INSERT_WORD)
-       return more > 2 ? more - 2 : 0;
+      if (is_microcoded_insn (insn))
+        return 0;
+      else if (is_cracked_insn (insn))
+        return more > 2 ? more - 2 : 0;
     }
 
   return more - 1;
@@ -12986,9 +13720,124 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn ATTRIBUTE_UNUSED,
   return cost;
 }
 
+/* The function returns a true if INSN is microcoded.
+   Return false otherwise.  */
+
+static bool
+is_microcoded_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn)
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return false;
+
+  if (rs6000_cpu == PROCESSOR_POWER4)
+    {
+      enum attr_type type = get_attr_type (insn);
+      if (type == TYPE_LOAD_EXT_U
+         || type == TYPE_LOAD_EXT_UX
+         || type == TYPE_LOAD_UX
+         || type == TYPE_STORE_UX
+         || type == TYPE_MFCR)
+        return true;
+    }
+
+  return false;
+}
+
+/* The function returns a nonzero value if INSN can be scheduled only
+   as the first insn in a dispatch group ("dispatch-slot restricted").
+   In this case, the returned value indicates how many dispatch slots
+   the insn occupies (at the beginning of the group).
+   Return 0 otherwise.  */
+
+static int
+is_dispatch_slot_restricted (rtx insn)
+{
+  enum attr_type type;
+
+  if (rs6000_cpu != PROCESSOR_POWER4)
+    return 0;
+
+  if (!insn
+      || insn == NULL_RTX
+      || GET_CODE (insn) == NOTE
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return 0;
+
+  type = get_attr_type (insn);
+
+  switch (type){
+  case TYPE_MFCR:
+  case TYPE_MFCRF:
+  case TYPE_MTCR:
+  case TYPE_DELAYED_CR:
+  case TYPE_CR_LOGICAL:
+  case TYPE_MTJMPR:
+  case TYPE_MFJMPR:
+    return 1;
+  case TYPE_IDIV:
+  case TYPE_LDIV:
+    return 2;
+  default:
+    return 0;
+  }
+}
+
+/* The function returns true if INSN is cracked into 2 instructions
+   by the processor (and therefore occupies 2 issue slots).  */
+
+static bool
+is_cracked_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn)
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return false;
+
+  if (rs6000_cpu == PROCESSOR_POWER4)
+    {
+      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;
+    }
+
+  return false;
+}
+
+/* The function returns true if INSN can be issued only from
+   the branch slot.  */
+
+static bool
+is_branch_slot_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn)
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return false;
+
+  if (rs6000_cpu == PROCESSOR_POWER4)
+    {
+      enum attr_type type = get_attr_type (insn);
+      if (type == TYPE_BRANCH || type == TYPE_JMPREG)
+       return true;     
+      return false;
+    }
+
+  return false;
+}
+
 /* A C statement (sans semicolon) to update the integer scheduling
-   priority INSN_PRIORITY (INSN).  Reduce the priority to execute the
-   INSN earlier, increase the priority to execute INSN later.  Do not
+   priority INSN_PRIORITY (INSN). Increase the priority to execute the
+   INSN earlier, reduce the priority to execute INSN later.  Do not
    define this macro if you do not need to adjust the scheduling
    priorities of insns.  */
 
@@ -13025,6 +13874,25 @@ rs6000_adjust_priority (rtx insn ATTRIBUTE_UNUSED, int priority)
   }
 #endif
 
+  if (is_dispatch_slot_restricted (insn)
+      && reload_completed
+      && current_sched_info->sched_max_insns_priority 
+      && rs6000_sched_restricted_insns_priority)
+    {
+
+      /* 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 
+          precede 'priority' (critical path) considerations.  */
+       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.  */
+       return (priority + 1); 
+    } 
+
   return priority;
 }
 
@@ -13054,8 +13922,9 @@ rs6000_issue_rate (void)
   case CPU_PPC604E:
   case CPU_PPC620:
   case CPU_PPC630:
-  case CPU_POWER4:
     return 4;
+  case CPU_POWER4:
+    return 5;
   default:
     return 1;
   }
@@ -13072,6 +13941,564 @@ rs6000_use_sched_lookahead (void)
   return 0;
 }
 
+/* Determine is PAT refers to memory.  */
+
+static bool
+is_mem_ref (rtx pat)
+{
+  const char * fmt;
+  int i, j;
+  bool ret = false;
+
+  if (GET_CODE (pat) == MEM)
+    return true;
+
+  /* Recursively process the pattern.  */
+  fmt = GET_RTX_FORMAT (GET_CODE (pat));
+
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0 && !ret; i--)
+    {
+      if (fmt[i] == 'e')
+       ret |= is_mem_ref (XEXP (pat, i));
+      else if (fmt[i] == 'E')
+       for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+         ret |= is_mem_ref (XVECEXP (pat, i, j));
+    }
+
+  return ret;
+}
+
+/* Determine if PAT is a PATTERN of a load insn.  */
+static bool
+is_load_insn1 (rtx pat)
+{
+  if (!pat || pat == NULL_RTX)
+    return false;
+
+  if (GET_CODE (pat) == SET)
+    return is_mem_ref (SET_SRC (pat));
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       if (is_load_insn1 (XVECEXP (pat, 0, i)))
+         return true;
+    }
+
+  return false;
+}
+
+/* Determine if INSN loads from memory.  */
+
+static bool
+is_load_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  if (GET_CODE (insn) == CALL_INSN)
+    return false;
+
+  return is_load_insn1 (PATTERN (insn));
+}
+
+/* Determine if PAT is a PATTERN of a store insn.  */
+
+static bool
+is_store_insn1 (rtx pat)
+{
+  if (!pat || pat == NULL_RTX)
+    return false;
+
+  if (GET_CODE (pat) == SET)
+    return is_mem_ref (SET_DEST (pat));
+
+  if (GET_CODE (pat) == PARALLEL)
+    {
+      int i;
+
+      for (i = 0; i < XVECLEN (pat, 0); i++)
+       if (is_store_insn1 (XVECEXP (pat, 0, i)))
+         return true;
+    }
+
+  return false;
+}
+
+/* Determine if INSN stores to memory.  */
+
+static bool
+is_store_insn (rtx insn)
+{
+  if (!insn || !INSN_P (insn))
+    return false;
+
+  return is_store_insn1 (PATTERN (insn));
+}
+
+/* Returns whether the dependence between INSN and NEXT is considered
+   costly by the given target.  */
+
+static bool
+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. 
+     This is the most aggressive option.  */
+  if (rs6000_sched_costly_dep == no_dep_costly)
+    return false;
+
+  /* If the flag is set to 1 - a dependence is always considered costly; 
+     do not allow dependent instructions in the same group.
+     This is the most conservative option.  */
+  if (rs6000_sched_costly_dep == all_deps_costly)
+    return true;       
+
+  if (rs6000_sched_costly_dep == store_to_load_dep_costly 
+      && is_load_insn (next) 
+      && is_store_insn (insn))
+    /* Prevent load after store in the same group.  */
+    return true;
+
+  if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
+      && 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.  */
+     return true;
+    
+  /* The flag is set to X; dependences with latency >= X are considered costly, 
+     and will not be scheduled in the same group.  */
+  if (rs6000_sched_costly_dep <= max_dep_latency
+      && ((cost - distance) >= (int)rs6000_sched_costly_dep))
+    return true;
+
+  return false;
+}
+
+/* Return the next insn after INSN that is found before TAIL is reached, 
+   skipping any "non-active" insns - insns that will not actually occupy
+   an issue slot.  Return NULL_RTX if such an insn is not found.  */
+
+static rtx
+get_next_active_insn (rtx insn, rtx tail)
+{
+  rtx next_insn;
+
+  if (!insn || insn == tail)
+    return NULL_RTX;
+
+  next_insn = NEXT_INSN (insn);
+
+  while (next_insn
+        && next_insn != tail
+        && (GET_CODE(next_insn) == NOTE
+            || GET_CODE (PATTERN (next_insn)) == USE
+            || GET_CODE (PATTERN (next_insn)) == CLOBBER))
+    {
+      next_insn = NEXT_INSN (next_insn);
+    }
+
+  if (!next_insn || next_insn == tail)
+    return NULL_RTX;
+
+  return next_insn;
+}
+
+/* Return whether the presence of INSN causes a dispatch group termination
+   of group WHICH_GROUP.
+
+   If WHICH_GROUP == current_group, this function will return true if INSN
+   causes the termination of the current group (i.e, the dispatch group to
+   which INSN belongs). This means that INSN will be the last insn in the
+   group it belongs to.
+
+   If WHICH_GROUP == previous_group, this function will return true if INSN
+   causes the termination of the previous group (i.e, the dispatch group that
+   precedes the group to which INSN belongs).  This means that INSN will be
+   the first insn in the group it belongs to).  */
+
+static bool
+insn_terminates_group_p (rtx insn, enum group_termination which_group)
+{
+  enum attr_type type;
+
+  if (! insn)
+    return false;
+
+  type = get_attr_type (insn);
+
+  if (is_microcoded_insn (insn))
+    return true;
+
+  if (which_group == current_group)
+    {
+      if (is_branch_slot_insn (insn))
+        return true;
+      return false;
+    }
+  else if (which_group == previous_group)
+    {
+      if (is_dispatch_slot_restricted (insn))
+        return true;
+      return false;
+    }
+
+  return false;
+}
+
+/* Return true if it is recommended to keep NEXT_INSN "far" (in a separate
+   dispatch group) from the insns in GROUP_INSNS.  Return false otherwise.  */
+
+static bool
+is_costly_group (rtx *group_insns, rtx next_insn)
+{
+  int i;
+  rtx link;
+  int cost;
+  int issue_rate = rs6000_issue_rate ();
+
+  for (i = 0; i < issue_rate; i++)
+    {
+      rtx insn = group_insns[i];
+      if (!insn)
+        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;
+            }
+        }
+    }
+
+  return false;
+}
+
+/* Utility of the function redefine_groups. 
+   Check if it is too costly to schedule NEXT_INSN together with GROUP_INSNS
+   in the same dispatch group.  If so, insert nops before NEXT_INSN, in order
+   to keep it "far" (in a separate group) from GROUP_INSNS, following
+   one of the following schemes, depending on the value of the flag
+   -minsert_sched_nops = X:
+   (1) X == sched_finish_regroup_exact: insert exactly as many nops as needed
+       in order to force NEXT_INSN into a separate group.
+   (2) X < sched_finish_regroup_exact: insert exactly X nops.  
+   GROUP_END, CAN_ISSUE_MORE and GROUP_COUNT record the state after nop 
+   insertion (has a group just ended, how many vacant issue slots remain in the
+   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)
+{
+  rtx nop;
+  bool force;
+  int issue_rate = rs6000_issue_rate ();
+  bool end = *group_end;
+  int i;
+
+  if (next_insn == NULL_RTX)
+    return can_issue_more;
+
+  if (rs6000_sched_insert_nops > sched_finish_regroup_exact)
+    return can_issue_more;
+
+  force = is_costly_group (group_insns, next_insn);
+  if (!force)
+    return can_issue_more;
+
+  if (sched_verbose > 6)
+    fprintf (dump,"force: group count = %d, can_issue_more = %d\n",
+                       *group_count ,can_issue_more);
+
+  if (rs6000_sched_insert_nops == sched_finish_regroup_exact)
+    {
+      if (*group_end)
+        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.  */
+      if (can_issue_more && !is_branch_slot_insn (next_insn))
+        can_issue_more--;
+
+      while (can_issue_more > 0)
+        {
+          nop = gen_nop();
+          emit_insn_before (nop, next_insn);
+          can_issue_more--;
+        }
+
+      *group_end = true;
+      return 0;
+    } 
+
+  if (rs6000_sched_insert_nops < sched_finish_regroup_exact)
+    {
+      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'.  */
+      if (can_issue_more == 0)
+        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;
+            }
+        }
+
+      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--;
+        }
+
+      /* 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 
+          || (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)));
+      if (*group_end && end)
+        (*group_count)--;
+
+      if (sched_verbose > 6)
+        fprintf (dump, "done force: group count = %d, can_issue_more = %d\n",
+                       *group_count, can_issue_more);
+      return can_issue_more;   
+    } 
+
+  return can_issue_more;
+}
+
+/* This function tries to synch the dispatch groups that the compiler "sees"
+   with the dispatch groups that the processor dispatcher is expected to 
+   form in practice.  It tries to achieve this synchronization by forcing the
+   estimated processor grouping on the compiler (as opposed to the function
+   'pad_goups' which tries to force the scheduler's grouping on the processor).
+
+   The function scans the insn sequence between PREV_HEAD_INSN and TAIL and
+   examines the (estimated) dispatch groups that will be formed by the processor
+   dispatcher.  It marks these group boundaries to reflect the estimated
+   processor grouping, overriding the grouping that the scheduler had marked.
+   Depending on the value of the flag '-minsert-sched-nops' this function can
+   force certain insns into separate groups or force a certain distance between
+   them by inserting nops, for example, if there exists a "costly dependence"
+   between the insns.
+
+   The function estimates the group boundaries that the processor will form as
+   folllows:  It keeps track of how many vacant issue slots are available after
+   each insn.  A subsequent insn will start a new group if one of the following
+   4 cases applies:
+   - no more vacant issue slots remain in the current dispatch group.
+   - only the last issue slot, which is the branch slot, is vacant, but the next
+     insn is not a branch.
+   - only the last 2 or less issue slots, including the branch slot, are vacant,
+     which means that a cracked insn (which occupies two issue slots) can't be
+     issued in this group.
+   - less than 'issue_rate' slots are vacant, and the next insn always needs to 
+     start a new group.  */
+
+static int
+redefine_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
+{
+  rtx insn, next_insn;
+  int issue_rate;
+  int can_issue_more;
+  int slot, i;
+  bool group_end;
+  int group_count = 0;
+  rtx *group_insns;
+
+  /* Initialize.  */
+  issue_rate = rs6000_issue_rate ();
+  group_insns = alloca (issue_rate * sizeof (rtx));
+  for (i = 0; i < issue_rate; i++) 
+    {
+      group_insns[i] = 0;
+    }
+  can_issue_more = issue_rate;
+  slot = 0;
+  insn = get_next_active_insn (prev_head_insn, tail);
+  group_end = false;
+
+  while (insn != NULL_RTX)
+    {
+      slot = (issue_rate - can_issue_more);
+      group_insns[slot] = 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;
+
+      next_insn = get_next_active_insn (insn, tail);
+      if (next_insn == NULL_RTX)
+        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)));
+
+      can_issue_more = force_new_group (sched_verbose, dump, group_insns, 
+                       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;
+            }
+        }
+
+      if (GET_MODE (next_insn) == TImode && can_issue_more)
+        PUT_MODE(next_insn, VOIDmode);
+      else if (!can_issue_more && GET_MODE (next_insn) != TImode)
+        PUT_MODE (next_insn, TImode);
+
+      insn = next_insn;
+      if (can_issue_more == 0)
+        can_issue_more = issue_rate;
+   } /* while */
+
+  return group_count;
+}
+
+/* Scan the insn sequence between PREV_HEAD_INSN and TAIL and examine the
+   dispatch group boundaries that the scheduler had marked.  Pad with nops
+   any dispatch groups which have vacant issue slots, in order to force the
+   scheduler's grouping on the processor dispatcher.  The function
+   returns the number of dispatch groups found.  */
+
+static int
+pad_groups (FILE *dump, int sched_verbose, rtx prev_head_insn, rtx tail)
+{
+  rtx insn, next_insn;
+  rtx nop;
+  int issue_rate;
+  int can_issue_more;
+  int group_end;
+  int group_count = 0;
+
+  /* Initialize issue_rate.  */
+  issue_rate = rs6000_issue_rate ();
+  can_issue_more = issue_rate;
+
+  insn = get_next_active_insn (prev_head_insn, tail);
+  next_insn = get_next_active_insn (insn, tail);
+
+  while (insn != NULL_RTX)
+    {
+      can_issue_more =
+       rs6000_variable_issue (dump, sched_verbose, insn, can_issue_more);
+
+      group_end = (next_insn == NULL_RTX || GET_MODE (next_insn) == TImode);
+
+      if (next_insn == NULL_RTX)
+        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++;
+        }
+
+      insn = next_insn;
+      next_insn = get_next_active_insn (insn, tail);
+    }
+
+  return group_count;
+}
+
+/* The following function is called at the end of scheduling BB.
+   After reload, it inserts nops at insn group bundling.  */
+
+static void
+rs6000_sched_finish (FILE *dump, int sched_verbose)
+{
+  int n_groups;
+
+  if (sched_verbose)
+    fprintf (dump, "=== Finishing schedule.\n");
+
+  if (reload_completed && rs6000_cpu == PROCESSOR_POWER4)
+    {
+      if (rs6000_sched_insert_nops == sched_finish_none)
+        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);
+      else
+        n_groups = redefine_groups (dump, sched_verbose,
+                               current_sched_info->prev_head,
+                               current_sched_info->next_tail);
+
+      if (sched_verbose >= 6)
+       {
+         fprintf (dump, "ngroups = %d\n", n_groups);
+         print_rtl (dump, current_sched_info->prev_head);
+         fprintf (dump, "Done finish_sched\n");
+       }
+    }
+}
 \f
 /* Length in units of the trampoline for entering a nested function.  */
 
@@ -13397,83 +14824,118 @@ symbolic_operand (rtx op)
 }
 #endif
 
-#ifdef RS6000_LONG_BRANCH
+#if TARGET_MACHO
 
-static tree stub_list = 0;
+static tree branch_island_list = 0;
 
-/* ADD_COMPILER_STUB adds the compiler generated stub for handling 
-   procedure calls to the linked list.  */
+/* Remember to generate a branch island for far calls to the given
+   function.  */
 
-void 
-add_compiler_stub (tree label_name, tree function_name, int line_number)
+static void 
+add_compiler_branch_island (tree label_name, tree function_name, int line_number)
 {
-  tree stub = build_tree_list (function_name, label_name);
-  TREE_TYPE (stub) = build_int_2 (line_number, 0);
-  TREE_CHAIN (stub) = stub_list;
-  stub_list = stub;
+  tree branch_island = build_tree_list (function_name, label_name);
+  TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
+  TREE_CHAIN (branch_island) = branch_island_list;
+  branch_island_list = branch_island;
 }
 
-#define STUB_LABEL_NAME(STUB)     TREE_VALUE (STUB)
-#define STUB_FUNCTION_NAME(STUB)  TREE_PURPOSE (STUB)
-#define STUB_LINE_NUMBER(STUB)    TREE_INT_CST_LOW (TREE_TYPE (STUB))
-
-/* OUTPUT_COMPILER_STUB outputs the compiler generated stub for
-   handling procedure calls from the linked list and initializes the
-   linked list.  */
+#define BRANCH_ISLAND_LABEL_NAME(BRANCH_ISLAND)     TREE_VALUE (BRANCH_ISLAND)
+#define BRANCH_ISLAND_FUNCTION_NAME(BRANCH_ISLAND)  TREE_PURPOSE (BRANCH_ISLAND)
+#define BRANCH_ISLAND_LINE_NUMBER(BRANCH_ISLAND)    \
+               TREE_INT_CST_LOW (TREE_TYPE (BRANCH_ISLAND))
 
-void
-output_compiler_stub (void)
-{
-  char tmp_buf[256];
-  char label_buf[256];
-  tree stub;
-
-  if (!flag_pic)
-    for (stub = stub_list; stub; stub = TREE_CHAIN (stub))
-      {
-       fprintf (asm_out_file,
-                "%s:\n", IDENTIFIER_POINTER(STUB_LABEL_NAME(stub)));
+/* Generate far-jump branch islands for everything on the
+   branch_island_list.  Invoked immediately after the last instruction
+   of the epilogue has been emitted; the branch-islands must be
+   appended to, and contiguous with, the function body.  Mach-O stubs
+   are generated in machopic_output_stub().  */
 
+static void
+macho_branch_islands (void)
+{
+  char tmp_buf[512];
+  tree branch_island;
+
+  for (branch_island = branch_island_list;
+       branch_island;
+       branch_island = TREE_CHAIN (branch_island))
+    {
+      const char *label =
+       IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
+      const char *name  =
+       darwin_strip_name_encoding (
+         IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
+      char name_buf[512];
+      /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF().  */
+      if (name[0] == '*' || name[0] == '&')
+       strcpy (name_buf, name+1);
+      else
+       {
+         name_buf[0] = '_';
+         strcpy (name_buf+1, name);
+       }
+      strcpy (tmp_buf, "\n");
+      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,%d\n", STUB_LINE_NUMBER(stub));
+      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));
 #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
-
-       if (IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))[0] == '*')
-         strcpy (label_buf,
-                 IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub))+1);
-       else
-         {
-           label_buf[0] = '_';
-           strcpy (label_buf+1,
-                   IDENTIFIER_POINTER (STUB_FUNCTION_NAME (stub)));
-         }
-
-       strcpy (tmp_buf, "lis r12,hi16(");
-       strcat (tmp_buf, label_buf);
-       strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
-       strcat (tmp_buf, label_buf);
-       strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
-       output_asm_insn (tmp_buf, 0);
-
+      if (flag_pic)
+       {
+         strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
+         strcat (tmp_buf, label);
+         strcat (tmp_buf, "_pic\n");
+         strcat (tmp_buf, label);
+         strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+         strcat (tmp_buf, "\taddis r11,r11,ha16(");
+         strcat (tmp_buf, name_buf);
+         strcat (tmp_buf, " - ");
+         strcat (tmp_buf, label);
+         strcat (tmp_buf, "_pic)\n");
+                  
+         strcat (tmp_buf, "\tmtlr r0\n");
+  
+         strcat (tmp_buf, "\taddi r12,r11,lo16(");
+         strcat (tmp_buf, name_buf);
+         strcat (tmp_buf, " - ");
+         strcat (tmp_buf, label);
+         strcat (tmp_buf, "_pic)\n");
+         strcat (tmp_buf, "\tmtctr r12\n\tbctr\n");
+       }
+      else
+       {
+         strcat (tmp_buf, ":\nlis r12,hi16(");
+         strcat (tmp_buf, name_buf);
+         strcat (tmp_buf, ")\n\tori r12,r12,lo16(");
+         strcat (tmp_buf, name_buf);
+         strcat (tmp_buf, ")\n\tmtctr r12\n\tbctr");
+       }
+      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,%d\n", STUB_LINE_NUMBER (stub));
+      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));
 #endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
-      }
+    }
 
-  stub_list = 0;
+  branch_island_list = 0;
 }
 
 /* NO_PREVIOUS_DEF checks in the link list whether the function name is
    already there or not.  */
 
-int
+static int
 no_previous_def (tree function_name)
 {
-  tree stub;
-  for (stub = stub_list; stub; stub = TREE_CHAIN (stub))
-    if (function_name == STUB_FUNCTION_NAME (stub))
+  tree branch_island;
+  for (branch_island = branch_island_list;
+       branch_island;
+       branch_island = TREE_CHAIN (branch_island))
+    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
       return 0;
   return 1;
 }
@@ -13481,13 +14943,15 @@ no_previous_def (tree function_name)
 /* GET_PREV_LABEL gets the label name from the previous definition of
    the function.  */
 
-tree
+static tree
 get_prev_label (tree function_name)
 {
-  tree stub;
-  for (stub = stub_list; stub; stub = TREE_CHAIN (stub))
-    if (function_name == STUB_FUNCTION_NAME (stub))
-      return STUB_LABEL_NAME (stub);
+  tree branch_island;
+  for (branch_island = branch_island_list;
+       branch_island;
+       branch_island = TREE_CHAIN (branch_island))
+    if (function_name == BRANCH_ISLAND_FUNCTION_NAME (branch_island))
+      return BRANCH_ISLAND_LABEL_NAME (branch_island);
   return 0;
 }
 
@@ -13497,13 +14961,14 @@ get_prev_label (tree function_name)
    CALL_DEST is the routine we are calling.  */
 
 char *
-output_call (rtx insn, rtx call_dest, int operand_number)
+output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
 {
   static char buf[256];
-  if (GET_CODE (call_dest) == SYMBOL_REF && TARGET_LONG_BRANCH && !flag_pic)
+  if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
+      && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
     {
       tree labelname;
-      tree funname = get_identifier (XSTR (call_dest, 0));
+      tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
       
       if (no_previous_def (funname))
        {
@@ -13517,23 +14982,25 @@ output_call (rtx insn, rtx call_dest, int operand_number)
          for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
          if (insn)
            line_number = NOTE_LINE_NUMBER (insn);
-         add_compiler_stub (labelname, funname, line_number);
+         add_compiler_branch_island (labelname, funname, line_number);
        }
       else
        labelname = get_prev_label (funname);
 
+      /* "jbsr foo, L42" is Mach-O for "Link as 'bl foo' if a 'bl'
+        instruction will reach 'foo', otherwise link as 'bl L42'".
+        "L42" should be a 'branch island', that will do a far jump to
+        'foo'.  Branch islands are generated in
+        macho_branch_islands().  */
       sprintf (buf, "jbsr %%z%d,%.246s",
-              operand_number, IDENTIFIER_POINTER (labelname));
-      return buf;
+              dest_operand_number, IDENTIFIER_POINTER (labelname));
     }
   else
-    {
-      sprintf (buf, "bl %%z%d", operand_number);
-      return buf;
-    }
+    sprintf (buf, "bl %%z%d", dest_operand_number);
+  return buf;
 }
 
-#endif /* RS6000_LONG_BRANCH */
+#endif /* TARGET_MACHO */
 
 /* Generate PIC and indirect symbol stubs.  */
 
@@ -13620,9 +15087,13 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
 
       if (GET_CODE (XEXP (orig, 0)) == PLUS)
        {
+         /* Use a different reg for the intermediate value, as
+            it will be marked UNCHANGING.  */
+         rtx reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+
          base =
            rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
-                                                   Pmode, reg);
+                                                   Pmode, reg_temp);
          offset =
            rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
                                                    Pmode, reg);
@@ -13665,14 +15136,8 @@ toc_section (void)
 static unsigned int
 rs6000_elf_section_type_flags (tree decl, const char *name, int reloc)
 {
-  unsigned int flags
-    = default_section_type_flags_1 (decl, name, reloc,
-                                   flag_pic || DEFAULT_ABI == ABI_AIX);
-
-  if (TARGET_RELOCATABLE)
-    flags |= SECTION_WRITE;
-
-  return flags;
+  return default_section_type_flags_1 (decl, name, reloc,
+                                      flag_pic || DEFAULT_ABI == ABI_AIX);
 }
 
 /* Record an element in the table of global constructors.  SYMBOL is
@@ -13769,7 +15234,7 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
 
   if (TARGET_RELOCATABLE
       && (get_pool_size () != 0 || current_function_profile)
-      && uses_TOC())
+      && uses_TOC ())
     {
       char buf[256];
 
@@ -14202,7 +15667,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED,
       return true;
 
     case MEM:
-      /* MEM should be slightly more expensive than (plus (reg) (const)) */
+      /* MEM should be slightly more expensive than (plus (reg) (const)) */
       *total = 5;
       return true;
 
@@ -14229,7 +15694,7 @@ 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;
 
@@ -14309,10 +15774,24 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
   enum machine_mode mode;
   unsigned int regno;
 
+  if (TARGET_32BIT && TARGET_POWERPC64 && TYPE_MODE (valtype) == 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 ((INTEGRAL_TYPE_P (valtype)
        && TYPE_PRECISION (valtype) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
-    mode = word_mode;
+    mode = TARGET_32BIT ? SImode : DImode;
   else
     mode = TYPE_MODE (valtype);
 
@@ -14350,6 +15829,28 @@ rs6000_libcall_value (enum machine_mode mode)
   return gen_rtx_REG (mode, regno);
 }
 
+/* Define the offset between two registers, FROM to be eliminated and its
+   replacement TO, at the start of a routine.  */
+HOST_WIDE_INT
+rs6000_initial_elimination_offset (int from, int to)
+{
+  rs6000_stack_t *info = rs6000_stack_info ();
+  HOST_WIDE_INT offset;
+
+  if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    offset = info->push_p ? 0 : -info->total_size;
+  else if (from == ARG_POINTER_REGNUM && to == FRAME_POINTER_REGNUM)
+    offset = info->total_size;
+  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    offset = info->push_p ? info->total_size : 0;
+  else if (from == RS6000_PIC_OFFSET_TABLE_REGNUM)
+    offset = 0;
+  else
+    abort ();
+
+  return offset;
+}
+
 /* Return true if TYPE is of type __ev64_opaque__.  */
 
 static bool
@@ -14385,4 +15886,39 @@ rs6000_dwarf_register_span (rtx reg)
                                   gen_rtx_REG (SImode, regno + 1200)));
 }
 
+/* Map internal gcc register numbers to DWARF2 register numbers.  */
+
+unsigned int
+rs6000_dbx_register_number (unsigned int regno)
+{
+  if (regno <= 63 || write_symbols != DWARF2_DEBUG)
+    return regno;
+  if (regno == MQ_REGNO)
+    return 100;
+  if (regno == LINK_REGISTER_REGNUM)
+    return 108;
+  if (regno == COUNT_REGISTER_REGNUM)
+    return 109;
+  if (CR_REGNO_P (regno))
+    return regno - CR0_REGNO + 86;
+  if (regno == XER_REGNO)
+    return 101;
+  if (ALTIVEC_REGNO_P (regno))
+    return regno - FIRST_ALTIVEC_REGNO + 1124;
+  if (regno == VRSAVE_REGNO)
+    return 356;
+  if (regno == VSCR_REGNO)
+    return 67;
+  if (regno == SPE_ACC_REGNO)
+    return 99;
+  if (regno == SPEFSCR_REGNO)
+    return 612;
+  /* SPE high reg number.  We get these values of regno from
+     rs6000_dwarf_register_span.  */
+  if (regno >= 1200 && regno < 1232)
+    return regno;
+
+  abort ();
+}
+
 #include "gt-rs6000.h"