OSDN Git Service

* config/rs6000/darwin.h (SUBTARGET_OPTIONS): Move from here, to...
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 391ef27..528d5e6 100644 (file)
@@ -79,6 +79,8 @@ typedef struct rs6000_stack {
   int toc_save_p;              /* true if the TOC needs to be saved */
   int push_p;                  /* true if we need to allocate stack space */
   int calls_p;                 /* true if the function makes any calls */
+  int world_save_p;             /* true if we're saving *everything*:
+                                  r13-r31, cr, f14-f31, vrsave, v20-v31  */
   enum rs6000_abi abi;         /* which ABI to use */
   int gp_save_offset;          /* offset to save GP regs from initial SP */
   int fp_save_offset;          /* offset to save FP regs from initial SP */
@@ -211,6 +213,9 @@ enum rs6000_abi rs6000_current_abi;
 /* ABI string from -mabi= option.  */
 const char *rs6000_abi_string;
 
+/* Whether to use variant of AIX ABI for PowerPC64 Linux.  */
+int dot_symbols;
+
 /* Debug flags */
 const char *rs6000_debug_name;
 int rs6000_debug_stack;                /* debug stack applications */
@@ -282,7 +287,312 @@ struct builtin_description
   const char *const name;
   const enum rs6000_builtins code;
 };
+\f
+/* Target cpu costs.  */
+
+struct processor_costs {
+  const int mulsi;        /* cost of SImode multiplication.  */
+  const int mulsi_const;  /* cost of SImode multiplication by constant.  */
+  const int mulsi_const9; /* cost of SImode mult by short constant.  */
+  const int muldi;        /* cost of DImode multiplication.  */
+  const int divsi;        /* cost of SImode division.  */
+  const int divdi;        /* cost of DImode division.  */
+  const int fp;           /* cost of simple SFmode and DFmode insns.  */
+  const int dmul;         /* cost of DFmode multiplication (and fmadd).  */
+  const int sdiv;         /* cost of SFmode division (fdivs).  */
+  const int ddiv;         /* cost of DFmode division (fdiv).  */
+};
+
+const struct processor_costs *rs6000_cost;
+
+/* Processor costs (relative to an add) */
+
+/* Instruction size costs on 32bit processors.  */
+static const
+struct processor_costs size32_cost = {
+  COSTS_N_INSNS (1),    /* mulsi */
+  COSTS_N_INSNS (1),    /* mulsi_const */
+  COSTS_N_INSNS (1),    /* mulsi_const9 */
+  COSTS_N_INSNS (1),    /* muldi */
+  COSTS_N_INSNS (1),    /* divsi */
+  COSTS_N_INSNS (1),    /* divdi */
+  COSTS_N_INSNS (1),    /* fp */
+  COSTS_N_INSNS (1),    /* dmul */
+  COSTS_N_INSNS (1),    /* sdiv */
+  COSTS_N_INSNS (1),    /* ddiv */
+};
+
+/* Instruction size costs on 64bit processors.  */
+static const
+struct processor_costs size64_cost = {
+  COSTS_N_INSNS (1),    /* mulsi */
+  COSTS_N_INSNS (1),    /* mulsi_const */
+  COSTS_N_INSNS (1),    /* mulsi_const9 */
+  COSTS_N_INSNS (1),    /* muldi */
+  COSTS_N_INSNS (1),    /* divsi */
+  COSTS_N_INSNS (1),    /* divdi */
+  COSTS_N_INSNS (1),    /* fp */
+  COSTS_N_INSNS (1),    /* dmul */
+  COSTS_N_INSNS (1),    /* sdiv */
+  COSTS_N_INSNS (1),    /* ddiv */
+};
+
+/* Instruction costs on RIOS1 processors.  */
+static const
+struct processor_costs rios1_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (3),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (19),   /* divsi */
+  COSTS_N_INSNS (19),   /* divdi */
+  COSTS_N_INSNS (2),    /* fp */
+  COSTS_N_INSNS (2),    /* dmul */
+  COSTS_N_INSNS (19),   /* sdiv */
+  COSTS_N_INSNS (19),   /* ddiv */
+};
+
+/* Instruction costs on RIOS2 processors.  */
+static const
+struct processor_costs rios2_cost = {
+  COSTS_N_INSNS (2),    /* mulsi */
+  COSTS_N_INSNS (2),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (2),    /* muldi */
+  COSTS_N_INSNS (13),   /* divsi */
+  COSTS_N_INSNS (13),   /* divdi */
+  COSTS_N_INSNS (2),    /* fp */
+  COSTS_N_INSNS (2),    /* dmul */
+  COSTS_N_INSNS (17),   /* sdiv */
+  COSTS_N_INSNS (17),   /* ddiv */
+};
+
+/* Instruction costs on RS64A processors.  */
+static const
+struct processor_costs rs64a_cost = {
+  COSTS_N_INSNS (20),   /* mulsi */
+  COSTS_N_INSNS (12),   /* mulsi_const */
+  COSTS_N_INSNS (8),    /* mulsi_const9 */
+  COSTS_N_INSNS (34),   /* muldi */
+  COSTS_N_INSNS (65),   /* divsi */
+  COSTS_N_INSNS (67),   /* divdi */
+  COSTS_N_INSNS (4),    /* fp */
+  COSTS_N_INSNS (4),    /* dmul */
+  COSTS_N_INSNS (31),   /* sdiv */
+  COSTS_N_INSNS (31),   /* ddiv */
+};
+
+/* Instruction costs on MPCCORE processors.  */
+static const
+struct processor_costs mpccore_cost = {
+  COSTS_N_INSNS (2),    /* mulsi */
+  COSTS_N_INSNS (2),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (2),    /* muldi */
+  COSTS_N_INSNS (6),    /* divsi */
+  COSTS_N_INSNS (6),    /* divdi */
+  COSTS_N_INSNS (4),    /* fp */
+  COSTS_N_INSNS (5),    /* dmul */
+  COSTS_N_INSNS (10),   /* sdiv */
+  COSTS_N_INSNS (17),   /* ddiv */
+};
+
+/* Instruction costs on PPC403 processors.  */
+static const
+struct processor_costs ppc403_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (33),   /* divsi */
+  COSTS_N_INSNS (33),   /* divdi */
+  COSTS_N_INSNS (11),   /* fp */
+  COSTS_N_INSNS (11),   /* dmul */
+  COSTS_N_INSNS (11),   /* sdiv */
+  COSTS_N_INSNS (11),   /* ddiv */
+};
+
+/* Instruction costs on PPC405 processors.  */
+static const
+struct processor_costs ppc405_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (3),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (35),   /* divsi */
+  COSTS_N_INSNS (35),   /* divdi */
+  COSTS_N_INSNS (11),   /* fp */
+  COSTS_N_INSNS (11),   /* dmul */
+  COSTS_N_INSNS (11),   /* sdiv */
+  COSTS_N_INSNS (11),   /* ddiv */
+};
+
+/* Instruction costs on PPC440 processors.  */
+static const
+struct processor_costs ppc440_cost = {
+  COSTS_N_INSNS (3),    /* mulsi */
+  COSTS_N_INSNS (2),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (3),    /* muldi */
+  COSTS_N_INSNS (34),   /* divsi */
+  COSTS_N_INSNS (34),   /* divdi */
+  COSTS_N_INSNS (5),    /* fp */
+  COSTS_N_INSNS (5),    /* dmul */
+  COSTS_N_INSNS (19),   /* sdiv */
+  COSTS_N_INSNS (33),   /* ddiv */
+};
+
+/* Instruction costs on PPC601 processors.  */
+static const
+struct processor_costs ppc601_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (5),    /* mulsi_const */
+  COSTS_N_INSNS (5),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (36),   /* divsi */
+  COSTS_N_INSNS (36),   /* divdi */
+  COSTS_N_INSNS (4),    /* fp */
+  COSTS_N_INSNS (5),    /* dmul */
+  COSTS_N_INSNS (17),   /* sdiv */
+  COSTS_N_INSNS (31),   /* ddiv */
+};
+
+/* Instruction costs on PPC603 processors.  */
+static const
+struct processor_costs ppc603_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (3),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (37),   /* divsi */
+  COSTS_N_INSNS (37),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (4),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (33),   /* ddiv */
+};
+
+/* Instruction costs on PPC604 processors.  */
+static const
+struct processor_costs ppc604_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (20),   /* divsi */
+  COSTS_N_INSNS (20),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (32),   /* ddiv */
+};
+
+/* Instruction costs on PPC604e processors.  */
+static const
+struct processor_costs ppc604e_cost = {
+  COSTS_N_INSNS (2),    /* mulsi */
+  COSTS_N_INSNS (2),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (2),    /* muldi */
+  COSTS_N_INSNS (20),   /* divsi */
+  COSTS_N_INSNS (20),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (32),   /* ddiv */
+};
+
+/* Instruction costs on PPC620 processors.  */
+static const
+struct processor_costs ppc620_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (3),    /* mulsi_const9 */
+  COSTS_N_INSNS (7),    /* muldi */
+  COSTS_N_INSNS (21),   /* divsi */
+  COSTS_N_INSNS (37),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (32),   /* ddiv */
+};
+
+/* Instruction costs on PPC630 processors.  */
+static const
+struct processor_costs ppc630_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (3),    /* mulsi_const9 */
+  COSTS_N_INSNS (7),    /* muldi */
+  COSTS_N_INSNS (21),   /* divsi */
+  COSTS_N_INSNS (37),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (17),   /* sdiv */
+  COSTS_N_INSNS (21),   /* ddiv */
+};
+
+/* Instruction costs on PPC750 and PPC7400 processors.  */
+static const
+struct processor_costs ppc750_cost = {
+  COSTS_N_INSNS (5),    /* mulsi */
+  COSTS_N_INSNS (3),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (5),    /* muldi */
+  COSTS_N_INSNS (17),   /* divsi */
+  COSTS_N_INSNS (17),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (17),   /* sdiv */
+  COSTS_N_INSNS (31),   /* ddiv */
+};
+
+/* Instruction costs on PPC7450 processors.  */
+static const
+struct processor_costs ppc7450_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (3),    /* mulsi_const */
+  COSTS_N_INSNS (3),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (23),   /* divsi */
+  COSTS_N_INSNS (23),   /* divdi */
+  COSTS_N_INSNS (5),    /* fp */
+  COSTS_N_INSNS (5),    /* dmul */
+  COSTS_N_INSNS (21),   /* sdiv */
+  COSTS_N_INSNS (35),   /* ddiv */
+};
+
+/* Instruction costs on PPC8540 processors.  */
+static const
+struct processor_costs ppc8540_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (19),   /* divsi */
+  COSTS_N_INSNS (19),   /* divdi */
+  COSTS_N_INSNS (4),    /* fp */
+  COSTS_N_INSNS (4),    /* dmul */
+  COSTS_N_INSNS (29),   /* sdiv */
+  COSTS_N_INSNS (29),   /* ddiv */
+};
+
+/* Instruction costs on POWER4 and POWER5 processors.  */
+static const
+struct processor_costs power4_cost = {
+  COSTS_N_INSNS (3),    /* mulsi */
+  COSTS_N_INSNS (2),    /* mulsi_const */
+  COSTS_N_INSNS (2),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (18),   /* divsi */
+  COSTS_N_INSNS (34),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (3),    /* dmul */
+  COSTS_N_INSNS (17),   /* sdiv */
+  COSTS_N_INSNS (17),   /* ddiv */
+};
 
+\f
 static bool rs6000_function_ok_for_sibcall (tree, tree);
 static int num_insns_constant_wide (HOST_WIDE_INT);
 static void validate_condition_mode (enum rtx_code, enum machine_mode);
@@ -353,7 +663,6 @@ static void rs6000_xcoff_file_end (void);
 #if TARGET_MACHO
 static bool rs6000_binds_local_p (tree);
 #endif
-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);
@@ -410,6 +719,7 @@ static void rs6000_parse_tls_size_option (void);
 static void rs6000_parse_yes_no_option (const char *, const char *, int *);
 static int first_altivec_reg_to_save (void);
 static unsigned int compute_vrsave_mask (void);
+static void compute_save_world_info(rs6000_stack_t *info_ptr);
 static void is_altivec_return_reg (rtx, void *);
 static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
 int easy_vector_constant (rtx, enum machine_mode);
@@ -426,12 +736,13 @@ static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *);
 static rtx rs6000_complex_function_value (enum machine_mode);
 static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree);
-static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
-                                     enum machine_mode, tree, int);
+static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int);
 static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
 static void setup_incoming_varargs (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree,
                                    int *, int);
+static bool rs6000_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                     tree, bool);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
 static void add_compiler_branch_island (tree, tree, int);
@@ -441,6 +752,9 @@ static tree get_prev_label (tree function_name);
 
 static tree rs6000_build_builtin_va_list (void);
 static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
+
+static enum machine_mode rs6000_eh_return_filter_mode (void);
 
 /* Hash table stuff for keeping track of TOC entries.  */
 
@@ -545,6 +859,10 @@ static const char alt_reg_names[][8] =
 #define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t"
 #undef TARGET_ASM_UNALIGNED_SI_OP
 #define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t"
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
 #endif
 #endif
 
@@ -569,8 +887,6 @@ static const char alt_reg_names[][8] =
 #undef TARGET_ASM_FUNCTION_EPILOGUE
 #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue
 
-#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE rs6000_use_dfa_pipeline_interface
 #undef  TARGET_SCHED_VARIABLE_ISSUE
 #define TARGET_SCHED_VARIABLE_ISSUE rs6000_variable_issue
 
@@ -645,6 +961,10 @@ static const char alt_reg_names[][8] =
 #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED hook_bool_CUMULATIVE_ARGS_true
 #undef TARGET_SPLIT_COMPLEX_ARG
 #define TARGET_SPLIT_COMPLEX_ARG hook_bool_tree_true
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK rs6000_must_pass_in_stack
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list
@@ -652,6 +972,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR rs6000_gimplify_va_arg
 
+#undef TARGET_EH_RETURN_FILTER_MODE
+#define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -706,6 +1029,13 @@ rs6000_init_hard_regno_mode_ok (void)
        rs6000_hard_regno_mode_ok_p[m][r] = true;
 }
 
+/* If not otherwise specified by a target, make 'long double' equivalent to
+   'double'.  */
+
+#ifndef RS6000_DEFAULT_LONG_DOUBLE_SIZE
+#define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64
+#endif
+
 /* Override command line options.  Mostly we process the processor
    type and sometimes adjust other TARGET_ options.  */
 
@@ -912,7 +1242,7 @@ rs6000_override_options (const char *default_cpu)
     }
 
   /* Set size of long double */
-  rs6000_long_double_type_size = 64;
+  rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
   if (rs6000_long_double_size_string)
     {
       char *tail;
@@ -985,7 +1315,7 @@ rs6000_override_options (const char *default_cpu)
       if (rs6000_isel_string == 0)
        rs6000_isel = 0;
       if (rs6000_long_double_size_string == 0)
-       rs6000_long_double_type_size = 64;
+       rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
     }
 
   rs6000_always_hint = (rs6000_cpu != PROCESSOR_POWER4
@@ -1106,6 +1436,86 @@ rs6000_override_options (const char *default_cpu)
      Linux and Darwin ABIs at the moment.  For now, only AIX is fixed.  */
   if (DEFAULT_ABI != ABI_AIX)
     targetm.calls.split_complex_arg = NULL;
+
+  /* Initialize rs6000_cost with the appropriate target costs.  */
+  if (optimize_size)
+    rs6000_cost = TARGET_POWERPC64 ? &size64_cost : &size32_cost;
+  else
+    switch (rs6000_cpu)
+      {
+      case PROCESSOR_RIOS1:
+       rs6000_cost = &rios1_cost;
+       break;
+
+      case PROCESSOR_RIOS2:
+       rs6000_cost = &rios2_cost;
+       break;
+
+      case PROCESSOR_RS64A:
+       rs6000_cost = &rs64a_cost;
+       break;
+
+      case PROCESSOR_MPCCORE:
+       rs6000_cost = &mpccore_cost;
+       break;
+
+      case PROCESSOR_PPC403:
+       rs6000_cost = &ppc403_cost;
+       break;
+
+      case PROCESSOR_PPC405:
+       rs6000_cost = &ppc405_cost;
+       break;
+
+      case PROCESSOR_PPC440:
+       rs6000_cost = &ppc440_cost;
+       break;
+
+      case PROCESSOR_PPC601:
+       rs6000_cost = &ppc601_cost;
+       break;
+
+      case PROCESSOR_PPC603:
+       rs6000_cost = &ppc603_cost;
+       break;
+
+      case PROCESSOR_PPC604:
+       rs6000_cost = &ppc604_cost;
+       break;
+
+      case PROCESSOR_PPC604e:
+       rs6000_cost = &ppc604e_cost;
+       break;
+
+      case PROCESSOR_PPC620:
+       rs6000_cost = &ppc620_cost;
+       break;
+
+      case PROCESSOR_PPC630:
+       rs6000_cost = &ppc630_cost;
+       break;
+
+      case PROCESSOR_PPC750:
+      case PROCESSOR_PPC7400:
+       rs6000_cost = &ppc750_cost;
+       break;
+
+      case PROCESSOR_PPC7450:
+       rs6000_cost = &ppc7450_cost;
+       break;
+
+      case PROCESSOR_PPC8540:
+       rs6000_cost = &ppc8540_cost;
+       break;
+
+      case PROCESSOR_POWER4:
+      case PROCESSOR_POWER5:
+       rs6000_cost = &power4_cost;
+       break;
+
+      default:
+       abort ();
+      }
 }
 
 /* Handle generic options of the form -mfoo=yes/no.
@@ -1277,7 +1687,17 @@ any_operand (rtx op ATTRIBUTE_UNUSED,
   return 1;
 }
 
+/* Returns 1 always.  */
+
+int
+any_parallel_operand (rtx op ATTRIBUTE_UNUSED, 
+                     enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
 /* Returns 1 if op is the count register.  */
+
 int
 count_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
@@ -1294,6 +1714,7 @@ count_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 }
 
 /* Returns 1 if op is an altivec register.  */
+
 int
 altivec_register_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
@@ -2626,9 +3047,6 @@ toc_relative_expr_p (rtx op)
   return constant_pool_expr_1 (op, &have_sym, &have_toc) && have_toc;
 }
 
-/* SPE offset addressing is limited to 5-bits worth of double words.  */
-#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
-
 bool
 legitimate_constant_pool_address_p (rtx x)
 {
@@ -2648,6 +3066,9 @@ legitimate_small_data_p (enum machine_mode mode, rtx x)
          && small_data_operand (x, mode));
 }
 
+/* SPE offset addressing is limited to 5-bits worth of double words.  */
+#define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
+
 bool
 rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
 {
@@ -2659,6 +3080,8 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
+  if (legitimate_constant_pool_address_p (x))
+    return true;
   if (GET_CODE (XEXP (x, 1)) != CONST_INT)
     return false;
 
@@ -2771,8 +3194,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_NUNITS (mode) != 1)
        return false;
-      if (GET_MODE_BITSIZE (mode) > 32
-         && !(TARGET_HARD_FLOAT && TARGET_FPRS && mode == DFmode))
+      if (GET_MODE_BITSIZE (mode) > 64)
        return false;
 
       return CONSTANT_P (x);
@@ -3041,8 +3463,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                  tmp1 = gen_reg_rtx (Pmode);
                  tmp2 = gen_reg_rtx (Pmode);
                  tmp3 = gen_reg_rtx (Pmode);
-                 mem = gen_rtx_MEM (Pmode, tmp1);
-                 RTX_UNCHANGING_P (mem) = 1;
+                 mem = gen_const_mem (Pmode, tmp1);
 
                  first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, lab,
                                                             gsym));
@@ -3285,8 +3706,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
        {
          rtx offset = gen_rtx_CONST (Pmode,
                         gen_rtx_MINUS (Pmode, x,
-                          gen_rtx_SYMBOL_REF (Pmode,
-                            machopic_function_base_name ())));
+                                       machopic_function_base_sym ()));
          x = gen_rtx_LO_SUM (GET_MODE (x),
                gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
                  gen_rtx_HIGH (Pmode, offset)), offset);
@@ -3479,6 +3899,10 @@ rs6000_conditional_register_usage (void)
       = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
       = call_really_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
 
+  if (TARGET_TOC && TARGET_MINIMAL_TOC)
+    fixed_regs[RS6000_PIC_OFFSET_TABLE_REGNUM]
+      = call_used_regs[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
+
   if (TARGET_ALTIVEC)
     global_regs[VSCR_REGNO] = 1;
 
@@ -3900,8 +4324,16 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                  return;
                }
 #endif
-             emit_insn (gen_macho_high (target, operands[1]));
-             emit_insn (gen_macho_low (operands[0], target, operands[1]));
+             if (mode == DImode)
+               {
+                 emit_insn (gen_macho_high_di (target, operands[1]));
+                 emit_insn (gen_macho_low_di (operands[0], target, operands[1]));
+               }
+             else
+               {
+                 emit_insn (gen_macho_high (target, operands[1]));
+                 emit_insn (gen_macho_low (operands[0], target, operands[1]));
+               }
              return;
            }
 
@@ -3988,10 +4420,9 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                        get_pool_mode (XEXP (operands[1], 0))))
            {
              operands[1]
-               = gen_rtx_MEM (mode,
-                              create_TOC_reference (XEXP (operands[1], 0)));
+               = gen_const_mem (mode,
+                                create_TOC_reference (XEXP (operands[1], 0)));
              set_mem_alias_set (operands[1], get_TOC_alias_set ());
-             RTX_UNCHANGING_P (operands[1]) = 1;
            }
        }
       break;
@@ -4136,6 +4567,17 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
       }
 }
 \f
+/* Return true if TYPE must be passed on the stack and not in registers.  */
+
+static bool
+rs6000_must_pass_in_stack (enum machine_mode mode, tree type)
+{
+  if (DEFAULT_ABI == ABI_AIX || TARGET_64BIT)
+    return must_pass_in_stack_var_size (mode, type);
+  else
+    return must_pass_in_stack_var_size_or_pad (mode, type);
+}
+
 /* If defined, a C expression which determines whether, and in which
    direction, to pad out an argument with extra space.  The value
    should be of type `enum direction': either `upward' to pad above
@@ -4419,124 +4861,49 @@ rs6000_spe_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 /* 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)
+rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
+{
+  int n_units;
+  int i, k;
+  rtx rvec[GP_ARG_NUM_REG + 1];
+
+  if (align_words >= GP_ARG_NUM_REG)
+    return NULL_RTX;
+
+  n_units = rs6000_arg_size (mode, type);
+
+  /* Optimize the simple case where the arg fits in one gpr, except in
+     the case of BLKmode due to assign_parms assuming that registers are
+     BITS_PER_WORD wide.  */
+  if (n_units == 0
+      || (n_units == 1 && mode != BLKmode))
+    return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+
+  k = 0;
+  if (align_words + n_units > GP_ARG_NUM_REG)
+    /* Not all of the arg fits in gprs.  Say that it goes in memory too,
+       using a magic NULL_RTX component.
+       FIXME: This is not strictly correct.  Only some of the arg
+       belongs in memory, not all of it.  However, there isn't any way
+       to do this currently, apart from building rtx descriptions for
+       the pieces of memory we want stored.  Due to bugs in the generic
+       code we can't use the normal function_arg_partial_nregs scheme
+       with the PARALLEL arg description we emit here.
+       In any case, the code to store the whole arg to memory is often
+       more efficient than code to store pieces, and we know that space
+       is available in the right place for the whole arg.  */
+    rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
+
+  i = 0;
+  do
     {
-      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 (ALTIVEC_VECTOR_MODE (mode) && align_words == GP_ARG_NUM_REG - 2)
-    {
-      /* Varargs vector regs must be saved in R9-R10.  */
-      return gen_rtx_PARALLEL (mode,
-                              gen_rtvec (3,
-                                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),
-                                gen_rtx_EXPR_LIST (VOIDmode,
-                                                   gen_rtx_REG (SImode,
-                                                                GP_ARG_MIN_REG
-                                                                + align_words + 1),
-                                                   GEN_INT (4))));
-    }
-  else if ((mode == BLKmode || ALTIVEC_VECTOR_MODE (mode))
-           && align_words <= (GP_ARG_NUM_REG - 1))
-    {
-      /* AltiVec vector regs are saved in R5-R8. */
-      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 (mode, gen_rtvec_v (k, rtlvec));
+      rtx r = gen_rtx_REG (SImode, GP_ARG_MIN_REG + align_words);
+      rtx off = GEN_INT (i++ * 4);
+      rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
     }
-  return NULL_RTX;
+  while (++align_words < GP_ARG_NUM_REG && --n_units != 0);
+
+  return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
 }
 
 /* Determine where to put an argument to a function.
@@ -4631,8 +4998,8 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
        {
          /* 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;
+         int align, align_words, n_words;
+         enum machine_mode part_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
@@ -4648,20 +5015,20 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
          /* Out of registers?  Memory, then.  */
          if (align_words >= GP_ARG_NUM_REG)
            return NULL_RTX;
-         
+
+         if (TARGET_32BIT && TARGET_POWERPC64)
+           return rs6000_mixed_function_arg (mode, type, align_words);
+
          /* 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)
+         part_mode = mode;
+         n_words = rs6000_arg_size (mode, type);
+         if (align_words + n_words > 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;
-         
-         if (TARGET_32BIT
-             && (TARGET_POWERPC64 || (align_words == GP_ARG_NUM_REG - 2)))
-           return rs6000_mixed_function_arg (cum, part_mode, type, align_words);
-         else
-           return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
+
+         return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
        }
     }
   else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
@@ -4688,10 +5055,13 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            gregno += (1 - gregno) & 1;
 
          /* Multi-reg args are not split between registers and stack.  */
-         if (gregno + n_words - 1 <= GP_ARG_MAX_REG)
-           return gen_rtx_REG (mode, gregno);
-         else
+         if (gregno + n_words - 1 > GP_ARG_MAX_REG)
            return NULL_RTX;
+
+         if (TARGET_32BIT && TARGET_POWERPC64)
+           return rs6000_mixed_function_arg (mode, type,
+                                             gregno - GP_ARG_MIN_REG);
+         return gen_rtx_REG (mode, gregno);
        }
     }
   else
@@ -4701,25 +5071,23 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
-         rtx fpr[2];
-         rtx *r;
+         rtx rvec[GP_ARG_NUM_REG + 1];
+         rtx r;
+         int k;
          bool needs_psave;
          enum machine_mode fmode = mode;
-         int n;
          unsigned long n_fpreg = (GET_MODE_SIZE (mode) + 7) >> 3;
 
          if (cum->fregno + n_fpreg > FP_ARG_MAX_REG + 1)
            {
-             /* Long double split over regs and memory.  */
-             if (fmode == TFmode)
-               fmode = DFmode;
-
              /* Currently, we only ever need one reg here because complex
                 doubles are split.  */
-             if (cum->fregno != FP_ARG_MAX_REG - 1)
+             if (cum->fregno != FP_ARG_MAX_REG || fmode != TFmode)
                abort ();
+
+             /* Long double split over regs and memory.  */
+             fmode = DFmode;
            }
-         fpr[1] = gen_rtx_REG (fmode, cum->fregno);
 
          /* Do we also need to pass this arg in the parameter save
             area?  */
@@ -4730,46 +5098,55 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                                 && align_words >= GP_ARG_NUM_REG)));
 
          if (!needs_psave && mode == fmode)
-           return fpr[1];
-
-          if (TARGET_32BIT && TARGET_POWERPC64
-              && mode == DFmode && cum->stdarg)
-            return rs6000_mixed_function_arg (cum, mode, type, align_words);
-
-         /* Describe where this piece goes.  */
-         r = fpr + 1;
-         *r = gen_rtx_EXPR_LIST (VOIDmode, *r, const0_rtx);
-         n = 1;
+           return gen_rtx_REG (fmode, cum->fregno);
 
+         k = 0;
          if (needs_psave)
            {
-             /* Now describe the part that goes in gprs or the stack.
+             /* Describe the part that goes in gprs or the stack.
                 This piece must come first, before the fprs.  */
-             rtx reg = NULL_RTX;
              if (align_words < GP_ARG_NUM_REG)
                {
                  unsigned long n_words = rs6000_arg_size (mode, type);
-                 enum machine_mode rmode = mode;
-
-                 if (align_words + n_words > GP_ARG_NUM_REG)
-                   /* If this is partially on the stack, then we only
-                      include the portion actually in registers here.
-                      We know this can only be one register because
-                      complex doubles are splt.  */
-                   rmode = Pmode;
-                 reg = gen_rtx_REG (rmode, GP_ARG_MIN_REG + align_words);
+
+                 if (align_words + n_words > GP_ARG_NUM_REG
+                     || (TARGET_32BIT && TARGET_POWERPC64))
+                   {
+                     /* If this is partially on the stack, then we only
+                        include the portion actually in registers here.  */
+                     enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
+                     rtx off;
+                     do
+                       {
+                         r = gen_rtx_REG (rmode,
+                                          GP_ARG_MIN_REG + align_words);
+                         off = GEN_INT (k * GET_MODE_SIZE (rmode));
+                         rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, off);
+                       }
+                     while (++align_words < GP_ARG_NUM_REG && --n_words != 0);
+                   }
+                 else
+                   {
+                     /* The whole arg fits in gprs.  */
+                     r = gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
+                     rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+                   }
                }
-             *--r = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
-             ++n;
+             else
+               /* It's entirely in memory.  */
+               rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
            }
 
-         return gen_rtx_PARALLEL (mode, gen_rtvec_v (n, r));
+         /* Describe where this piece goes in the fprs.  */
+         r = gen_rtx_REG (fmode, cum->fregno);
+         rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, r, const0_rtx);
+
+         return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rvec));
        }
       else if (align_words < GP_ARG_NUM_REG)
        {
-         if (TARGET_32BIT && TARGET_POWERPC64
-             && (mode == DImode || mode == BLKmode))
-           return rs6000_mixed_function_arg (cum, mode, type, align_words);
+         if (TARGET_32BIT && TARGET_POWERPC64)
+           return rs6000_mixed_function_arg (mode, type, align_words);
 
          return gen_rtx_REG (mode, GP_ARG_MIN_REG + align_words);
        }
@@ -4778,15 +5155,20 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     }
 }
 \f
-/* For an arg passed partly in registers and partly in memory,
-   this is the number of registers used.
-   For args passed entirely in registers or entirely in memory, zero.  */
+/* For an arg passed partly in registers and partly in memory, this is
+   the number of registers used.  For args passed entirely in registers
+   or entirely in memory, zero.  When an arg is described by a PARALLEL,
+   perhaps using more than one register type, this function returns the
+   number of registers used by the first element of the PARALLEL.  */
 
 int
 function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode, 
                            tree type, int named)
 {
   int ret = 0;
+  int align;
+  int parm_offset;
+  int align_words;
 
   if (DEFAULT_ABI == ABI_V4)
     return 0;
@@ -4795,17 +5177,29 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       && cum->nargs_prototype >= 0)
     return 0;
 
-  if (USE_FP_FOR_ARG_P (cum, mode, type))
+  align = function_arg_boundary (mode, type) / PARM_BOUNDARY - 1;
+  parm_offset = TARGET_32BIT ? 2 : 0;
+  align_words = cum->words + ((parm_offset - cum->words) & align);
+
+  if (USE_FP_FOR_ARG_P (cum, mode, type)
+      /* If we are passing this arg in gprs as well, then this function
+        should return the number of gprs (or memory) partially passed,
+        *not* the number of fprs.  */
+      && !(type
+          && (cum->nargs_prototype <= 0
+              || (DEFAULT_ABI == ABI_AIX
+                  && TARGET_XL_CALL
+                  && align_words >= GP_ARG_NUM_REG))))
     {
       if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
-       ret = FP_ARG_MAX_REG - cum->fregno;
+       ret = FP_ARG_MAX_REG + 1 - cum->fregno;
       else if (cum->nargs_prototype >= 0)
        return 0;
     }
 
-  if (cum->words < GP_ARG_NUM_REG
-      && GP_ARG_NUM_REG < cum->words + rs6000_arg_size (mode, type))
-    ret = GP_ARG_NUM_REG - cum->words;
+  if (align_words < GP_ARG_NUM_REG
+      && GP_ARG_NUM_REG < align_words + rs6000_arg_size (mode, type))
+    ret = GP_ARG_NUM_REG - align_words;
 
   if (ret != 0 && TARGET_DEBUG_ARG)
     fprintf (stderr, "function_arg_partial_nregs: %d\n", ret);
@@ -4827,10 +5221,10 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
    As an extension to all ABIs, variable sized types are passed by
    reference.  */
 
-int
-function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, 
-                               enum machine_mode mode ATTRIBUTE_UNUSED, 
-                               tree type, int named ATTRIBUTE_UNUSED)
+static bool
+rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, 
+                         enum machine_mode mode ATTRIBUTE_UNUSED, 
+                         tree type, bool named ATTRIBUTE_UNUSED)
 {
   if ((DEFAULT_ABI == ABI_V4
        && ((type && AGGREGATE_TYPE_P (type))
@@ -4920,7 +5314,7 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       save_area = virtual_incoming_args_rtx;
       cfun->machine->sysv_varargs_p = 0;
 
-      if (MUST_PASS_IN_STACK (mode, type))
+      if (targetm.calls.must_pass_in_stack (mode, type))
        first_reg_offset += rs6000_arg_size (TYPE_MODE (type), type);
     }
 
@@ -5055,11 +5449,13 @@ rs6000_va_start (tree valist, rtx nextarg)
             HOST_WIDE_INT_PRINT_DEC", n_fpr = "HOST_WIDE_INT_PRINT_DEC"\n",
             words, n_gpr, n_fpr);
 
-  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr, build_int_2 (n_gpr, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (gpr), gpr,
+            build_int_cst (NULL_TREE, n_gpr, 0));
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
-  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr, build_int_2 (n_fpr, 0));
+  t = build (MODIFY_EXPR, TREE_TYPE (fpr), fpr,
+            build_int_cst (NULL_TREE, n_fpr, 0));
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -5067,7 +5463,7 @@ rs6000_va_start (tree valist, rtx nextarg)
   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
   if (words != 0)
     t = build (PLUS_EXPR, TREE_TYPE (ovf), t,
-              build_int_2 (words * UNITS_PER_WORD, 0));
+              build_int_cst (NULL_TREE, words * UNITS_PER_WORD, 0));
   t = build (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -5075,7 +5471,7 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the register save area.  */
   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
   t = build (PLUS_EXPR, TREE_TYPE (sav), t,
-            build_int_2 (-RS6000_VARARGS_SIZE, -1));
+            build_int_cst (NULL_TREE, -RS6000_VARARGS_SIZE, -1));
   t = build (MODIFY_EXPR, TREE_TYPE (sav), sav, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -5088,29 +5484,20 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 {
   tree f_gpr, f_fpr, f_res, f_ovf, f_sav;
   tree gpr, fpr, ovf, sav, reg, t, u;
-  int indirect_p, size, rsize, n_reg, sav_ofs, sav_scale;
+  int size, rsize, n_reg, sav_ofs, sav_scale;
   tree lab_false, lab_over, addr;
   int align;
   tree ptrtype = build_pointer_type (type);
 
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
+    {
+      t = rs6000_gimplify_va_arg (valist, ptrtype, pre_p, post_p);
+      return build_fold_indirect_ref (t);
+    }
+
   if (DEFAULT_ABI != ABI_V4)
     {
-      /* Variable sized types are passed by reference, as are AltiVec
-        vectors when 32-bit and not using the AltiVec ABI extension.  */
-      if (int_size_in_bytes (type) < 0
-         || (TARGET_32BIT
-             && !TARGET_ALTIVEC_ABI
-             && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
-       {
-         /* Args grow upward.  */
-         t = build2 (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
-                     build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
-         t = build1 (NOP_EXPR, build_pointer_type (ptrtype), t);
-         t = build_fold_indirect_ref (t);
-         return build_fold_indirect_ref (t);
-       }
-      if (targetm.calls.split_complex_arg
-         && TREE_CODE (type) == COMPLEX_TYPE)
+      if (targetm.calls.split_complex_arg && TREE_CODE (type) == COMPLEX_TYPE)
        {
          tree elem_type = TREE_TYPE (type);
          enum machine_mode elem_mode = TYPE_MODE (elem_type);
@@ -5154,25 +5541,10 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   rsize = (size + 3) / 4;
   align = 1;
 
-  if (AGGREGATE_TYPE_P (type)
-      || TYPE_MODE (type) == TFmode
-      || (!TARGET_ALTIVEC_ABI && ALTIVEC_VECTOR_MODE (TYPE_MODE (type))))
-    {
-      /* Aggregates, long doubles, and AltiVec vectors are passed by
-        reference.  */
-      indirect_p = 1;
-      reg = gpr;
-      n_reg = 1;
-      sav_ofs = 0;
-      sav_scale = 4;
-      size = 4;
-      rsize = 1;
-    }
-  else if (TARGET_HARD_FLOAT && TARGET_FPRS
-          && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
+  if (TARGET_HARD_FLOAT && TARGET_FPRS
+      && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
     {
       /* FP args go in FP registers, if present.  */
-      indirect_p = 0;
       reg = fpr;
       n_reg = 1;
       sav_ofs = 8*4;
@@ -5183,7 +5555,6 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   else
     {
       /* Otherwise into GP registers.  */
-      indirect_p = 0;
       reg = gpr;
       n_reg = rsize;
       sav_ofs = 0;
@@ -5213,12 +5584,11 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       if (n_reg == 2)
        {
          u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
-                    build_int_2 (n_reg - 1, 0));
+                    size_int (n_reg - 1));
          u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
        }
 
-      t = build_int_2 (8 - n_reg + 1, 0);
-      TREE_TYPE (t) = TREE_TYPE (reg);
+      t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
       t = build2 (GE_EXPR, boolean_type_node, u, t);
       u = build1 (GOTO_EXPR, void_type_node, lab_false);
       t = build3 (COND_EXPR, void_type_node, t, u, NULL_TREE);
@@ -5226,12 +5596,11 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 
       t = sav;
       if (sav_ofs)
-       t = build2 (PLUS_EXPR, ptr_type_node, sav, build_int_2 (sav_ofs, 0));
+       t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
 
-      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg,
-                build_int_2 (n_reg, 0));
+      u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
       u = build1 (CONVERT_EXPR, integer_type_node, u);
-      u = build2 (MULT_EXPR, integer_type_node, u, build_int_2 (sav_scale, 0));
+      u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
       t = build2 (PLUS_EXPR, ptr_type_node, t, u);
 
       t = build2 (MODIFY_EXPR, void_type_node, addr, t);
@@ -5247,7 +5616,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
        {
          /* Ensure that we don't find any more args in regs.
             Alignment has taken care of the n_reg == 2 case.  */
-         t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, build_int_2 (8, 0));
+         t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
          gimplify_and_add (t, pre_p);
        }
     }
@@ -5258,15 +5627,16 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   t = ovf;
   if (align != 1)
     {
-      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (align - 1, 0));
-      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+      t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
+                 build_int_cst (NULL_TREE, -align, -1));
     }
   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
 
   u = build2 (MODIFY_EXPR, void_type_node, addr, t);
   gimplify_and_add (u, pre_p);
 
-  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, build_int_2 (size, 0));
+  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
   t = build2 (MODIFY_EXPR, TREE_TYPE (ovf), ovf, t);
   gimplify_and_add (t, pre_p);
 
@@ -5276,24 +5646,17 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       append_to_statement_list (t, pre_p);
     }
 
-  if (indirect_p)
-    {
-      addr = fold_convert (build_pointer_type (ptrtype), addr);
-      addr = build_fold_indirect_ref (addr);
-    }
-  else
-    addr = fold_convert (ptrtype, addr);
-
+  addr = fold_convert (ptrtype, addr);
   return build_fold_indirect_ref (addr);
 }
 
 /* Builtins.  */
 
-#define def_builtin(MASK, NAME, TYPE, CODE)                    \
-do {                                                           \
-  if ((MASK) & target_flags)                                   \
-    builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,     \
-                     NULL, NULL_TREE);                         \
+#define def_builtin(MASK, NAME, TYPE, CODE)                            \
+do {                                                                   \
+  if ((MASK) & target_flags)                                           \
+    lang_hooks.builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD,  \
+                                NULL, NULL_TREE);                      \
 } while (0)
 
 /* Simple ternary operations: VECd = foo (VECa, VECb, VECc).  */
@@ -7255,8 +7618,8 @@ altivec_init_builtins (void)
     = build_function_type (V8HI_type_node, void_list_node);
   tree void_ftype_void
     = build_function_type (void_type_node, void_list_node);
-  tree void_ftype_qi
-    = build_function_type_list (void_type_node, char_type_node, NULL_TREE);
+  tree void_ftype_int
+    = build_function_type_list (void_type_node, integer_type_node, NULL_TREE);
 
   tree v16qi_ftype_long_pcvoid
     = build_function_type_list (V16QI_type_node,
@@ -7327,7 +7690,7 @@ altivec_init_builtins (void)
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mtvscr", void_ftype_v4si, ALTIVEC_BUILTIN_MTVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_mfvscr", v8hi_ftype_void, ALTIVEC_BUILTIN_MFVSCR);
   def_builtin (MASK_ALTIVEC, "__builtin_altivec_dssall", void_ftype_void, ALTIVEC_BUILTIN_DSSALL);
-  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_qi, ALTIVEC_BUILTIN_DSS);
+  def_builtin (MASK_ALTIVEC, "__builtin_altivec_dss", void_ftype_int, ALTIVEC_BUILTIN_DSS);
   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);
@@ -7921,6 +8284,89 @@ rs6000_init_libfuncs (void)
       set_conv_libfunc (sfloat_optab, TFmode, SImode, "_q_itoq");
     }
 }
+
+\f
+/* Expand a block clear operation, and return 1 if successful.  Return 0
+   if we should let the compiler generate normal code.
+
+   operands[0] is the destination
+   operands[1] is the length
+   operands[2] is the alignment */
+
+int
+expand_block_clear (rtx operands[])
+{
+  rtx orig_dest = operands[0];
+  rtx bytes_rtx        = operands[1];
+  rtx align_rtx = operands[2];
+  int constp   = (GET_CODE (bytes_rtx) == CONST_INT);
+  int align;
+  int bytes;
+  int offset;
+  int clear_bytes;
+
+  /* If this is not a fixed size move, just call memcpy */
+  if (! constp)
+    return 0;
+
+  /* If this is not a fixed size alignment, abort */
+  if (GET_CODE (align_rtx) != CONST_INT)
+    abort ();
+  align = INTVAL (align_rtx) * BITS_PER_UNIT;
+
+  /* Anything to clear? */
+  bytes = INTVAL (bytes_rtx);
+  if (bytes <= 0)
+    return 1;
+
+  if (bytes > (TARGET_POWERPC64 && align >= 32 ? 64 : 32))
+    return 0;
+
+  if (optimize_size && bytes > 16)
+    return 0;
+
+  for (offset = 0; bytes > 0; offset += clear_bytes, bytes -= clear_bytes)
+    {
+      rtx (*mov) (rtx, rtx);
+      enum machine_mode mode = BLKmode;
+      rtx dest;
+      
+      if (bytes >= 8 && TARGET_POWERPC64
+              /* 64-bit loads and stores require word-aligned
+                 displacements.  */
+              && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
+       {
+         clear_bytes = 8;
+         mode = DImode;
+         mov = gen_movdi;
+       }
+      else if (bytes >= 4 && !STRICT_ALIGNMENT)
+       {                       /* move 4 bytes */
+         clear_bytes = 4;
+         mode = SImode;
+         mov = gen_movsi;
+       }
+      else if (bytes == 2 && !STRICT_ALIGNMENT)
+       {                       /* move 2 bytes */
+         clear_bytes = 2;
+         mode = HImode;
+         mov = gen_movhi;
+       }
+      else /* move 1 byte at a time */
+       {
+         clear_bytes = 1;
+         mode = QImode;
+         mov = gen_movqi;
+       }
+      
+      dest = adjust_address (orig_dest, mode, offset);
+      
+      emit_insn ((*mov) (dest, const0_rtx));
+    }
+
+  return 1;
+}
+
 \f
 /* Expand a block move operation, and return 1 if successful.  Return 0
    if we should let the compiler generate normal code.
@@ -7954,7 +8400,7 @@ expand_block_move (rtx operands[])
   /* If this is not a fixed size alignment, abort */
   if (GET_CODE (align_rtx) != CONST_INT)
     abort ();
-  align = INTVAL (align_rtx);
+  align = INTVAL (align_rtx) * BITS_PER_UNIT;
 
   /* Anything to move? */
   bytes = INTVAL (bytes_rtx);
@@ -7969,7 +8415,7 @@ expand_block_move (rtx operands[])
   for (offset = 0; bytes > 0; offset += move_bytes, bytes -= move_bytes)
     {
       union {
-       rtx (*movstrsi) (rtx, rtx, rtx, rtx);
+       rtx (*movmemsi) (rtx, rtx, rtx, rtx);
        rtx (*mov) (rtx, rtx);
       } gen_func;
       enum machine_mode mode = BLKmode;
@@ -7987,7 +8433,7 @@ expand_block_move (rtx operands[])
          && ! fixed_regs[12])
        {
          move_bytes = (bytes > 32) ? 32 : bytes;
-         gen_func.movstrsi = gen_movstrsi_8reg;
+         gen_func.movmemsi = gen_movmemsi_8reg;
        }
       else if (TARGET_STRING
               && bytes > 16    /* move up to 24 bytes at a time */
@@ -7999,7 +8445,7 @@ expand_block_move (rtx operands[])
               && ! fixed_regs[10])
        {
          move_bytes = (bytes > 24) ? 24 : bytes;
-         gen_func.movstrsi = gen_movstrsi_6reg;
+         gen_func.movmemsi = gen_movmemsi_6reg;
        }
       else if (TARGET_STRING
               && bytes > 8     /* move up to 16 bytes at a time */
@@ -8009,12 +8455,12 @@ expand_block_move (rtx operands[])
               && ! fixed_regs[8])
        {
          move_bytes = (bytes > 16) ? 16 : bytes;
-         gen_func.movstrsi = gen_movstrsi_4reg;
+         gen_func.movmemsi = gen_movmemsi_4reg;
        }
       else if (bytes >= 8 && TARGET_POWERPC64
               /* 64-bit loads and stores require word-aligned
                  displacements.  */
-              && (align >= 8 || (! STRICT_ALIGNMENT && align >= 4)))
+              && (align >= 64 || (!STRICT_ALIGNMENT && align >= 32)))
        {
          move_bytes = 8;
          mode = DImode;
@@ -8023,15 +8469,15 @@ expand_block_move (rtx operands[])
       else if (TARGET_STRING && bytes > 4 && !TARGET_POWERPC64)
        {                       /* move up to 8 bytes at a time */
          move_bytes = (bytes > 8) ? 8 : bytes;
-         gen_func.movstrsi = gen_movstrsi_2reg;
+         gen_func.movmemsi = gen_movmemsi_2reg;
        }
-      else if (bytes >= 4 && (align >= 4 || ! STRICT_ALIGNMENT))
+      else if (bytes >= 4 && !STRICT_ALIGNMENT)
        {                       /* move 4 bytes */
          move_bytes = 4;
          mode = SImode;
          gen_func.mov = gen_movsi;
        }
-      else if (bytes == 2 && (align >= 2 || ! STRICT_ALIGNMENT))
+      else if (bytes == 2 && !STRICT_ALIGNMENT)
        {                       /* move 2 bytes */
          move_bytes = 2;
          mode = HImode;
@@ -8040,7 +8486,7 @@ expand_block_move (rtx operands[])
       else if (TARGET_STRING && bytes > 1)
        {                       /* move up to 4 bytes at a time */
          move_bytes = (bytes > 4) ? 4 : bytes;
-         gen_func.movstrsi = gen_movstrsi_1reg;
+         gen_func.movmemsi = gen_movmemsi_1reg;
        }
       else /* move 1 byte at a time */
        {
@@ -8070,7 +8516,7 @@ expand_block_move (rtx operands[])
 
       if (mode == BLKmode)
        {
-         /* Move the address into scratch registers.  The movstrsi
+         /* Move the address into scratch registers.  The movmemsi
             patterns require zero offset.  */
          if (!REG_P (XEXP (src, 0)))
            {
@@ -8086,7 +8532,7 @@ expand_block_move (rtx operands[])
            }
          set_mem_size (dest, GEN_INT (move_bytes));
          
-         emit_insn ((*gen_func.movstrsi) (dest, src,
+         emit_insn ((*gen_func.movmemsi) (dest, src,
                                           GEN_INT (move_bytes & 31),
                                           align_rtx));
        }
@@ -8096,35 +8542,172 @@ expand_block_move (rtx operands[])
 }
 
 \f
-/* Return 1 if OP is a load multiple operation.  It is known to be a
-   PARALLEL and the first section will be tested.  */
-
+/* Return 1 if OP is suitable for a save_world call in prologue. It is
+   known to be a PARALLEL. */
 int
-load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+save_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  int count = XVECLEN (op, 0);
-  unsigned int dest_regno;
-  rtx src_addr;
+  int index;
   int i;
+  rtx elt;
+  int count = XVECLEN (op, 0);
 
-  /* Perform a quick check so we don't blow up below.  */
-  if (count <= 1
-      || GET_CODE (XVECEXP (op, 0, 0)) != SET
-      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
-      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+  if (count != 55)
     return 0;
 
-  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
-  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+  index = 0;
+  if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+      || GET_CODE (XVECEXP (op, 0, index++)) != USE)
+    return 0;
 
-  for (i = 1; i < count; i++)
+  for (i=1; i <= 18; i++)
     {
-      rtx elt = XVECEXP (op, 0, i);
+      elt = XVECEXP (op, 0, index++);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_DEST (elt)) != MEM
+         || ! memory_operand (SET_DEST (elt), DFmode)
+         || GET_CODE (SET_SRC (elt)) != REG
+         || GET_MODE (SET_SRC (elt)) != DFmode)
+       return 0;
+    }
 
+  for (i=1; i <= 12; i++)
+    {
+      elt = XVECEXP (op, 0, index++);
       if (GET_CODE (elt) != SET
-         || GET_CODE (SET_DEST (elt)) != REG
-         || GET_MODE (SET_DEST (elt)) != SImode
-         || REGNO (SET_DEST (elt)) != dest_regno + i
+         || GET_CODE (SET_DEST (elt)) != MEM
+         || GET_CODE (SET_SRC (elt)) != REG
+         || GET_MODE (SET_SRC (elt)) != V4SImode)
+       return 0;
+    }
+
+  for (i=1; i <= 19; i++)
+    {
+      elt = XVECEXP (op, 0, index++);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_DEST (elt)) != MEM
+         || ! memory_operand (SET_DEST (elt), Pmode)
+         || GET_CODE (SET_SRC (elt)) != REG
+         || GET_MODE (SET_SRC (elt)) != Pmode)
+       return 0;
+    }
+
+  elt = XVECEXP (op, 0, index++);
+  if (GET_CODE (elt) != SET
+      || GET_CODE (SET_DEST (elt)) != MEM
+      || ! memory_operand (SET_DEST (elt), Pmode)
+      || GET_CODE (SET_SRC (elt)) != REG
+      || REGNO (SET_SRC (elt)) != CR2_REGNO
+      || GET_MODE (SET_SRC (elt)) != Pmode)
+    return 0;
+
+  if (GET_CODE (XVECEXP (op, 0, index++)) != USE
+      || GET_CODE (XVECEXP (op, 0, index++)) != USE
+      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
+    return 0;
+  return 1;
+}
+
+/* Return 1 if OP is suitable for a save_world call in prologue. It is
+   known to be a PARALLEL. */
+int
+restore_world_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  int index;
+  int i;
+  rtx elt;
+  int count = XVECLEN (op, 0);
+
+  if (count != 59)
+    return 0;
+
+  index = 0;
+  if (GET_CODE (XVECEXP (op, 0, index++)) != RETURN
+      || GET_CODE (XVECEXP (op, 0, index++)) != USE
+      || GET_CODE (XVECEXP (op, 0, index++)) != USE
+      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER)
+    return 0;
+
+  elt = XVECEXP (op, 0, index++);
+  if (GET_CODE (elt) != SET
+      || GET_CODE (SET_SRC (elt)) != MEM
+      || ! memory_operand (SET_SRC (elt), Pmode)
+      || GET_CODE (SET_DEST (elt)) != REG
+      || REGNO (SET_DEST (elt)) != CR2_REGNO
+      || GET_MODE (SET_DEST (elt)) != Pmode)
+    return 0;
+
+  for (i=1; i <= 19; i++)
+    {
+      elt = XVECEXP (op, 0, index++);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_SRC (elt)) != MEM
+         || ! memory_operand (SET_SRC (elt), Pmode)
+         || GET_CODE (SET_DEST (elt)) != REG
+         || GET_MODE (SET_DEST (elt)) != Pmode)
+       return 0;
+    }
+
+  for (i=1; i <= 12; i++)
+    {
+      elt = XVECEXP (op, 0, index++);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_SRC (elt)) != MEM
+         || GET_CODE (SET_DEST (elt)) != REG
+         || GET_MODE (SET_DEST (elt)) != V4SImode)
+       return 0;
+    }
+
+  for (i=1; i <= 18; i++)
+    {
+      elt = XVECEXP (op, 0, index++);
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_SRC (elt)) != MEM
+         || ! memory_operand (SET_SRC (elt), DFmode)
+         || GET_CODE (SET_DEST (elt)) != REG
+         || GET_MODE (SET_DEST (elt)) != DFmode)
+       return 0;
+    }
+
+  if (GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+      || GET_CODE (XVECEXP (op, 0, index++)) != CLOBBER
+      || GET_CODE (XVECEXP (op, 0, index++)) != USE)
+    return 0;
+  return 1;
+}
+
+\f
+/* Return 1 if OP is a load multiple operation.  It is known to be a
+   PARALLEL and the first section will be tested.  */
+
+int
+load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  int count = XVECLEN (op, 0);
+  unsigned int dest_regno;
+  rtx src_addr;
+  int i;
+
+  /* Perform a quick check so we don't blow up below.  */
+  if (count <= 1
+      || GET_CODE (XVECEXP (op, 0, 0)) != SET
+      || GET_CODE (SET_DEST (XVECEXP (op, 0, 0))) != REG
+      || GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != MEM)
+    return 0;
+
+  dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, 0)));
+  src_addr = XEXP (SET_SRC (XVECEXP (op, 0, 0)), 0);
+
+  for (i = 1; i < count; i++)
+    {
+      rtx elt = XVECEXP (op, 0, i);
+
+      if (GET_CODE (elt) != SET
+         || GET_CODE (SET_DEST (elt)) != REG
+         || GET_MODE (SET_DEST (elt)) != SImode
+         || REGNO (SET_DEST (elt)) != dest_regno + i
          || GET_CODE (SET_SRC (elt)) != MEM
          || GET_MODE (SET_SRC (elt)) != SImode
          || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
@@ -8825,6 +9408,26 @@ includes_rldicr_lshift_p (rtx shiftop, rtx andop)
     return 0;
 }
 
+/* Return 1 if operands will generate a valid arguments to rlwimi
+instruction for insert with right shift in 64-bit mode.  The mask may
+not start on the first bit or stop on the last bit because wrap-around
+effects of instruction do not correspond to semantics of RTL insn.  */
+
+int
+insvdi_rshift_rlwimi_p (rtx sizeop, rtx startop, rtx shiftop)
+{
+  if (INTVAL (startop) < 64
+      && INTVAL (startop) > 32
+      && (INTVAL (sizeop) + INTVAL (startop) < 64)
+      && (INTVAL (sizeop) + INTVAL (startop) > 33)
+      && (INTVAL (sizeop) + INTVAL (startop) + INTVAL (shiftop) < 96)
+      && (INTVAL (sizeop) + INTVAL (startop) + INTVAL (shiftop) >= 64)
+      && (64 - (INTVAL (shiftop) & 63)) >= INTVAL (sizeop))
+    return 1;
+
+  return 0;
+}
+
 /* Return 1 if REGNO (reg1) == REGNO (reg2) - 1 making them candidates
    for lfq and stfq insns iff the registers are hard registers.   */
 
@@ -9191,6 +9794,36 @@ rs6000_get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
   return 0;
 }
 
+/* Write out a function code label.  */
+
+void
+rs6000_output_function_entry (FILE *file, const char *fname)
+{
+  if (fname[0] != '.')
+    {
+      switch (DEFAULT_ABI)
+       {
+       default:
+         abort ();
+
+       case ABI_AIX:
+         if (DOT_SYMBOLS)
+           putc ('.', file);
+         else
+           ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "L.");
+         break;
+
+       case ABI_V4:
+       case ABI_DARWIN:
+         break;
+       }
+    }
+  if (TARGET_AIX)
+    RS6000_OUTPUT_BASENAME (file, fname);
+  else
+    assemble_name (file, fname);
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 #if TARGET_ELF
@@ -9256,12 +9889,12 @@ print_operand (FILE *file, rtx x, int code)
       return;
 
     case 'D':
-      /* Like 'J' but get to the GT bit.  */
+      /* Like 'J' but get to the EQ bit.  */
       if (GET_CODE (x) != REG)
        abort ();
 
-      /* Bit 1 is GT bit.  */
-      i = 4 * (REGNO (x) - CR0_REGNO) + 1;
+      /* Bit 1 is EQ bit.  */
+      i = 4 * (REGNO (x) - CR0_REGNO) + 2;
 
       /* If we want bit 31, write a shift count of zero, not 32.  */
       fprintf (file, "%d", i == 31 ? 0 : i + 1);
@@ -9723,37 +10356,21 @@ print_operand (FILE *file, rtx x, int code)
       if (SYMBOL_REF_DECL (x))
         mark_decl_referenced (SYMBOL_REF_DECL (x));
 
-      if (XSTR (x, 0)[0] != '.')
-       {
-         switch (DEFAULT_ABI)
-           {
-           default:
-             abort ();
-
-           case ABI_AIX:
-             putc ('.', file);
-             break;
-
-           case ABI_V4:
-           case ABI_DARWIN:
-             break;
-           }
-       }
-      /* For macho, we need to check it see if we need a stub.  */
+      /* For macho, check to see if we need a stub.  */
       if (TARGET_MACHO)
        {
          const char *name = XSTR (x, 0);
 #if TARGET_MACHO
          if (MACHOPIC_INDIRECT
-             && machopic_classify_name (name) == MACHOPIC_UNDEFINED_FUNCTION)
-           name = machopic_stub_name (name);
+             && machopic_classify_symbol (x) == MACHOPIC_UNDEFINED_FUNCTION)
+           name = machopic_indirection_name (x, /*stub_p=*/true);
 #endif
          assemble_name (file, name);
        }
-     else if (TARGET_AIX)
-       RS6000_OUTPUT_BASENAME (file, XSTR (x, 0));
-      else
+      else if (!DOT_SYMBOLS)
        assemble_name (file, XSTR (x, 0));
+      else
+       rs6000_output_function_entry (file, XSTR (x, 0));
       return;
 
     case 'Z':
@@ -10009,7 +10626,9 @@ rs6000_assemble_visibility (tree decl, int vis)
 {
   /* Functions need to have their entry point symbol visibility set as
      well as their descriptor symbol visibility.  */
-  if (DEFAULT_ABI == ABI_AIX && TREE_CODE (decl) == FUNCTION_DECL)
+  if (DEFAULT_ABI == ABI_AIX
+      && DOT_SYMBOLS
+      && TREE_CODE (decl) == FUNCTION_DECL)
     {
       static const char * const visibility_types[] = {
         NULL, "internal", "hidden", "protected"
@@ -10219,9 +10838,9 @@ rs6000_emit_sCOND (enum rtx_code code, rtx result)
        abort ();
 
       if (cond_code == NE)
-       emit_insn (gen_e500_flip_gt_bit (t, t));
+       emit_insn (gen_e500_flip_eq_bit (t, t));
 
-      emit_insn (gen_move_from_CR_gt_bit (result, t));
+      emit_insn (gen_move_from_CR_eq_bit (result, t));
       return;
     }
 
@@ -10402,9 +11021,9 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
   return string;
 }
 
-/* Return the string to flip the GT bit on a CR.  */
+/* Return the string to flip the EQ bit on a CR.  */
 char *
-output_e500_flip_gt_bit (rtx dst, rtx src)
+output_e500_flip_eq_bit (rtx dst, rtx src)
 {
   static char string[64];
   int a, b;
@@ -10413,9 +11032,9 @@ output_e500_flip_gt_bit (rtx dst, rtx src)
       || GET_CODE (src) != REG || ! CR_REGNO_P (REGNO (src)))
     abort ();
 
-  /* GT bit.  */
-  a = 4 * (REGNO (dst) - CR0_REGNO) + 1;
-  b = 4 * (REGNO (src) - CR0_REGNO) + 1;
+  /* EQ bit.  */
+  a = 4 * (REGNO (dst) - CR0_REGNO) + 2;
+  b = 4 * (REGNO (src) - CR0_REGNO) + 2;
 
   sprintf (string, "crnot %d,%d", a, b);
   return string;
@@ -10708,7 +11327,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
       int j = -1;
       bool used_update = false;
 
-      if (GET_CODE (src) == MEM && INT_REGNO_P (reg))
+      if (MEM_P (src) && INT_REGNO_P (reg))
         {
           rtx breg;
 
@@ -10725,6 +11344,15 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                         : gen_adddi3 (breg, breg, delta_rtx));
              src = gen_rtx_MEM (mode, breg);
            }
+         else if (! offsettable_memref_p (src))
+           {
+             rtx newsrc, basereg;
+             basereg = gen_rtx_REG (Pmode, reg);
+             emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0)));
+             newsrc = gen_rtx_MEM (GET_MODE (src), basereg);
+             MEM_COPY_ATTRIBUTES (newsrc, src);
+             src = newsrc;
+           }
 
          /* We have now address involving an base register only.
             If we use one of the registers to address memory, 
@@ -10772,6 +11400,8 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                           : gen_adddi3 (breg, breg, delta_rtx));
              dst = gen_rtx_MEM (mode, breg);
            }
+         else if (! offsettable_memref_p (dst))
+           abort ();
        }
 
       for (i = 0; i < nregs; i++)
@@ -10813,7 +11443,8 @@ first_reg_to_save (void)
        && (! call_used_regs[first_reg]
            || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
                && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic)))))
+                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic)
+                   || (TARGET_TOC && TARGET_MINIMAL_TOC)))))
       break;
 
 #if TARGET_MACHO
@@ -10896,6 +11527,57 @@ compute_vrsave_mask (void)
   return mask;
 }
 
+/* For a very restricted set of circumstances, we can cut down the
+   size of prologs/epilogs by calling our own save/restore-the-world
+   routines. */
+
+static void
+compute_save_world_info(rs6000_stack_t *info_ptr)
+{
+  info_ptr->world_save_p =
+    (DEFAULT_ABI == ABI_DARWIN)
+    && ! (current_function_calls_setjmp && flag_exceptions)
+    && info_ptr->first_fp_reg_save == FIRST_SAVED_FP_REGNO
+    && info_ptr->first_gp_reg_save == FIRST_SAVED_GP_REGNO
+    && info_ptr->first_altivec_reg_save == FIRST_SAVED_ALTIVEC_REGNO
+    && info_ptr->cr_save_p;
+  
+  /* This will not work in conjunction with sibcalls.  Make sure there
+     are none.  (This check is expensive, but seldom executed.) */
+  if ( info_ptr->world_save_p )
+    { 
+      rtx insn;
+      for ( insn = get_last_insn_anywhere (); insn; insn = PREV_INSN (insn))
+        if ( GET_CODE (insn) == CALL_INSN
+             && SIBLING_CALL_P (insn))
+          { 
+            info_ptr->world_save_p = 0;
+            break;
+          }
+    }
+  
+  if (info_ptr->world_save_p)
+    {
+      /* Even if we're not touching VRsave, make sure there's room on the
+        stack for it, if it looks like we're calling SAVE_WORLD, which
+         will attempt to save it. */
+      info_ptr->vrsave_size  = 4;
+
+      /* "Save" the VRsave register too if we're saving the world.  */
+      if (info_ptr->vrsave_mask == 0)
+        info_ptr->vrsave_mask = compute_vrsave_mask ();
+
+      /* Because the Darwin register save/restore routines only handle
+         F14 .. F31 and V20 .. V31 as per the ABI, perform a consistancy
+         check and abort if there's something worng.  */
+      if (info_ptr->first_fp_reg_save < FIRST_SAVED_FP_REGNO 
+          || info_ptr->first_altivec_reg_save < FIRST_SAVED_ALTIVEC_REGNO)
+        abort ();
+    }
+  return; 
+}
+
+
 static void
 is_altivec_return_reg (rtx reg, void *xyes)
 {
@@ -11136,6 +11818,8 @@ rs6000_stack_info (void)
   else
     info_ptr->vrsave_size  = 0;
 
+  compute_save_world_info (info_ptr);
+
   /* Calculate the offsets.  */
   switch (DEFAULT_ABI)
     {
@@ -12198,6 +12882,10 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
   return gen_rtx_MEM (mode, gen_rtx_PLUS (Pmode, reg, offset_rtx));
 }
 
+#ifndef TARGET_FIX_AND_CONTINUE
+#define TARGET_FIX_AND_CONTINUE 0
+#endif
+
 /* Emit function prologue as insns.  */
 
 void
@@ -12215,11 +12903,24 @@ rs6000_emit_prologue (void)
   int using_store_multiple;
   HOST_WIDE_INT sp_offset = 0;
   
-   if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-     {
-       reg_mode = V2SImode;
-       reg_size = 8;
-     }
+  if (TARGET_FIX_AND_CONTINUE)
+    {
+      /* gdb on darwin arranges to forward a function from the old
+        address by modifying the first 4 instructions of the function
+        to branch to the overriding function.  This is necessary to
+        permit function pointers that point to the old function to
+        actually forward to the new function.  */
+      emit_insn (gen_nop ());
+      emit_insn (gen_nop ());
+      emit_insn (gen_nop ());
+      emit_insn (gen_nop ());
+    }
+
+  if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
+    {
+      reg_mode = V2SImode;
+      reg_size = 8;
+    }
 
   using_store_multiple = (TARGET_MULTIPLE && ! TARGET_POWERPC64
                          && (!TARGET_SPE_ABI
@@ -12250,8 +12951,128 @@ rs6000_emit_prologue (void)
        rs6000_emit_stack_tie ();
     }
 
+  /* Handle world saves specially here.  */
+  if (info->world_save_p)
+    {
+      int i, j, sz;
+      rtx treg;
+      rtvec p;
+
+      /* save_world expects lr in r0. */
+      if (info->lr_save_p)
+        {
+          insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+                                gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+          RTX_FRAME_RELATED_P (insn) = 1;
+        }
+
+      /* The SAVE_WORLD and RESTORE_WORLD routines make a number of
+         assumptions about the offsets of various bits of the stack
+         frame.  Abort if things aren't what they should be.  */
+      if (info->gp_save_offset != -220
+          || info->fp_save_offset != -144
+          || info->lr_save_offset != 8
+          || info->cr_save_offset != 4
+          || !info->push_p
+          || !info->lr_save_p
+          || (current_function_calls_eh_return && info->ehrd_offset != -432)
+          || (info->vrsave_save_offset != -224
+              || info->altivec_save_offset != (-224 -16 -192)))
+        abort ();
+
+      treg = gen_rtx_REG (SImode, 11);
+      emit_move_insn (treg, GEN_INT (-info->total_size));
+
+      /* SAVE_WORLD takes the caller's LR in R0 and the frame size
+         in R11.  It also clobbers R12, so beware!  */
+
+      /* Preserve CR2 for save_world prologues */
+      sz = 6;
+      sz += 32 - info->first_gp_reg_save;
+      sz += 64 - info->first_fp_reg_save;
+      sz += LAST_ALTIVEC_REGNO - info->first_altivec_reg_save + 1;
+      p = rtvec_alloc (sz);
+      j = 0;
+      RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode,
+                                            gen_rtx_REG (Pmode,
+                                                         LINK_REGISTER_REGNUM));
+      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
+                                        gen_rtx_SYMBOL_REF (Pmode,
+                                                            "*save_world"));
+      /* We do floats first so that the instruction pattern matches
+         properly.  */
+     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
+        {
+          rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->fp_save_offset
+                                            + sp_offset + 8 * i));
+          rtx mem = gen_rtx_MEM (DFmode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+        }
+      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
+        {
+          rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->altivec_save_offset
+                                            + sp_offset + 16 * i));
+          rtx mem = gen_rtx_MEM (V4SImode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+        }
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+        {
+          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->gp_save_offset
+                                            + sp_offset + reg_size * i));
+          rtx mem = gen_rtx_MEM (reg_mode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+        }
+
+        {
+          /* CR register traditionally saved as CR2.  */
+          rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->cr_save_offset
+                                            + sp_offset));
+          rtx mem = gen_rtx_MEM (reg_mode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg);
+        }
+      /* Prevent any attempt to delete the setting of r0 and treg!  */
+      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
+      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode, treg);
+      RTVEC_ELT (p, j++) = gen_rtx_CLOBBER (VOIDmode, sp_reg_rtx);
+
+      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                            NULL_RTX, NULL_RTX);
+
+      if (current_function_calls_eh_return)
+        {
+          unsigned int i;
+          for (i = 0; ; ++i)
+            {
+              unsigned int regno = EH_RETURN_DATA_REGNO (i);
+              if (regno == INVALID_REGNUM)
+                break;
+              emit_frame_save (frame_reg_rtx, frame_ptr_rtx, reg_mode, regno,
+                               info->ehrd_offset + sp_offset
+                               + reg_size * (int) i,
+                               info->total_size);
+            }
+        }
+    }
+
   /* Save AltiVec registers if needed.  */
-  if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+  if (! info->world_save_p && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
     {
       int i;
 
@@ -12292,7 +13113,7 @@ rs6000_emit_prologue (void)
      epilogue.  */
 
   if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && info->vrsave_mask != 0)
+      && ! info->world_save_p && info->vrsave_mask != 0)
     {
       rtx reg, mem, vrsave;
       int offset;
@@ -12320,20 +13141,37 @@ rs6000_emit_prologue (void)
     }
 
   /* If we use the link register, get it into r0.  */
-  if (info->lr_save_p)
-    emit_move_insn (gen_rtx_REG (Pmode, 0),
-                   gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+  if (! info->world_save_p && info->lr_save_p)
+    {
+      insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
+                            gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+      RTX_FRAME_RELATED_P (insn) = 1;
+    }
 
   /* If we need to save CR, put it into r12.  */
-  if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
+  if (! info->world_save_p && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
     {
+      rtx set;
+      
       cr_save_rtx = gen_rtx_REG (SImode, 12);
-      emit_insn (gen_movesi_from_cr (cr_save_rtx));
+      insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
+      RTX_FRAME_RELATED_P (insn) = 1;
+      /* Now, there's no way that dwarf2out_frame_debug_expr is going
+        to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
+        But that's OK.  All we have to do is specify that _one_ condition
+        code register is saved in this stack slot.  The thrower's epilogue
+        will then restore all the call-saved registers.
+        We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
+      set = gen_rtx_SET (VOIDmode, cr_save_rtx,
+                        gen_rtx_REG (SImode, CR2_REGNO));
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                           set,
+                                           REG_NOTES (insn));
     }
 
   /* Do any required saving of fpr's.  If only one or two to save, do
      it ourselves.  Otherwise, call function.  */
-  if (saving_FPRs_inline)
+  if (! info->world_save_p && saving_FPRs_inline)
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
@@ -12344,7 +13182,7 @@ rs6000_emit_prologue (void)
                           info->fp_save_offset + sp_offset + 8 * i,
                           info->total_size);
     }
-  else if (info->first_fp_reg_save != 64)
+  else if (! info->world_save_p && info->first_fp_reg_save != 64)
     {
       int i;
       char rname[30];
@@ -12380,7 +13218,7 @@ rs6000_emit_prologue (void)
 
   /* Save GPRs.  This is done as a PARALLEL if we are using
      the store-multiple instructions.  */
-  if (using_store_multiple)
+  if (! info->world_save_p && using_store_multiple)
     {
       rtvec p;
       int i;
@@ -12402,12 +13240,15 @@ rs6000_emit_prologue (void)
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
                            NULL_RTX, NULL_RTX);
     }
-  else
+  else if (! info->world_save_p)
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
        if ((regs_ever_live[info->first_gp_reg_save+i] 
-            && ! call_used_regs[info->first_gp_reg_save+i])
+            && (! call_used_regs[info->first_gp_reg_save+i]
+                || (i+info->first_gp_reg_save
+                    == RS6000_PIC_OFFSET_TABLE_REGNUM
+                    && TARGET_TOC && TARGET_MINIMAL_TOC)))
            || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
                && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                    || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
@@ -12458,7 +13299,7 @@ rs6000_emit_prologue (void)
 
   /* ??? There's no need to emit actual instructions here, but it's the
      easiest way to get the frame unwind information emitted.  */
-  if (current_function_calls_eh_return)
+  if (! info->world_save_p && current_function_calls_eh_return)
     {
       unsigned int i, regno;
 
@@ -12493,7 +13334,7 @@ rs6000_emit_prologue (void)
     }
 
   /* Save lr if we used it.  */
-  if (info->lr_save_p)
+  if (! info->world_save_p && info->lr_save_p)
     {
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                               GEN_INT (info->lr_save_offset + sp_offset));
@@ -12504,15 +13345,17 @@ rs6000_emit_prologue (void)
       
       insn = emit_move_insn (mem, reg);
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-                           reg, gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+                           NULL_RTX, NULL_RTX);
     }
 
   /* Save CR if we use any that must be preserved.  */
-  if (info->cr_save_p)
+  if (! info->world_save_p && info->cr_save_p)
     {
       rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                               GEN_INT (info->cr_save_offset + sp_offset));
       rtx mem = gen_rtx_MEM (SImode, addr);
+      /* See the large comment above about why CR2_REGNO is used.  */
+      rtx magic_eh_cr_reg = gen_rtx_REG (SImode, CR2_REGNO);
 
       set_mem_alias_set (mem, rs6000_sr_alias_set);
 
@@ -12520,24 +13363,26 @@ rs6000_emit_prologue (void)
         that it's free.  */
       if (REGNO (frame_reg_rtx) == 12)
        {
+         rtx set;
+
          cr_save_rtx = gen_rtx_REG (SImode, 0);
-         emit_insn (gen_movesi_from_cr (cr_save_rtx));
+         insn = emit_insn (gen_movesi_from_cr (cr_save_rtx));
+         RTX_FRAME_RELATED_P (insn) = 1;
+         set = gen_rtx_SET (VOIDmode, cr_save_rtx, magic_eh_cr_reg);
+         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                               set,
+                                               REG_NOTES (insn));
+         
        }
       insn = emit_move_insn (mem, cr_save_rtx);
 
-      /* Now, there's no way that dwarf2out_frame_debug_expr is going
-        to understand '(unspec:SI [(reg:CC 68) ...] UNSPEC_MOVESI_FROM_CR)'.
-        But that's OK.  All we have to do is specify that _one_ condition
-        code register is saved in this stack slot.  The thrower's epilogue
-        will then restore all the call-saved registers.
-        We use CR2_REGNO (70) to be compatible with gcc-2.95 on Linux.  */
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, 
-                           cr_save_rtx, gen_rtx_REG (SImode, CR2_REGNO));
+                           NULL_RTX, NULL_RTX);
     }
 
   /* Update stack and set back pointer unless this is V.4, 
      for which it was done previously.  */
-  if (info->push_p
+  if (! info->world_save_p && info->push_p
       && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
     rs6000_emit_allocate_stack (info->total_size, FALSE);
 
@@ -12566,9 +13411,16 @@ rs6000_emit_prologue (void)
     if (save_LR_around_toc_setup)
       {
        rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
-       rs6000_maybe_dead (emit_move_insn (frame_ptr_rtx, lr));
+
+       insn = emit_move_insn (frame_ptr_rtx, lr);
+       rs6000_maybe_dead (insn);
+       RTX_FRAME_RELATED_P (insn) = 1;
+
        rs6000_emit_load_toc_table (TRUE);
-       rs6000_maybe_dead (emit_move_insn (lr, frame_ptr_rtx));
+
+       insn = emit_move_insn (lr, frame_ptr_rtx);
+       rs6000_maybe_dead (insn);
+       RTX_FRAME_RELATED_P (insn) = 1;
       }
     else
       rs6000_emit_load_toc_table (TRUE);
@@ -12578,15 +13430,15 @@ rs6000_emit_prologue (void)
   if (DEFAULT_ABI == ABI_DARWIN
       && flag_pic && current_function_uses_pic_offset_table)
     {
-      rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
-      const char *picbase = machopic_function_base_name ();
-      rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
+      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+      rtx src = machopic_function_base_sym ();
 
-      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
+      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
 
-      rs6000_maybe_dead (
-       emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
-                       gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
+      insn = emit_move_insn (gen_rtx_REG (Pmode, 
+                                         RS6000_PIC_OFFSET_TABLE_REGNUM),
+                            lr);
+      rs6000_maybe_dead (insn);
     }
 #endif
 }
@@ -12699,6 +13551,101 @@ rs6000_emit_epilogue (int sibcall)
                         || rs6000_cpu == PROCESSOR_PPC750
                         || optimize_size);
 
+  if (info->world_save_p)
+    {
+      int i, j;
+      char rname[30];
+      const char *alloc_rname;
+      rtvec p;
+
+      /* eh_rest_world_r10 will return to the location saved in the LR
+         stack slot (which is not likely to be our caller.)
+         Input: R10 -- stack adjustment.  Clobbers R0, R11, R12, R7, R8.
+         rest_world is similar, except any R10 parameter is ignored.
+         The exception-handling stuff that was here in 2.95 is no
+         longer necessary.  */
+
+      p = rtvec_alloc (9
+                      + 1
+                      + 32 - info->first_gp_reg_save 
+                       + LAST_ALTIVEC_REGNO + 1 - info->first_altivec_reg_save
+                       + 63 + 1 - info->first_fp_reg_save);
+
+      strcpy (rname, (current_function_calls_eh_return) ?
+                        "*eh_rest_world_r10" : "*rest_world");
+      alloc_rname = ggc_strdup (rname);
+
+      j = 0;
+      RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
+      RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
+                                        gen_rtx_REG (Pmode,
+                                                     LINK_REGISTER_REGNUM));
+      RTVEC_ELT (p, j++)
+        = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
+      /* The instruction pattern requires a clobber here;
+         it is shared with the restVEC helper. */
+      RTVEC_ELT (p, j++)
+        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 11));
+
+      {
+        /* CR register traditionally saved as CR2.  */
+        rtx reg = gen_rtx_REG (reg_mode, CR2_REGNO);
+        rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                 GEN_INT (info->cr_save_offset));
+        rtx mem = gen_rtx_MEM (reg_mode, addr);
+        set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+        RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+      }
+
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+        {
+          rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->gp_save_offset
+                                            + reg_size * i));
+          rtx mem = gen_rtx_MEM (reg_mode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+      }
+      for (i = 0; info->first_altivec_reg_save + i <= LAST_ALTIVEC_REGNO; i++)
+        {
+          rtx reg = gen_rtx_REG (V4SImode, info->first_altivec_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->altivec_save_offset
+                                            + 16 * i));
+          rtx mem = gen_rtx_MEM (V4SImode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+        }
+      for (i = 0; info->first_fp_reg_save + i <= 63; i++)
+        {
+          rtx reg = gen_rtx_REG (DFmode, info->first_fp_reg_save + i);
+          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                   GEN_INT (info->fp_save_offset
+                                            + 8 * i));
+          rtx mem = gen_rtx_MEM (DFmode, addr);
+          set_mem_alias_set (mem, rs6000_sr_alias_set);
+
+          RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, reg, mem);
+        }
+      RTVEC_ELT (p, j++)
+        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 0));
+      RTVEC_ELT (p, j++)
+        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 12));
+      RTVEC_ELT (p, j++)
+        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 7));
+      RTVEC_ELT (p, j++)
+        = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 8));
+      RTVEC_ELT (p, j++)
+        = gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, 10));
+      emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, p));
+
+      return;
+    }
+
   /* If we have a frame pointer, a call to alloca,  or a large stack
      frame, restore the old stack pointer using the backchain.  Otherwise,
      we know what size to update it with.  */
@@ -12856,7 +13803,9 @@ rs6000_emit_epilogue (int sibcall)
   else
     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
       if ((regs_ever_live[info->first_gp_reg_save+i] 
-          && ! call_used_regs[info->first_gp_reg_save+i])
+          && (! call_used_regs[info->first_gp_reg_save+i]
+              || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
+                  && TARGET_TOC && TARGET_MINIMAL_TOC)))
          || (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
              && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
@@ -13289,17 +14238,12 @@ rs6000_output_function_epilogue (FILE *file,
       /* Offset from start of code to tb table.  */
       fputs ("\t.long ", file);
       ASM_OUTPUT_INTERNAL_LABEL_PREFIX (file, "LT");
-#if TARGET_AIX
-      RS6000_OUTPUT_BASENAME (file, fname);
-#else
-      assemble_name (file, fname);
-#endif
-      fputs ("-.", file);
-#if TARGET_AIX
-      RS6000_OUTPUT_BASENAME (file, fname);
-#else
-      assemble_name (file, fname);
-#endif
+      if (TARGET_AIX)
+       RS6000_OUTPUT_BASENAME (file, fname);
+      else
+       assemble_name (file, fname);
+      putc ('-', file);
+      rs6000_output_function_entry (file, fname);
       putc ('\n', file);
 
       /* Interrupt handler mask.  */
@@ -13371,6 +14315,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   reload_completed = 1;
   epilogue_completed = 1;
   no_new_pseudos = 1;
+  reset_block_changes ();
 
   /* Mark the end of the (empty) prologue.  */
   emit_note (NOTE_INSN_PROLOGUE_END);
@@ -14073,12 +15018,9 @@ output_profile_hook (int labelno ATTRIBUTE_UNUSED)
 #if TARGET_MACHO
       /* For PIC code, set up a stub and collect the caller's address
         from r0, which is where the prologue puts it.  */
-      if (MACHOPIC_INDIRECT)
-       {
-         mcount_name = machopic_stub_name (mcount_name);
-         if (current_function_uses_pic_offset_table)
-           caller_addr_regno = 0;
-       }
+      if (MACHOPIC_INDIRECT
+         && current_function_uses_pic_offset_table)
+       caller_addr_regno = 0;
 #endif
       emit_library_call (gen_rtx_SYMBOL_REF (Pmode, mcount_name),
                         0, VOIDmode, 1,
@@ -14179,12 +15121,6 @@ output_function_profiler (FILE *file, int labelno)
 }
 
 \f
-static int
-rs6000_use_dfa_pipeline_interface (void)
-{
-  return 1;
-}
-
 /* Power4 load update and store update instructions are cracked into a
    load or store and an integer insn which are executed in the same cycle.
    Branches have their own dispatch slot which does not count against the
@@ -15496,7 +16432,7 @@ static void
 add_compiler_branch_island (tree label_name, tree function_name, int line_number)
 {
   tree branch_island = build_tree_list (function_name, label_name);
-  TREE_TYPE (branch_island) = build_int_2 (line_number, 0);
+  TREE_TYPE (branch_island) = build_int_cst (NULL_TREE, line_number, 0);
   TREE_CHAIN (branch_island) = branch_island_list;
   branch_island_list = branch_island;
 }
@@ -15525,8 +16461,7 @@ macho_branch_islands (void)
       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)));
+       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] == '&')
@@ -15688,13 +16623,14 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
     machopic_picsymbol_stub1_section ();
   else
     machopic_symbol_stub1_section ();
-  fprintf (file, "\t.align 2\n");
-
-  fprintf (file, "%s:\n", stub);
-  fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
 
   if (flag_pic == 2)
     {
+      fprintf (file, "\t.align 5\n");
+
+      fprintf (file, "%s:\n", stub);
+      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
+
       label++;
       local_label_0 = alloca (sizeof("\"L0000000000$spb\""));
       sprintf (local_label_0, "\"L%011d$spb\"", label);
@@ -15711,17 +16647,23 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\tbctr\n");
     }
   else
-   {
-     fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
-     fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
-     fprintf (file, "\tmtctr r12\n");
-     fprintf (file, "\tbctr\n");
-   }
+    {
+      fprintf (file, "\t.align 4\n");
+
+      fprintf (file, "%s:\n", stub);
+      fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
+
+      fprintf (file, "\tlis r11,ha16(%s)\n", lazy_ptr_name);
+      fprintf (file, "\tlwzu r12,lo16(%s)(r11)\n", lazy_ptr_name);
+      fprintf (file, "\tmtctr r12\n");
+      fprintf (file, "\tbctr\n");
+    }
   
   machopic_lazy_symbol_ptr_section ();
   fprintf (file, "%s:\n", lazy_ptr_name);
   fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
-  fprintf (file, "\t.long dyld_stub_binding_helper\n");
+  fprintf (file, "%sdyld_stub_binding_helper\n",
+          (TARGET_64BIT ? DOUBLE_INT_ASM_OP : "\t.long\t"));
 }
 
 /* Legitimize PIC addresses.  If the address is already
@@ -15874,22 +16816,27 @@ rs6000_elf_declare_function_name (FILE *file, const char *name, tree decl)
       fputs ("\t.section\t\".opd\",\"aw\"\n\t.align 3\n", file);
       ASM_OUTPUT_LABEL (file, name);
       fputs (DOUBLE_INT_ASM_OP, file);
-      putc ('.', file);
-      assemble_name (file, name);
-      fputs (",.TOC.@tocbase,0\n\t.previous\n\t.size\t", file);
-      assemble_name (file, name);
-      fputs (",24\n\t.type\t.", file);
-      assemble_name (file, name);
-      fputs (",@function\n", file);
-      if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+      rs6000_output_function_entry (file, name);
+      fputs (",.TOC.@tocbase,0\n\t.previous\n", file);
+      if (DOT_SYMBOLS)
        {
-         fputs ("\t.globl\t.", file);
+         fputs ("\t.size\t", file);
+         assemble_name (file, name);
+         fputs (",24\n\t.type\t.", file);
          assemble_name (file, name);
-         putc ('\n', file);
+         fputs (",@function\n", file);
+         if (TREE_PUBLIC (decl) && ! DECL_WEAK (decl))
+           {
+             fputs ("\t.globl\t.", file);
+             assemble_name (file, name);
+             putc ('\n', file);
+           }
        }
+      else
+       ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
       ASM_DECLARE_RESULT (file, DECL_RESULT (decl));
-      putc ('.', file);
-      ASM_OUTPUT_LABEL (file, name);
+      rs6000_output_function_entry (file, name);
+      fputs (":\n", file);
       return;
     }
 
@@ -16122,221 +17069,317 @@ static bool
 rs6000_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, 
                  int *total)
 {
+  enum machine_mode mode = GET_MODE (x);
+
   switch (code)
     {
-      /* On the RS/6000, if it is valid in the insn, it is free.
-        So this always returns 0.  */
+      /* On the RS/6000, if it is valid in the insn, it is free.  */
     case CONST_INT:
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-    case CONST_DOUBLE:
-    case HIGH:
-      *total = 0;
-      return true;
-
-    case PLUS:
-      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
-                && ((unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1))
-                                              + 0x8000) >= 0x10000)
-                && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
-               ? COSTS_N_INSNS (2)
-               : COSTS_N_INSNS (1));
-      return true;
-
-    case AND:
-    case IOR:
-    case XOR:
-      *total = ((GET_CODE (XEXP (x, 1)) == CONST_INT
-                && (INTVAL (XEXP (x, 1)) & (~ (HOST_WIDE_INT) 0xffff)) != 0
-                && ((INTVAL (XEXP (x, 1)) & 0xffff) != 0))
-               ? COSTS_N_INSNS (2)
-               : COSTS_N_INSNS (1));
-      return true;
-
-    case MULT:
-      if (optimize_size)
+      if (((outer_code == SET
+           || outer_code == PLUS
+           || outer_code == MINUS)
+          && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+              || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
+         || ((outer_code == IOR || outer_code == XOR)
+             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
+         || ((outer_code == DIV || outer_code == UDIV
+              || outer_code == MOD || outer_code == UMOD)
+             && exact_log2 (INTVAL (x)) >= 0)
+         || (outer_code == AND
+             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+                 || mask_operand (x, VOIDmode)))
+         || outer_code == ASHIFT
+         || outer_code == ASHIFTRT
+         || outer_code == LSHIFTRT
+         || outer_code == ROTATE
+         || outer_code == ROTATERT
+         || outer_code == ZERO_EXTRACT
+         || (outer_code == MULT
+             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+         || (outer_code == COMPARE
+             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
+                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K'))))
        {
-         *total = COSTS_N_INSNS (2);
+         *total = 0;
          return true;
        }
-      switch (rs6000_cpu)
+      else if ((outer_code == PLUS
+               && reg_or_add_cint64_operand (x, VOIDmode))
+              || (outer_code == MINUS
+                  && reg_or_sub_cint64_operand (x, VOIDmode))
+              || ((outer_code == SET
+                   || outer_code == IOR
+                   || outer_code == XOR)
+                  && (INTVAL (x)
+                      & ~ (unsigned HOST_WIDE_INT) 0xffffffff) == 0))
        {
-       case PROCESSOR_RIOS1:
-       case PROCESSOR_PPC405:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? COSTS_N_INSNS (5)
-                   : (INTVAL (XEXP (x, 1)) >= -256
-                      && INTVAL (XEXP (x, 1)) <= 255)
-                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
-         return true;
-
-       case PROCESSOR_PPC440:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? COSTS_N_INSNS (3)
-                   : COSTS_N_INSNS (2));
-         return true;
-
-       case PROCESSOR_RS64A:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
-                   : (INTVAL (XEXP (x, 1)) >= -256
-                      && INTVAL (XEXP (x, 1)) <= 255)
-                   ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
-         return true;
-
-       case PROCESSOR_RIOS2:
-       case PROCESSOR_MPCCORE:
-       case PROCESSOR_PPC604e:
-         *total = COSTS_N_INSNS (2);
+         *total = COSTS_N_INSNS (1);
          return true;
+       }
+      /* FALLTHRU */
 
-       case PROCESSOR_PPC601:
-         *total = COSTS_N_INSNS (5);
+    case CONST_DOUBLE:
+      if (mode == DImode
+         && ((outer_code == AND
+              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
+                  || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
+                  || mask64_operand (x, DImode)))
+             || ((outer_code == IOR || outer_code == XOR)
+                 && CONST_DOUBLE_HIGH (x) == 0
+                 && (CONST_DOUBLE_LOW (x)
+                     & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)))
+       {
+         *total = 0;
          return true;
-
-       case PROCESSOR_PPC603:
-       case PROCESSOR_PPC7400:
-       case PROCESSOR_PPC750:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? COSTS_N_INSNS (5)
-                   : (INTVAL (XEXP (x, 1)) >= -256
-                      && INTVAL (XEXP (x, 1)) <= 255)
-                   ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
+       }
+      else if (mode == DImode
+              && (outer_code == SET
+                  || outer_code == IOR
+                  || outer_code == XOR)
+              && CONST_DOUBLE_HIGH (x) == 0)
+       {
+         *total = COSTS_N_INSNS (1);
          return true;
+       }
+      /* FALLTHRU */
 
-       case PROCESSOR_PPC7450:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? COSTS_N_INSNS (4)
-                   : COSTS_N_INSNS (3));
-         return true;
+    case CONST:
+    case HIGH:
+    case SYMBOL_REF:
+    case MEM:
+      /* When optimizing for size, MEM should be slightly more expensive
+        than generating address, e.g., (plus (reg) (const)).
+        L1 cache latecy is about two instructions.  */
+      *total = optimize_size ? COSTS_N_INSNS (1) + 1 : COSTS_N_INSNS (2);
+      return true;
 
-       case PROCESSOR_PPC403:
-       case PROCESSOR_PPC604:
-       case PROCESSOR_PPC8540:
-         *total = COSTS_N_INSNS (4);
-         return true;
+    case LABEL_REF:
+      *total = 0;
+      return true;
 
-       case PROCESSOR_PPC620:
-       case PROCESSOR_PPC630:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
-                   : (INTVAL (XEXP (x, 1)) >= -256
-                      && INTVAL (XEXP (x, 1)) <= 255)
-                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
-         return true;
+    case PLUS:
+      if (mode == DFmode)
+       {
+         if (GET_CODE (XEXP (x, 0)) == MULT)
+           {
+             /* FNMA accounted in outer NEG.  */
+             if (outer_code == NEG)
+               *total = rs6000_cost->dmul - rs6000_cost->fp;
+             else
+               *total = rs6000_cost->dmul;
+           }
+         else
+           *total = rs6000_cost->fp;
+       }
+      else if (mode == SFmode)
+       {
+         /* FNMA accounted in outer NEG.  */
+         if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
+           *total = 0;
+         else
+           *total = rs6000_cost->fp;
+       }
+      else if (GET_CODE (XEXP (x, 0)) == MULT)
+       {
+         /* The rs6000 doesn't have shift-and-add instructions.  */
+         rs6000_rtx_costs (XEXP (x, 0), MULT, PLUS, total);
+         *total += COSTS_N_INSNS (1);
+       }
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-       case PROCESSOR_POWER4:
-       case PROCESSOR_POWER5:
-         *total = (GET_CODE (XEXP (x, 1)) != CONST_INT
-                   ? GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4)
-                   : COSTS_N_INSNS (2));
-         return true;
+    case MINUS:
+      if (mode == DFmode)
+       {
+         if (GET_CODE (XEXP (x, 0)) == MULT)
+           {
+             /* FNMA accounted in outer NEG.  */
+             if (outer_code == NEG)
+               *total = 0;
+             else
+               *total = rs6000_cost->dmul;
+           }
+         else
+           *total = rs6000_cost->fp;
+       }
+      else if (mode == SFmode)
+       {
+         /* FNMA accounted in outer NEG.  */
+         if (outer_code == NEG && GET_CODE (XEXP (x, 0)) == MULT)
+           *total = 0;
+         else
+           *total = rs6000_cost->fp;
+       }
+      else if (GET_CODE (XEXP (x, 0)) == MULT)
+       {
+         /* The rs6000 doesn't have shift-and-sub instructions.  */
+         rs6000_rtx_costs (XEXP (x, 0), MULT, MINUS, total);
+         *total += COSTS_N_INSNS (1);
+       }
+      else
+        *total = COSTS_N_INSNS (1);
+      return false;
 
-       default:
-         abort ();
+    case MULT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+       {
+         if (INTVAL (XEXP (x, 1)) >= -256
+             && INTVAL (XEXP (x, 1)) <= 255)
+           *total = rs6000_cost->mulsi_const9;
+         else
+           *total = rs6000_cost->mulsi_const;
        }
+      /* FMA accounted in outer PLUS/MINUS.  */
+      else if ((mode == DFmode || mode == SFmode)
+              && (outer_code == PLUS || outer_code == MINUS))
+       *total = 0;
+      else if (mode == DFmode)
+       *total = rs6000_cost->dmul;
+      else if (mode == SFmode)
+       *total = rs6000_cost->fp;
+      else if (mode == DImode)
+       *total = rs6000_cost->muldi;
+      else
+       *total = rs6000_cost->mulsi;
+      return false;
 
     case DIV:
     case MOD:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
+      if (FLOAT_MODE_P (mode))
        {
-         *total = COSTS_N_INSNS (2);
-         return true;
+         *total = mode == DFmode ? rs6000_cost->ddiv
+                                 : rs6000_cost->sdiv;
+         return false;
        }
       /* FALLTHRU */
 
     case UDIV:
     case UMOD:
-      switch (rs6000_cpu)
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && exact_log2 (INTVAL (XEXP (x, 1))) >= 0)
        {
-       case PROCESSOR_RIOS1:
-         *total = COSTS_N_INSNS (19);
-         return true;
-
-       case PROCESSOR_RIOS2:
-         *total = COSTS_N_INSNS (13);
-         return true;
-
-       case PROCESSOR_RS64A:
-         *total = (GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (65)
-                   : COSTS_N_INSNS (67));
-         return true;
-
-       case PROCESSOR_MPCCORE:
-         *total = COSTS_N_INSNS (6);
-         return true;
-
-       case PROCESSOR_PPC403:
-         *total = COSTS_N_INSNS (33);
-         return true;
-
-       case PROCESSOR_PPC405:
-         *total = COSTS_N_INSNS (35);
-         return true;
+         if (code == DIV || code == MOD)
+           /* Shift, addze */
+           *total = COSTS_N_INSNS (2);
+         else
+           /* Shift */
+           *total = COSTS_N_INSNS (1);
+       }
+      else 
+       {
+         if (GET_MODE (XEXP (x, 1)) == DImode)
+           *total = rs6000_cost->divdi;
+         else
+           *total = rs6000_cost->divsi;
+       }
+      /* Add in shift and subtract for MOD. */
+      if (code == MOD || code == UMOD)
+       *total += COSTS_N_INSNS (2);
+      return false;
 
-       case PROCESSOR_PPC440:
-         *total = COSTS_N_INSNS (34);
-         return true;
+    case FFS:
+      *total = COSTS_N_INSNS (4);
+      return false;
 
-       case PROCESSOR_PPC601:
-         *total = COSTS_N_INSNS (36);
-         return true;
+    case NOT:
+      if (outer_code == AND || outer_code == IOR || outer_code == XOR)
+       {
+         *total = 0;
+         return false;
+       }
+      /* FALLTHRU */
 
-       case PROCESSOR_PPC603:
-         *total = COSTS_N_INSNS (37);
-         return true;
+    case AND:
+    case IOR:
+    case XOR:
+    case ZERO_EXTRACT:
+      *total = COSTS_N_INSNS (1);
+      return false;
 
-       case PROCESSOR_PPC604:
-       case PROCESSOR_PPC604e:
-         *total = COSTS_N_INSNS (20);
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+    case ROTATE:
+    case ROTATERT:
+      /* Handle mul_highpart.  */
+      if (outer_code == TRUNCATE
+         && GET_CODE (XEXP (x, 0)) == MULT)
+       {
+         if (mode == DImode)
+           *total = rs6000_cost->muldi;
+         else
+           *total = rs6000_cost->mulsi;
          return true;
+       }
+      else if (outer_code == AND)
+       *total = 0;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-       case PROCESSOR_PPC620:
-       case PROCESSOR_PPC630:
-         *total = (GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (21)
-                   : COSTS_N_INSNS (37));
-         return true;
+    case SIGN_EXTEND:
+    case ZERO_EXTEND:
+      if (GET_CODE (XEXP (x, 0)) == MEM)
+       *total = 0;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-       case PROCESSOR_PPC750:
-       case PROCESSOR_PPC8540:
-       case PROCESSOR_PPC7400:
-         *total = COSTS_N_INSNS (19);
-         return true;
+    case COMPARE:
+    case NEG:
+    case ABS:
+      if (!FLOAT_MODE_P (mode))
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
 
-       case PROCESSOR_PPC7450:
-         *total = COSTS_N_INSNS (23);
-         return true;
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+      *total = rs6000_cost->fp;
+      return false;
 
-       case PROCESSOR_POWER4:
-       case PROCESSOR_POWER5:
-         *total = (GET_MODE (XEXP (x, 1)) != DImode
-                   ? COSTS_N_INSNS (18)
-                   : COSTS_N_INSNS (34));
+    case UNSPEC:
+      switch (XINT (x, 1))
+       {
+       case UNSPEC_FRSP:
+         *total = rs6000_cost->fp;
          return true;
 
        default:
-         abort ();
+         break;
        }
+      break;
 
-    case FFS:
-      *total = COSTS_N_INSNS (4);
-      return true;
+    case CALL:
+    case IF_THEN_ELSE:
+      if (optimize_size)
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+      else if (FLOAT_MODE_P (mode)
+              && TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS)
+       {
+         *total = rs6000_cost->fp;
+         return false;
+       }
 
-    case MEM:
-      /* MEM should be slightly more expensive than (plus (reg) (const)).  */
-      *total = 5;
-      return true;
+      break;
 
     default:
-      return false;
+      break;
     }
+
+  return false;
 }
 
 /* A C expression returning the cost of moving data from a register of class
@@ -16467,7 +17510,8 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
           && targetm.calls.split_complex_arg)
     return rs6000_complex_function_value (mode);
   else if (TREE_CODE (valtype) == VECTOR_TYPE
-          && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI)
+          && TARGET_ALTIVEC && TARGET_ALTIVEC_ABI
+          && ALTIVEC_VECTOR_MODE(mode))
     regno = ALTIVEC_ARG_RETURN;
   else
     regno = GP_ARG_RETURN;
@@ -16588,4 +17632,11 @@ rs6000_dbx_register_number (unsigned int regno)
   abort ();
 }
 
+/* target hook eh_return_filter_mode */
+static enum machine_mode 
+rs6000_eh_return_filter_mode (void)
+{
+  return TARGET_32BIT ? SImode : word_mode;
+}
+
 #include "gt-rs6000.h"