OSDN Git Service

* config/rs6000/spe.md (SPE_ACC_REGNO): Delete definition.
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index f72fde3..2d4f5e8 100644 (file)
@@ -616,7 +616,6 @@ struct processor_costs power6_cost = {
 static bool rs6000_function_ok_for_sibcall (tree, tree);
 static const char *rs6000_invalid_within_doloop (rtx);
 static rtx rs6000_generate_compare (enum rtx_code);
-static void rs6000_maybe_dead (rtx);
 static void rs6000_emit_stack_tie (void);
 static void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
 static rtx spe_synthesize_frame_save (rtx);
@@ -631,7 +630,6 @@ static int toc_hash_eq (const void *, const void *);
 static int constant_pool_expr_1 (rtx, int *, int *);
 static bool constant_pool_expr_p (rtx);
 static bool legitimate_small_data_p (enum machine_mode, rtx);
-static bool legitimate_indexed_address_p (rtx, int);
 static bool legitimate_lo_sum_address_p (enum machine_mode, rtx, int);
 static struct machine_function * rs6000_init_machine_status (void);
 static bool rs6000_assemble_integer (rtx, unsigned int, int);
@@ -648,6 +646,7 @@ static void rs6000_eliminate_indexed_memrefs (rtx operands[2]);
 static const char *rs6000_mangle_fundamental_type (tree);
 extern const struct attribute_spec rs6000_attribute_table[];
 static void rs6000_set_default_type_attributes (tree);
+static bool rs6000_reg_live_or_pic_offset_p (int);
 static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
@@ -656,13 +655,11 @@ static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 static bool rs6000_return_in_memory (tree, tree);
 static void rs6000_file_start (void);
 #if TARGET_ELF
-static unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
+static int rs6000_elf_reloc_rw_mask (void);
 static void rs6000_elf_asm_out_constructor (rtx, int);
 static void rs6000_elf_asm_out_destructor (rtx, int);
 static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
 static void rs6000_elf_asm_init_sections (void);
-static section *rs6000_elf_select_section (tree, int, unsigned HOST_WIDE_INT);
-static void rs6000_elf_unique_section (tree, int);
 static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
                                               unsigned HOST_WIDE_INT);
 static void rs6000_elf_encode_section_info (tree, rtx, int)
@@ -673,6 +670,7 @@ static bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx);
 static void rs6000_xcoff_asm_output_anchor (rtx);
 static void rs6000_xcoff_asm_globalize_label (FILE *, const char *);
 static void rs6000_xcoff_asm_init_sections (void);
+static int rs6000_xcoff_reloc_rw_mask (void);
 static void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree);
 static section *rs6000_xcoff_select_section (tree, int,
                                             unsigned HOST_WIDE_INT);
@@ -696,10 +694,10 @@ static bool is_load_insn (rtx);
 static rtx get_store_dest (rtx pat);
 static bool is_store_insn (rtx);
 static bool set_to_load_agen (rtx,rtx);
-static bool adjacent_mem_locations (rtx,rtx); 
+static bool adjacent_mem_locations (rtx,rtx);
 static int rs6000_adjust_priority (rtx, int);
 static int rs6000_issue_rate (void);
-static bool rs6000_is_costly_dependence (rtx, rtx, rtx, int, int);
+static bool rs6000_is_costly_dependence (dep_t, int, int);
 static rtx get_next_active_insn (rtx, rtx);
 static bool insn_terminates_group_p (rtx , enum group_termination);
 static bool insn_must_be_first_in_group (rtx);
@@ -716,8 +714,10 @@ static int rs6000_use_sched_lookahead_guard (rtx);
 static tree rs6000_builtin_mask_for_load (void);
 static tree rs6000_builtin_mul_widen_even (tree);
 static tree rs6000_builtin_mul_widen_odd (tree);
+static tree rs6000_builtin_conversion (enum tree_code, tree);
 
 static void def_builtin (int, const char *, tree, int);
+static bool rs6000_vector_alignment_reachable (tree, bool);
 static void rs6000_init_builtins (void);
 static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx);
 static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx);
@@ -764,6 +764,7 @@ static rtx generate_set_vrsave (rtx, rs6000_stack_t *, int);
 int easy_vector_constant (rtx, enum machine_mode);
 static bool rs6000_is_opaque_type (tree);
 static rtx rs6000_dwarf_register_span (rtx);
+static void rs6000_init_dwarf_reg_sizes_extra (tree);
 static rtx rs6000_legitimize_tls_address (rtx, enum tls_model);
 static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static rtx rs6000_tls_get_addr (void);
@@ -797,7 +798,6 @@ static int rs6000_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
 static const char *invalid_arg_for_unprototyped_fn (tree, tree, tree);
 #if TARGET_MACHO
 static void macho_branch_islands (void);
-static void add_compiler_branch_island (tree, tree, int);
 static int no_previous_def (tree function_name);
 static tree get_prev_label (tree function_name);
 static void rs6000_darwin_file_start (void);
@@ -982,6 +982,11 @@ static const char alt_reg_names[][8] =
 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN rs6000_builtin_mul_widen_even
 #undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD
 #define TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_ODD rs6000_builtin_mul_widen_odd
+#undef TARGET_VECTORIZE_BUILTIN_CONVERSION
+#define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion
+
+#undef TARGET_VECTOR_ALIGNMENT_REACHABLE
+#define TARGET_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable
 
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
@@ -1026,6 +1031,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
 
+#undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
+#define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
+
 /* On rs6000, function arguments are promoted, as are function return
    values.  */
 #undef TARGET_PROMOTE_FUNCTION_ARGS
@@ -1125,11 +1133,12 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
     return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1);
 
   /* The float registers can only hold floating modes and DImode.
-     This also excludes decimal float modes.  */
+     This excludes the 32-bit decimal float mode for now.  */
   if (FP_REGNO_P (regno))
     return
       (SCALAR_FLOAT_MODE_P (mode)
-       && !DECIMAL_FLOAT_MODE_P (mode)
+       && (mode != TDmode || (regno % 2) == 0)
+       && mode != SDmode
        && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
       || (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
@@ -1167,6 +1176,61 @@ rs6000_init_hard_regno_mode_ok (void)
        rs6000_hard_regno_mode_ok_p[m][r] = true;
 }
 
+#if TARGET_MACHO
+/* The Darwin version of SUBTARGET_OVERRIDE_OPTIONS.  */
+
+static void
+darwin_rs6000_override_options (void)
+{
+  /* The Darwin ABI always includes AltiVec, can't be (validly) turned
+     off.  */
+  rs6000_altivec_abi = 1;
+  TARGET_ALTIVEC_VRSAVE = 1;
+  if (DEFAULT_ABI == ABI_DARWIN)
+  {
+    if (MACHO_DYNAMIC_NO_PIC_P)
+      {
+        if (flag_pic)
+            warning (0, "-mdynamic-no-pic overrides -fpic or -fPIC");
+        flag_pic = 0;
+      }
+    else if (flag_pic == 1)
+      {
+        flag_pic = 2;
+      }
+  }
+  if (TARGET_64BIT && ! TARGET_POWERPC64)
+    {
+      target_flags |= MASK_POWERPC64;
+      warning (0, "-m64 requires PowerPC64 architecture, enabling");
+    }
+  if (flag_mkernel)
+    {
+      rs6000_default_long_calls = 1;
+      target_flags |= MASK_SOFT_FLOAT;
+    }
+
+  /* Make -m64 imply -maltivec.  Darwin's 64-bit ABI includes
+     Altivec.  */
+  if (!flag_mkernel && !flag_apple_kext
+      && TARGET_64BIT
+      && ! (target_flags_explicit & MASK_ALTIVEC))
+    target_flags |= MASK_ALTIVEC;
+
+  /* Unless the user (not the configurer) has explicitly overridden
+     it with -mcpu=G3 or -mno-altivec, then 10.5+ targets default to
+     G4 unless targetting the kernel.  */
+  if (!flag_mkernel
+      && !flag_apple_kext
+      && strverscmp (darwin_macosx_version_min, "10.5") >= 0
+      && ! (target_flags_explicit & MASK_ALTIVEC)
+      && ! rs6000_select[1].string)
+    {
+      target_flags |= MASK_ALTIVEC;
+    }
+}
+#endif
+
 /* If not otherwise specified by a target, make 'long double' equivalent to
    'double'.  */
 
@@ -1235,11 +1299,9 @@ rs6000_override_options (const char *default_cpu)
         {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
-        {"8540", PROCESSOR_PPC8540,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
+        {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         /* 8548 has a dummy entry for now.  */
-        {"8548", PROCESSOR_PPC8540,
-         POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_STRICT_ALIGN},
+        {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
          POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
@@ -1266,10 +1328,10 @@ rs6000_override_options (const char *default_cpu)
          | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND},
         {"power6", PROCESSOR_POWER6,
          POWERPC_7400_MASK | MASK_POWERPC64 | MASK_MFCRF | MASK_POPCNTB
-         | MASK_FPRND},
+         | MASK_FPRND | MASK_CMPB | MASK_DFP },
         {"power6x", PROCESSOR_POWER6,
          POWERPC_7400_MASK | MASK_POWERPC64 | MASK_MFCRF | MASK_POPCNTB
-         | MASK_FPRND | MASK_MFPGPR},
+         | MASK_FPRND | MASK_CMPB | MASK_MFPGPR | MASK_DFP },
         {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
         {"powerpc64", PROCESSOR_POWERPC64,
          POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
@@ -1296,7 +1358,7 @@ rs6000_override_options (const char *default_cpu)
     POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN
                     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
                     | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
-                    | MASK_DLMZB | MASK_MFPGPR)
+                    | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP)
   };
 
   rs6000_init_hard_regno_mode_ok ();
@@ -1637,7 +1699,7 @@ rs6000_override_options (const char *default_cpu)
        rs6000_cost = &ppc630_cost;
        break;
 
-      case PROCESSOR_CELL: 
+      case PROCESSOR_CELL:
        rs6000_cost = &ppccell_cost;
        break;
 
@@ -1678,6 +1740,30 @@ rs6000_builtin_mask_for_load (void)
     return 0;
 }
 
+/* Implement targetm.vectorize.builtin_conversion.  */
+static tree
+rs6000_builtin_conversion (enum tree_code code, tree type)
+{
+  if (!TARGET_ALTIVEC)
+    return NULL_TREE;
+
+  switch (code)
+    {
+    case FLOAT_EXPR:
+      switch (TYPE_MODE (type))
+       {
+       case V4SImode:
+         return TYPE_UNSIGNED (type) ?
+           rs6000_builtin_decls[ALTIVEC_BUILTIN_VCFUX] :
+           rs6000_builtin_decls[ALTIVEC_BUILTIN_VCFSX];
+       default:
+         return NULL_TREE;
+       }
+    default:
+      return NULL_TREE;
+    }
+}
+
 /* Implement targetm.vectorize.builtin_mul_widen_even.  */
 static tree
 rs6000_builtin_mul_widen_even (tree type)
@@ -1688,7 +1774,7 @@ rs6000_builtin_mul_widen_even (tree type)
   switch (TYPE_MODE (type))
     {
     case V8HImode:
-      return TYPE_UNSIGNED (type) ? 
+      return TYPE_UNSIGNED (type) ?
             rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULEUH] :
             rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULESH];
 
@@ -1724,6 +1810,37 @@ rs6000_builtin_mul_widen_odd (tree type)
     }
 }
 
+
+/* Return true iff, data reference of TYPE can reach vector alignment (16)
+   after applying N number of iterations.  This routine does not determine
+   how may iterations are required to reach desired alignment.  */
+
+static bool
+rs6000_vector_alignment_reachable (tree type ATTRIBUTE_UNUSED, bool is_packed)
+{
+  if (is_packed)
+    return false;
+
+  if (TARGET_32BIT)
+    {
+      if (rs6000_alignment_flags == MASK_ALIGN_NATURAL)
+        return true;
+
+      if (rs6000_alignment_flags ==  MASK_ALIGN_POWER)
+        return true;
+
+      return false;
+    }
+  else
+    {
+      if (TARGET_MACHO)
+        return false;
+
+      /* Assuming that all other types are naturally aligned. CHECKME!  */
+      return true;
+    }
+}
+
 /* Handle generic options of the form -mfoo=yes/no.
    NAME is the option name.
    VALUE is the option value.
@@ -2123,6 +2240,12 @@ rs6000_file_start (void)
        putc ('\n', file);
     }
 
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+  if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
+    fprintf (file, "\t.gnu_attribute 4, %d\n",
+            (TARGET_HARD_FLOAT && TARGET_FPRS) ? 1 : 2);
+#endif
+
   if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
     {
       switch_to_section (toc_section);
@@ -2229,7 +2352,10 @@ num_insns_constant (rtx op, enum machine_mode mode)
            REAL_VALUE_TYPE rv;
 
            REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-           REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
+           if (DECIMAL_FLOAT_MODE_P (mode))
+             REAL_VALUE_TO_TARGET_DECIMAL64 (rv, l);
+           else
+             REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
            high = l[WORDS_BIG_ENDIAN == 0];
            low  = l[WORDS_BIG_ENDIAN != 0];
          }
@@ -2969,6 +3095,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       return SPE_CONST_OFFSET_OK (offset);
 
     case DFmode:
+    case DDmode:
       if (TARGET_E500_DOUBLE)
        return SPE_CONST_OFFSET_OK (offset);
 
@@ -2981,7 +3108,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       if (TARGET_E500_DOUBLE)
        return SPE_CONST_OFFSET_OK (offset);
 
-      if (mode == DFmode || !TARGET_POWERPC64)
+      if (mode == DFmode || mode == DDmode || !TARGET_POWERPC64)
        extra = 4;
       else if (offset & 3)
        return false;
@@ -2993,7 +3120,8 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
                && SPE_CONST_OFFSET_OK (offset + 8));
 
     case TImode:
-      if (mode == TFmode || !TARGET_POWERPC64)
+    case TDmode:
+      if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
        extra = 12;
       else if (offset & 3)
        return false;
@@ -3009,7 +3137,7 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
   return (offset < 0x10000) && (offset + extra < 0x10000);
 }
 
-static bool
+bool
 legitimate_indexed_address_p (rtx x, int strict)
 {
   rtx op0, op1;
@@ -3148,8 +3276,9 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_MODE_NUNITS (mode) == 1
           && ((TARGET_HARD_FLOAT && TARGET_FPRS)
               || TARGET_POWERPC64
-              || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
-                  && mode != TFmode))
+              || (((mode != DImode && mode != DFmode && mode != DDmode)
+                   || TARGET_E500_DOUBLE)
+                  && mode != TFmode && mode != TDmode))
           && (TARGET_POWERPC64 || mode != DImode)
           && mode != TImode)
     {
@@ -3170,6 +3299,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
     }
   else if (SPE_VECTOR_MODE (mode)
           || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
+                                     || mode == DDmode || mode == TDmode
                                      || mode == DImode)))
     {
       if (mode == DImode)
@@ -3353,25 +3483,22 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
                rs6000_emit_move (got, gsym, Pmode);
              else
                {
-                 rtx tempLR, tmp3, mem;
+                 rtx tmp3, mem;
                  rtx first, last;
 
-                 tempLR = gen_reg_rtx (Pmode);
                  tmp1 = gen_reg_rtx (Pmode);
                  tmp2 = gen_reg_rtx (Pmode);
                  tmp3 = gen_reg_rtx (Pmode);
                  mem = gen_const_mem (Pmode, tmp1);
 
-                 first = emit_insn (gen_load_toc_v4_PIC_1b (tempLR, gsym));
-                 emit_move_insn (tmp1, tempLR);
+                 first = emit_insn (gen_load_toc_v4_PIC_1b (gsym));
+                 emit_move_insn (tmp1,
+                                 gen_rtx_REG (Pmode, LR_REGNO));
                  emit_move_insn (tmp2, mem);
                  emit_insn (gen_addsi3 (tmp3, tmp1, tmp2));
                  last = emit_move_insn (got, tmp3);
                  set_unique_reg_note (last, REG_EQUAL, gsym);
-                 REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
-                                                        REG_NOTES (first));
-                 REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
-                                                       REG_NOTES (last));
+                 maybe_encapsulate_block (first, last, gsym);
                }
            }
        }
@@ -3449,7 +3576,7 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model)
        }
       else
        {
-         /* IE, or 64 bit offset LE.  */
+         /* IE, or 64-bit offset LE.  */
          tmp2 = gen_reg_rtx (Pmode);
          if (TARGET_64BIT)
            insn = gen_tls_got_tprel_64 (tmp2, got, addr);
@@ -3615,10 +3742,11 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && DEFAULT_ABI == ABI_V4
       && !flag_pic
 #endif
-      /* Don't do this for TFmode, since the result isn't offsettable.
+      /* Don't do this for TFmode or TDmode, since the result isn't offsettable.
         The same goes for DImode without 64-bit gprs and DFmode
         without fprs.  */
       && mode != TFmode
+      && mode != TDmode
       && (mode != DImode || TARGET_POWERPC64)
       && (mode != DFmode || TARGET_POWERPC64
          || (TARGET_FPRS && TARGET_HARD_FLOAT)))
@@ -3688,8 +3816,8 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
    word aligned.
 
    For modes spanning multiple registers (DFmode in 32-bit GPRs,
-   32-bit DImode, TImode, TFmode), indexed addressing cannot be used because
-   adjacent memory cells are accessed by adding word-sized offsets
+   32-bit DImode, TImode, TFmode, TDmode), indexed addressing cannot be used
+   because adjacent memory cells are accessed by adding word-sized offsets
    during assembly output.  */
 int
 rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
@@ -3710,6 +3838,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && !ALTIVEC_VECTOR_MODE (mode)
       && !SPE_VECTOR_MODE (mode)
       && mode != TFmode
+      && mode != TDmode
       /* Restrict addressing for DI because of our SUBREG hackery.  */
       && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
                                  || mode == DImode))
@@ -3732,12 +3861,31 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
     return 1;
   if (mode != TImode
       && mode != TFmode
+      && mode != TDmode
       && ((TARGET_HARD_FLOAT && TARGET_FPRS)
          || TARGET_POWERPC64
          || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
       && (TARGET_POWERPC64 || mode != DImode)
       && legitimate_indexed_address_p (x, reg_ok_strict))
     return 1;
+  if (GET_CODE (x) == PRE_MODIFY
+      && mode != TImode
+      && mode != TFmode
+      && mode != TDmode
+      && ((TARGET_HARD_FLOAT && TARGET_FPRS)
+         || TARGET_POWERPC64
+         || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
+      && (TARGET_POWERPC64 || mode != DImode)
+      && !ALTIVEC_VECTOR_MODE (mode)
+      && !SPE_VECTOR_MODE (mode)
+      /* Restrict addressing for DI because of our SUBREG hackery.  */
+      && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
+      && TARGET_UPDATE
+      && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict)
+      && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1), reg_ok_strict)
+         || legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict))
+      && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
+    return 1;
   if (legitimate_lo_sum_address_p (mode, x, reg_ok_strict))
     return 1;
   return 0;
@@ -3770,7 +3918,10 @@ rs6000_mode_dependent_address (rtx addr)
     case LO_SUM:
       return true;
 
-    /* Auto-increment cases are now treated generically in recog.c.  */
+    case PRE_INC:
+    case PRE_DEC:
+    case PRE_MODIFY:
+      return TARGET_UPDATE;
 
     default:
       break;
@@ -3898,9 +4049,15 @@ rs6000_conditional_register_usage (void)
   if (TARGET_SPE)
     {
       global_regs[SPEFSCR_REGNO] = 1;
-      fixed_regs[FIXED_SCRATCH]
-       = call_used_regs[FIXED_SCRATCH]
-       = call_really_used_regs[FIXED_SCRATCH] = 1;
+      /* We used to use r14 as FIXED_SCRATCH to address SPE 64-bit
+         registers in prologues and epilogues.  We no longer use r14
+         for FIXED_SCRATCH, but we're keeping r14 out of the allocation
+         pool for link-compatibility with older versions of GCC.  Once
+         "old" code has died out, we can return r14 to the allocation
+         pool.  */
+      fixed_regs[14]
+       = call_used_regs[14]
+       = call_really_used_regs[14] = 1;
     }
 
   if (! TARGET_ALTIVEC)
@@ -3938,7 +4095,7 @@ rs6000_emit_set_const (rtx dest, enum machine_mode mode,
       return dest;
 
     case SImode:
-      result = no_new_pseudos ? dest : gen_reg_rtx (SImode);
+      result = !can_create_pseudo_p () ? dest : gen_reg_rtx (SImode);
 
       emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (result),
                              GEN_INT (INTVAL (source)
@@ -4088,7 +4245,7 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
 }
 
 /* Helper for the following.  Get rid of [r+r] memory refs
-   in cases where it won't work (TImode, TFmode).  */
+   in cases where it won't work (TImode, TFmode, TDmode).  */
 
 static void
 rs6000_eliminate_indexed_memrefs (rtx operands[2])
@@ -4157,7 +4314,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       return;
     }
 
-  if (!no_new_pseudos && GET_CODE (operands[0]) == MEM
+  if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM
       && !gpc_reg_operand (operands[1], mode))
     operands[1] = force_reg (mode, operands[1]);
 
@@ -4180,7 +4337,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
        {
          rtx newreg;
-         newreg = (no_new_pseudos ? copy_rtx (operands[1])
+         newreg = (!can_create_pseudo_p () ? copy_rtx (operands[1])
                    : gen_reg_rtx (mode));
          emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
          operands[1] = newreg;
@@ -4252,10 +4409,12 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       break;
 
     case TFmode:
+    case TDmode:
       rs6000_eliminate_indexed_memrefs (operands);
       /* fall through */
 
     case DFmode:
+    case DDmode:
     case SFmode:
       if (CONSTANT_P (operands[1])
          && ! easy_fp_constant (operands[1], mode))
@@ -4305,7 +4464,9 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
          && GET_CODE (operands[1]) != HIGH
          && GET_CODE (operands[1]) != CONST_INT)
        {
-         rtx target = (no_new_pseudos ? operands[0] : gen_reg_rtx (mode));
+         rtx target = (!can_create_pseudo_p ()
+                       ? operands[0]
+                       : gen_reg_rtx (mode));
 
          /* If this is a function address on -mcall-aixdesc,
             convert it to the address of the descriptor.  */
@@ -4467,7 +4628,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
   (SCALAR_FLOAT_MODE_P (MODE)                  \
-   && !DECIMAL_FLOAT_MODE_P (MODE)             \
+   && (MODE) != SDmode                         \
    && (CUM)->fregno <= FP_ARG_MAX_REG          \
    && TARGET_HARD_FLOAT && TARGET_FPRS)
 
@@ -4709,7 +4870,7 @@ function_arg_boundary (enum machine_mode mode, tree type)
       && (GET_MODE_SIZE (mode) == 8
          || (TARGET_HARD_FLOAT
              && TARGET_FPRS
-             && mode == TFmode)))
+             && (mode == TFmode || mode == TDmode))))
     return 64;
   else if (SPE_VECTOR_MODE (mode)
           || (type && TREE_CODE (type) == VECTOR_TYPE
@@ -4947,14 +5108,21 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode
+             || mode == DDmode || mode == TDmode
              || (mode == TFmode && !TARGET_IEEEQUAD)))
        {
-         if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
+         /* _Decimal128 must use an even/odd register pair.  This assumes
+            that the register number is odd when fregno is odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
+           cum->fregno++;
+
+         if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
+             <= FP_ARG_V4_MAX_REG)
            cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
          else
            {
              cum->fregno = FP_ARG_V4_MAX_REG + 1;
-             if (mode == DFmode || mode == TFmode)
+             if (mode == DFmode || mode == TFmode || mode == DDmode || mode == TDmode)
                cum->words += cum->words & 1;
              cum->words += rs6000_arg_size (mode, type);
            }
@@ -5006,9 +5174,16 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
       cum->words = align_words + n_words;
 
       if (SCALAR_FLOAT_MODE_P (mode)
-         && !DECIMAL_FLOAT_MODE_P (mode)
+         && mode != SDmode
          && TARGET_HARD_FLOAT && TARGET_FPRS)
-       cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+       {
+         /* _Decimal128 must be passed in an even/odd float register pair.
+            This assumes that the register number is odd when fregno is
+            odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
+           cum->fregno++;
+         cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
+       }
 
       if (TARGET_DEBUG_ARG)
        {
@@ -5225,7 +5400,7 @@ rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *cum, tree type,
              = gen_rtx_EXPR_LIST (VOIDmode,
                                   gen_rtx_REG (mode, cum->fregno++),
                                   GEN_INT (bitpos / BITS_PER_UNIT));
-           if (mode == TFmode)
+           if (mode == TFmode || mode == TDmode)
              cum->fregno++;
          }
        else if (cum->named && USE_ALTIVEC_FOR_ARG_P (cum, mode, ftype, 1))
@@ -5486,8 +5661,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else if (TARGET_SPE_ABI && TARGET_SPE
           && (SPE_VECTOR_MODE (mode)
               || (TARGET_E500_DOUBLE && (mode == DFmode
+                                         || mode == DDmode
                                          || mode == DCmode
                                          || mode == TFmode
+                                         || mode == TDmode
                                          || mode == TCmode))))
     return rs6000_spe_function_arg (cum, mode, type);
 
@@ -5495,9 +5672,16 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
          && (mode == SFmode || mode == DFmode
-             || (mode == TFmode && !TARGET_IEEEQUAD)))
+             || (mode == TFmode && !TARGET_IEEEQUAD)
+             || mode == DDmode || mode == TDmode))
        {
-         if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
+         /* _Decimal128 must use an even/odd register pair.  This assumes
+            that the register number is odd when fregno is odd.  */
+         if (mode == TDmode && (cum->fregno % 2) == 1)
+           cum->fregno++;
+
+         if (cum->fregno + (mode == TFmode || mode == TDmode ? 1 : 0)
+             <= FP_ARG_V4_MAX_REG)
            return gen_rtx_REG (mode, cum->fregno);
          else
            return NULL_RTX;
@@ -5527,6 +5711,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     {
       int align_words = rs6000_parm_start (mode, type, cum->words);
 
+      /* _Decimal128 must be passed in an even/odd float register pair.
+        This assumes that the register number is odd when fregno is odd.  */
+      if (mode == TDmode && (cum->fregno % 2) == 1)
+       cum->fregno++;
+
       if (USE_FP_FOR_ARG_P (cum, mode, type))
        {
          rtx rvec[GP_ARG_NUM_REG + 1];
@@ -5540,10 +5729,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
            {
              /* Currently, we only ever need one reg here because complex
                 doubles are split.  */
-             gcc_assert (cum->fregno == FP_ARG_MAX_REG && fmode == TFmode);
+             gcc_assert (cum->fregno == FP_ARG_MAX_REG
+                         && (fmode == TFmode || fmode == TDmode));
 
-             /* Long double split over regs and memory.  */
-             fmode = DFmode;
+             /* Long double or _Decimal128 split over regs and memory.  */
+             fmode = DECIMAL_FLOAT_MODE_P (fmode) ? DDmode : DFmode;
            }
 
          /* Do we also need to pass this arg in the parameter save
@@ -6063,8 +6253,8 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the overflow area.  */
   t = make_tree (TREE_TYPE (ovf), virtual_incoming_args_rtx);
   if (words != 0)
-    t = build2 (PLUS_EXPR, TREE_TYPE (ovf), t,
-               build_int_cst (NULL_TREE, words * UNITS_PER_WORD));
+    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (ovf), t,
+               size_int (words * UNITS_PER_WORD));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovf), ovf, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6080,8 +6270,8 @@ rs6000_va_start (tree valist, rtx nextarg)
   /* Find the register save area.  */
   t = make_tree (TREE_TYPE (sav), virtual_stack_vars_rtx);
   if (cfun->machine->varargs_save_offset)
-    t = build2 (PLUS_EXPR, TREE_TYPE (sav), t,
-               build_int_cst (NULL_TREE, cfun->machine->varargs_save_offset));
+    t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (sav), t,
+               size_int (cfun->machine->varargs_save_offset));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (sav), sav, t);
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -6098,6 +6288,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   tree lab_false, lab_over, addr;
   int align;
   tree ptrtype = build_pointer_type (type);
+  int regalign = 0;
 
   if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
     {
@@ -6154,7 +6345,9 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   if (TARGET_HARD_FLOAT && TARGET_FPRS
       && (TYPE_MODE (type) == SFmode
          || TYPE_MODE (type) == DFmode
-         || TYPE_MODE (type) == TFmode))
+         || TYPE_MODE (type) == TFmode
+         || TYPE_MODE (type) == DDmode
+         || TYPE_MODE (type) == TDmode))
     {
       /* FP args go in FP registers, if present.  */
       reg = fpr;
@@ -6195,10 +6388,19 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       u = reg;
       if (n_reg == 2 && reg == gpr)
        {
+         regalign = 1;
          u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
                     size_int (n_reg - 1));
          u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, u);
        }
+      /* _Decimal128 is passed in even/odd fpr pairs; the stored
+        reg number is 0 for f1, so we want to make it odd.  */
+      else if (reg == fpr && TYPE_MODE (type) == TDmode)
+       {
+         regalign = 1;
+         t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg, size_int (1));
+         u = build2 (MODIFY_EXPR, void_type_node, reg, t);
+       }
 
       t = fold_convert (TREE_TYPE (reg), size_int (8 - n_reg + 1));
       t = build2 (GE_EXPR, boolean_type_node, u, t);
@@ -6208,12 +6410,12 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 
       t = sav;
       if (sav_ofs)
-       t = build2 (PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
+       t = build2 (POINTER_PLUS_EXPR, ptr_type_node, sav, size_int (sav_ofs));
 
       u = build2 (POSTINCREMENT_EXPR, TREE_TYPE (reg), reg, size_int (n_reg));
-      u = build1 (CONVERT_EXPR, integer_type_node, u);
-      u = build2 (MULT_EXPR, integer_type_node, u, size_int (sav_scale));
-      t = build2 (PLUS_EXPR, ptr_type_node, t, u);
+      u = fold_convert (sizetype, u);
+      u = build2 (MULT_EXPR, sizetype, u, size_int (sav_scale));
+      t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t, u);
 
       t = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
       gimplify_and_add (t, pre_p);
@@ -6224,10 +6426,10 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       t = build1 (LABEL_EXPR, void_type_node, lab_false);
       append_to_statement_list (t, pre_p);
 
-      if ((n_reg == 2 && reg != gpr) || n_reg > 2)
+      if ((n_reg == 2 && !regalign) || n_reg > 2)
        {
          /* Ensure that we don't find any more args in regs.
-            Alignment has taken care of the n_reg == 2 gpr case.  */
+            Alignment has taken care of for special cases.  */
          t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (reg), reg, size_int (8));
          gimplify_and_add (t, pre_p);
        }
@@ -6239,16 +6441,18 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   t = ovf;
   if (align != 1)
     {
-      t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+      t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (align - 1));
+      t = fold_convert (sizetype, t);
       t = build2 (BIT_AND_EXPR, TREE_TYPE (t), t,
-                 build_int_cst (NULL_TREE, -align));
+                 size_int (-align));
+      t = fold_convert (TREE_TYPE (ovf), t);
     }
   gimplify_expr (&t, pre_p, NULL, is_gimple_val, fb_rvalue);
 
   u = build2 (GIMPLE_MODIFY_STMT, void_type_node, addr, t);
   gimplify_and_add (u, pre_p);
 
-  t = build2 (PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
+  t = build2 (POINTER_PLUS_EXPR, TREE_TYPE (t), t, size_int (size));
   t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (ovf), ovf, t);
   gimplify_and_add (t, pre_p);
 
@@ -6268,12 +6472,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       tree tmp = create_tmp_var (type, "va_arg_tmp");
       tree dest_addr = build_fold_addr_expr (tmp);
 
-      tree copy = build_function_call_expr
-       (implicit_built_in_decls[BUILT_IN_MEMCPY],
-        tree_cons (NULL_TREE, dest_addr,
-                   tree_cons (NULL_TREE, addr,
-                              tree_cons (NULL_TREE, size_int (rsize * 4),
-                                         NULL_TREE))));
+      tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+                                  3, dest_addr, addr, size_int (rsize * 4));
 
       gimplify_and_add (copy, pre_p);
       addr = dest_addr;
@@ -6908,10 +7108,10 @@ static struct builtin_description bdesc_1arg[] =
 };
 
 static rtx
-rs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
+rs6000_expand_unop_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat;
-  tree arg0 = TREE_VALUE (arglist);
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
   rtx op0 = expand_normal (arg0);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -6957,10 +7157,10 @@ rs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
 }
 
 static rtx
-altivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
+altivec_expand_abs_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, scratch1, scratch2;
-  tree arg0 = TREE_VALUE (arglist);
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
   rtx op0 = expand_normal (arg0);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -6989,11 +7189,11 @@ altivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
 }
 
 static rtx
-rs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
+rs6000_expand_binop_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat;
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
@@ -7063,12 +7263,12 @@ rs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
 
 static rtx
 altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
-                                 tree arglist, rtx target)
+                                 tree exp, rtx target)
 {
   rtx pat, scratch;
-  tree cr6_form = TREE_VALUE (arglist);
-  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree cr6_form = CALL_EXPR_ARG (exp, 0);
+  tree arg0 = CALL_EXPR_ARG (exp, 1);
+  tree arg1 = CALL_EXPR_ARG (exp, 2);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   enum machine_mode tmode = SImode;
@@ -7139,11 +7339,11 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
 }
 
 static rtx
-altivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
+altivec_expand_lv_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, addr;
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = Pmode;
   enum machine_mode mode1 = Pmode;
@@ -7185,11 +7385,11 @@ altivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
 }
 
 static rtx
-spe_expand_stv_builtin (enum insn_code icode, tree arglist)
+spe_expand_stv_builtin (enum insn_code icode, tree exp)
 {
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   rtx op2 = expand_normal (arg2);
@@ -7218,11 +7418,11 @@ spe_expand_stv_builtin (enum insn_code icode, tree arglist)
 }
 
 static rtx
-altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
+altivec_expand_stv_builtin (enum insn_code icode, tree exp)
 {
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   rtx op2 = expand_normal (arg2);
@@ -7259,12 +7459,12 @@ altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
 }
 
 static rtx
-rs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
+rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat;
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   rtx op2 = expand_normal (arg2);
@@ -7322,8 +7522,7 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
 static rtx
 altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   tree arg0;
   enum machine_mode tmode, mode0;
@@ -7351,7 +7550,7 @@ altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
 
   *expandedp = true;
 
-  arg0 = TREE_VALUE (arglist);
+  arg0 = CALL_EXPR_ARG (exp, 0);
   op0 = expand_normal (arg0);
   tmode = insn_data[icode].operand[0].mode;
   mode0 = insn_data[icode].operand[1].mode;
@@ -7376,8 +7575,7 @@ static rtx
 altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
                           bool *expandedp)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   tree arg0, arg1;
   enum machine_mode mode0, mode1;
@@ -7403,8 +7601,8 @@ altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
       return NULL_RTX;
     }
 
-  arg0 = TREE_VALUE (arglist);
-  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
   op0 = expand_normal (arg0);
   op1 = expand_normal (arg1);
   mode0 = insn_data[icode].operand[0].mode;
@@ -7428,8 +7626,7 @@ static rtx
 altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
                            bool *expandedp)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   tree arg0, arg1, arg2;
   enum machine_mode mode0, mode1, mode2;
@@ -7444,9 +7641,9 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
   for (i = 0; i < ARRAY_SIZE (bdesc_dst); i++, d++)
     if (d->code == fcode)
       {
-       arg0 = TREE_VALUE (arglist);
-       arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-       arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+       arg0 = CALL_EXPR_ARG (exp, 0);
+       arg1 = CALL_EXPR_ARG (exp, 1);
+       arg2 = CALL_EXPR_ARG (exp, 2);
        op0 = expand_normal (arg0);
        op1 = expand_normal (arg1);
        op2 = expand_normal (arg2);
@@ -7486,7 +7683,7 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
 
 /* Expand vec_init builtin.  */
 static rtx
-altivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
+altivec_expand_vec_init_builtin (tree type, tree exp, rtx target)
 {
   enum machine_mode tmode = TYPE_MODE (type);
   enum machine_mode inner_mode = GET_MODE_INNER (tmode);
@@ -7494,15 +7691,14 @@ altivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
   rtvec v = rtvec_alloc (n_elt);
 
   gcc_assert (VECTOR_MODE_P (tmode));
+  gcc_assert (n_elt == call_expr_nargs (exp));
 
-  for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
+  for (i = 0; i < n_elt; ++i)
     {
-      rtx x = expand_normal (TREE_VALUE (arglist));
+      rtx x = expand_normal (CALL_EXPR_ARG (exp, i));
       RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
     }
 
-  gcc_assert (arglist == NULL);
-
   if (!target || !register_operand (target, tmode))
     target = gen_reg_rtx (tmode);
 
@@ -7530,16 +7726,16 @@ get_element_number (tree vec_type, tree arg)
 
 /* Expand vec_set builtin.  */
 static rtx
-altivec_expand_vec_set_builtin (tree arglist)
+altivec_expand_vec_set_builtin (tree exp)
 {
   enum machine_mode tmode, mode1;
   tree arg0, arg1, arg2;
   int elt;
   rtx op0, op1;
 
-  arg0 = TREE_VALUE (arglist);
-  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
+  arg2 = CALL_EXPR_ARG (exp, 2);
 
   tmode = TYPE_MODE (TREE_TYPE (arg0));
   mode1 = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
@@ -7562,15 +7758,15 @@ altivec_expand_vec_set_builtin (tree arglist)
 
 /* Expand vec_ext builtin.  */
 static rtx
-altivec_expand_vec_ext_builtin (tree arglist, rtx target)
+altivec_expand_vec_ext_builtin (tree exp, rtx target)
 {
   enum machine_mode tmode, mode0;
   tree arg0, arg1;
   int elt;
   rtx op0;
 
-  arg0 = TREE_VALUE (arglist);
-  arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  arg0 = CALL_EXPR_ARG (exp, 0);
+  arg1 = CALL_EXPR_ARG (exp, 1);
 
   op0 = expand_normal (arg0);
   elt = get_element_number (TREE_TYPE (arg0), arg1);
@@ -7598,8 +7794,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   struct builtin_description_predicates *dp;
   size_t i;
   enum insn_code icode;
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   tree arg0;
   rtx op0, pat;
   enum machine_mode tmode, mode0;
@@ -7630,15 +7825,15 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_STVX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, arglist);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvx, exp);
     case ALTIVEC_BUILTIN_STVEBX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, arglist);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvebx, exp);
     case ALTIVEC_BUILTIN_STVEHX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, arglist);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvehx, exp);
     case ALTIVEC_BUILTIN_STVEWX:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, arglist);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvewx, exp);
     case ALTIVEC_BUILTIN_STVXL:
-      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, arglist);
+      return altivec_expand_stv_builtin (CODE_FOR_altivec_stvxl, exp);
 
     case ALTIVEC_BUILTIN_MFVSCR:
       icode = CODE_FOR_altivec_mfvscr;
@@ -7657,7 +7852,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
 
     case ALTIVEC_BUILTIN_MTVSCR:
       icode = CODE_FOR_altivec_mtvscr;
-      arg0 = TREE_VALUE (arglist);
+      arg0 = CALL_EXPR_ARG (exp, 0);
       op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
 
@@ -7679,7 +7874,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
 
     case ALTIVEC_BUILTIN_DSS:
       icode = CODE_FOR_altivec_dss;
-      arg0 = TREE_VALUE (arglist);
+      arg0 = CALL_EXPR_ARG (exp, 0);
       STRIP_NOPS (arg0);
       op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
@@ -7705,19 +7900,19 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     case ALTIVEC_BUILTIN_VEC_INIT_V8HI:
     case ALTIVEC_BUILTIN_VEC_INIT_V16QI:
     case ALTIVEC_BUILTIN_VEC_INIT_V4SF:
-      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), arglist, target);
+      return altivec_expand_vec_init_builtin (TREE_TYPE (exp), exp, target);
 
     case ALTIVEC_BUILTIN_VEC_SET_V4SI:
     case ALTIVEC_BUILTIN_VEC_SET_V8HI:
     case ALTIVEC_BUILTIN_VEC_SET_V16QI:
     case ALTIVEC_BUILTIN_VEC_SET_V4SF:
-      return altivec_expand_vec_set_builtin (arglist);
+      return altivec_expand_vec_set_builtin (exp);
 
     case ALTIVEC_BUILTIN_VEC_EXT_V4SI:
     case ALTIVEC_BUILTIN_VEC_EXT_V8HI:
     case ALTIVEC_BUILTIN_VEC_EXT_V16QI:
     case ALTIVEC_BUILTIN_VEC_EXT_V4SF:
-      return altivec_expand_vec_ext_builtin (arglist, target);
+      return altivec_expand_vec_ext_builtin (exp, target);
 
     default:
       break;
@@ -7728,39 +7923,39 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
   d = (struct builtin_description *) bdesc_abs;
   for (i = 0; i < ARRAY_SIZE (bdesc_abs); i++, d++)
     if (d->code == fcode)
-      return altivec_expand_abs_builtin (d->icode, arglist, target);
+      return altivec_expand_abs_builtin (d->icode, exp, target);
 
   /* Expand the AltiVec predicates.  */
   dp = (struct builtin_description_predicates *) bdesc_altivec_preds;
   for (i = 0; i < ARRAY_SIZE (bdesc_altivec_preds); i++, dp++)
     if (dp->code == fcode)
       return altivec_expand_predicate_builtin (dp->icode, dp->opcode,
-                                              arglist, target);
+                                              exp, target);
 
   /* LV* are funky.  We initialized them differently.  */
   switch (fcode)
     {
     case ALTIVEC_BUILTIN_LVSL:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsl,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVSR:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvsr,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVEBX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvebx,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVEHX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvehx,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVEWX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvewx,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVXL:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvxl,
-                                       arglist, target);
+                                       exp, target);
     case ALTIVEC_BUILTIN_LVX:
       return altivec_expand_lv_builtin (CODE_FOR_altivec_lvx,
-                                       arglist, target);
+                                       exp, target);
     default:
       break;
       /* Fall through.  */
@@ -7806,8 +8001,7 @@ static struct builtin_description bdesc_2arg_spe[] =
 static rtx
 spe_expand_builtin (tree exp, rtx target, bool *expandedp)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   tree arg1, arg0;
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   enum insn_code icode;
@@ -7828,7 +8022,7 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
     case SPE_BUILTIN_EVSTWHO:
     case SPE_BUILTIN_EVSTWWE:
     case SPE_BUILTIN_EVSTWWO:
-      arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      arg1 = CALL_EXPR_ARG (exp, 2);
       if (TREE_CODE (arg1) != INTEGER_CST
          || TREE_INT_CST_LOW (arg1) & ~0x1f)
        {
@@ -7845,10 +8039,10 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
     {
     case SPE_BUILTIN_EVSPLATFI:
       return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplatfi,
-                                        arglist, target);
+                                        exp, target);
     case SPE_BUILTIN_EVSPLATI:
       return rs6000_expand_unop_builtin (CODE_FOR_spe_evsplati,
-                                        arglist, target);
+                                        exp, target);
     default:
       break;
     }
@@ -7856,48 +8050,48 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
   d = (struct builtin_description *) bdesc_2arg_spe;
   for (i = 0; i < ARRAY_SIZE (bdesc_2arg_spe); ++i, ++d)
     if (d->code == fcode)
-      return rs6000_expand_binop_builtin (d->icode, arglist, target);
+      return rs6000_expand_binop_builtin (d->icode, exp, target);
 
   d = (struct builtin_description *) bdesc_spe_predicates;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_predicates); ++i, ++d)
     if (d->code == fcode)
-      return spe_expand_predicate_builtin (d->icode, arglist, target);
+      return spe_expand_predicate_builtin (d->icode, exp, target);
 
   d = (struct builtin_description *) bdesc_spe_evsel;
   for (i = 0; i < ARRAY_SIZE (bdesc_spe_evsel); ++i, ++d)
     if (d->code == fcode)
-      return spe_expand_evsel_builtin (d->icode, arglist, target);
+      return spe_expand_evsel_builtin (d->icode, exp, target);
 
   switch (fcode)
     {
     case SPE_BUILTIN_EVSTDDX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstddx, exp);
     case SPE_BUILTIN_EVSTDHX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstdhx, exp);
     case SPE_BUILTIN_EVSTDWX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstdwx, exp);
     case SPE_BUILTIN_EVSTWHEX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhex, exp);
     case SPE_BUILTIN_EVSTWHOX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhox, exp);
     case SPE_BUILTIN_EVSTWWEX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwex, exp);
     case SPE_BUILTIN_EVSTWWOX:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwox, exp);
     case SPE_BUILTIN_EVSTDD:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstdd, exp);
     case SPE_BUILTIN_EVSTDH:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstdh, exp);
     case SPE_BUILTIN_EVSTDW:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstdw, exp);
     case SPE_BUILTIN_EVSTWHE:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwhe, exp);
     case SPE_BUILTIN_EVSTWHO:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwho, exp);
     case SPE_BUILTIN_EVSTWWE:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwe, exp);
     case SPE_BUILTIN_EVSTWWO:
-      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, arglist);
+      return spe_expand_stv_builtin (CODE_FOR_spe_evstwwo, exp);
     case SPE_BUILTIN_MFSPEFSCR:
       icode = CODE_FOR_spe_mfspefscr;
       tmode = insn_data[icode].operand[0].mode;
@@ -7914,7 +8108,7 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
       return target;
     case SPE_BUILTIN_MTSPEFSCR:
       icode = CODE_FOR_spe_mtspefscr;
-      arg0 = TREE_VALUE (arglist);
+      arg0 = CALL_EXPR_ARG (exp, 0);
       op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
 
@@ -7937,12 +8131,12 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
 }
 
 static rtx
-spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
+spe_expand_predicate_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, scratch, tmp;
-  tree form = TREE_VALUE (arglist);
-  tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+  tree form = CALL_EXPR_ARG (exp, 0);
+  tree arg0 = CALL_EXPR_ARG (exp, 1);
+  tree arg1 = CALL_EXPR_ARG (exp, 2);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -8045,13 +8239,13 @@ spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
 */
 
 static rtx
-spe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
+spe_expand_evsel_builtin (enum insn_code icode, tree exp, rtx target)
 {
   rtx pat, scratch;
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  tree arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arglist))));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
+  tree arg2 = CALL_EXPR_ARG (exp, 2);
+  tree arg3 = CALL_EXPR_ARG (exp, 3);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   rtx op2 = expand_normal (arg2);
@@ -8105,8 +8299,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
                       enum machine_mode mode ATTRIBUTE_UNUSED,
                       int ignore ATTRIBUTE_UNUSED)
 {
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
   struct builtin_description *d;
   size_t i;
@@ -8124,7 +8317,7 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
       gcc_assert (TARGET_ALTIVEC);
 
-      arg = TREE_VALUE (arglist);
+      arg = CALL_EXPR_ARG (exp, 0);
       gcc_assert (TREE_CODE (TREE_TYPE (arg)) == POINTER_TYPE);
       op = expand_expr (arg, NULL_RTX, Pmode, EXPAND_NORMAL);
       addr = memory_address (mode, op);
@@ -8153,6 +8346,16 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
       return target;
     }
 
+  /* FIXME: There's got to be a nicer way to handle this case than
+     constructing a new CALL_EXPR.  */
+  if (fcode == ALTIVEC_BUILTIN_VCFUX
+      || fcode == ALTIVEC_BUILTIN_VCFSX)
+    {
+      if (call_expr_nargs (exp) == 1)
+       exp = build_call_nary (TREE_TYPE (exp), CALL_EXPR_FN (exp),
+                              2, CALL_EXPR_ARG (exp, 0), integer_zero_node);
+    }
+
   if (TARGET_ALTIVEC)
     {
       ret = altivec_expand_builtin (exp, target, &success);
@@ -8174,19 +8377,19 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
   d = (struct builtin_description *) bdesc_1arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
     if (d->code == fcode)
-      return rs6000_expand_unop_builtin (d->icode, arglist, target);
+      return rs6000_expand_unop_builtin (d->icode, exp, target);
 
   /* Handle simple binary operations.  */
   d = (struct builtin_description *) bdesc_2arg;
   for (i = 0; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
     if (d->code == fcode)
-      return rs6000_expand_binop_builtin (d->icode, arglist, target);
+      return rs6000_expand_binop_builtin (d->icode, exp, target);
 
   /* Handle simple ternary operations.  */
   d = (struct builtin_description *) bdesc_3arg;
   for (i = 0; i < ARRAY_SIZE  (bdesc_3arg); i++, d++)
     if (d->code == fcode)
-      return rs6000_expand_ternop_builtin (d->icode, arglist, target);
+      return rs6000_expand_ternop_builtin (d->icode, exp, target);
 
   gcc_unreachable ();
 }
@@ -9191,22 +9394,22 @@ rs6000_common_init_builtins (void)
               && mode3 == V4SImode)
        type = v4sf_ftype_v4sf_v4sf_v4si;
 
-      /* vchar, vchar, vchar, 4 bit literal.  */
+      /* vchar, vchar, vchar, 4-bit literal.  */
       else if (mode0 == V16QImode && mode1 == mode0 && mode2 == mode0
               && mode3 == QImode)
        type = v16qi_ftype_v16qi_v16qi_int;
 
-      /* vshort, vshort, vshort, 4 bit literal.  */
+      /* vshort, vshort, vshort, 4-bit literal.  */
       else if (mode0 == V8HImode && mode1 == mode0 && mode2 == mode0
               && mode3 == QImode)
        type = v8hi_ftype_v8hi_v8hi_int;
 
-      /* vint, vint, vint, 4 bit literal.  */
+      /* vint, vint, vint, 4-bit literal.  */
       else if (mode0 == V4SImode && mode1 == mode0 && mode2 == mode0
               && mode3 == QImode)
        type = v4si_ftype_v4si_v4si_int;
 
-      /* vfloat, vfloat, vfloat, 4 bit literal.  */
+      /* vfloat, vfloat, vfloat, 4-bit literal.  */
       else if (mode0 == V4SFmode && mode1 == mode0 && mode2 == mode0
               && mode3 == QImode)
        type = v4sf_ftype_v4sf_v4sf_int;
@@ -9310,23 +9513,23 @@ rs6000_common_init_builtins (void)
       else if (mode0 == V4SImode && mode1 == V8HImode && mode2 == V4SImode)
        type = v4si_ftype_v8hi_v4si;
 
-      /* vint, vint, 5 bit literal.  */
+      /* vint, vint, 5-bit literal.  */
       else if (mode0 == V4SImode && mode1 == V4SImode && mode2 == QImode)
        type = v4si_ftype_v4si_int;
 
-      /* vshort, vshort, 5 bit literal.  */
+      /* vshort, vshort, 5-bit literal.  */
       else if (mode0 == V8HImode && mode1 == V8HImode && mode2 == QImode)
        type = v8hi_ftype_v8hi_int;
 
-      /* vchar, vchar, 5 bit literal.  */
+      /* vchar, vchar, 5-bit literal.  */
       else if (mode0 == V16QImode && mode1 == V16QImode && mode2 == QImode)
        type = v16qi_ftype_v16qi_int;
 
-      /* vfloat, vint, 5 bit literal.  */
+      /* vfloat, vint, 5-bit literal.  */
       else if (mode0 == V4SFmode && mode1 == V4SImode && mode2 == QImode)
        type = v4sf_ftype_v4si_int;
 
-      /* vint, vfloat, 5 bit literal.  */
+      /* vint, vfloat, 5-bit literal.  */
       else if (mode0 == V4SImode && mode1 == V4SFmode && mode2 == QImode)
        type = v4si_ftype_v4sf_int;
 
@@ -9450,7 +9653,6 @@ rs6000_init_libfuncs (void)
            set_optab_libfunc (ge_optab, TFmode, "__gcc_qge");
            set_optab_libfunc (lt_optab, TFmode, "__gcc_qlt");
            set_optab_libfunc (le_optab, TFmode, "__gcc_qle");
-           set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
 
            set_conv_libfunc (sext_optab, TFmode, SFmode, "__gcc_stoq");
            set_conv_libfunc (sext_optab, TFmode, DFmode, "__gcc_dtoq");
@@ -9461,6 +9663,9 @@ rs6000_init_libfuncs (void)
            set_conv_libfunc (sfloat_optab, TFmode, SImode, "__gcc_itoq");
            set_conv_libfunc (ufloat_optab, TFmode, SImode, "__gcc_utoq");
          }
+
+       if (!(TARGET_HARD_FLOAT && TARGET_FPRS))
+         set_optab_libfunc (unord_optab, TFmode, "__gcc_qunord");
       }
     else
       {
@@ -10321,8 +10526,9 @@ rs6000_got_register (rtx value ATTRIBUTE_UNUSED)
   /* The second flow pass currently (June 1999) can't update
      regs_ever_live without disturbing other parts of the compiler, so
      update it here to make the prolog/epilogue code happy.  */
-  if (no_new_pseudos && ! regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM])
-    regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM] = 1;
+  if (!can_create_pseudo_p ()
+      && !df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM))
+    df_set_regs_ever_live (RS6000_PIC_OFFSET_TABLE_REGNUM, true);
 
   current_function_uses_pic_offset_table = 1;
 
@@ -10689,6 +10895,9 @@ print_operand (FILE *file, rtx x, int code)
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0),
                                           UNITS_PER_WORD));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0),
+                                          UNITS_PER_WORD));
          else
            output_address (XEXP (adjust_address_nv (x, SImode,
                                                     UNITS_PER_WORD),
@@ -10858,10 +11067,10 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'T':
       /* Print the symbolic name of a branch target register.  */
-      if (GET_CODE (x) != REG || (REGNO (x) != LINK_REGISTER_REGNUM
-                                 && REGNO (x) != COUNT_REGISTER_REGNUM))
+      if (GET_CODE (x) != REG || (REGNO (x) != LR_REGNO
+                                 && REGNO (x) != CTR_REGNO))
        output_operand_lossage ("invalid %%T value");
-      else if (REGNO (x) == LINK_REGISTER_REGNUM)
+      else if (REGNO (x) == LR_REGNO)
        fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
       else
        fputs ("ctr", file);
@@ -10889,7 +11098,8 @@ print_operand (FILE *file, rtx x, int code)
       /* Print `u' if this has an auto-increment or auto-decrement.  */
       if (GET_CODE (x) == MEM
          && (GET_CODE (XEXP (x, 0)) == PRE_INC
-             || GET_CODE (XEXP (x, 0)) == PRE_DEC))
+             || GET_CODE (XEXP (x, 0)) == PRE_DEC
+             || GET_CODE (XEXP (x, 0)) == PRE_MODIFY))
        putc ('u', file);
       return;
 
@@ -10976,7 +11186,9 @@ print_operand (FILE *file, rtx x, int code)
 
     case 'X':
       if (GET_CODE (x) == MEM
-         && legitimate_indexed_address_p (XEXP (x, 0), 0))
+         && (legitimate_indexed_address_p (XEXP (x, 0), 0)
+             || (GET_CODE (XEXP (x, 0)) == PRE_MODIFY
+                 && legitimate_indexed_address_p (XEXP (XEXP (x, 0), 1), 0))))
        putc ('x', file);
       return;
 
@@ -10989,6 +11201,8 @@ print_operand (FILE *file, rtx x, int code)
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 8));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 8), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -11036,6 +11250,8 @@ print_operand (FILE *file, rtx x, int code)
          if (GET_CODE (XEXP (x, 0)) == PRE_INC
              || GET_CODE (XEXP (x, 0)) == PRE_DEC)
            output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (plus_constant (XEXP (XEXP (x, 0), 0), 12));
          else
            output_address (XEXP (adjust_address_nv (x, SImode, 12), 0));
          if (small_data_operand (x, GET_MODE (x)))
@@ -11116,6 +11332,8 @@ print_operand (FILE *file, rtx x, int code)
          else if (GET_CODE (XEXP (x, 0)) == PRE_DEC)
            fprintf (file, "%d(%s)", - GET_MODE_SIZE (GET_MODE (x)),
                     reg_names[REGNO (XEXP (XEXP (x, 0), 0))]);
+         else if (GET_CODE (XEXP (x, 0)) == PRE_MODIFY)
+           output_address (XEXP (XEXP (x, 0), 1));
          else
            output_address (XEXP (x, 0));
        }
@@ -12625,7 +12843,7 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
   emit_insn (fn (res, mem, val));
 }
 
-/* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
+/* Expand an atomic fetch-and-operate pattern.  CODE is the binary operation
    to perform.  MEM is the memory on which to operate.  VAL is the second
    operand of the binary operator.  BEFORE and AFTER are optional locations to
    return the value of MEM either before of after the operation.  SCRATCH is
@@ -12839,7 +13057,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
   mode = GET_MODE (dst);
   nregs = hard_regno_nregs[reg][mode];
   if (FP_REGNO_P (reg))
-    reg_mode = DFmode;
+    reg_mode = DECIMAL_FLOAT_MODE_P (mode) ? DDmode : DFmode;
   else if (ALTIVEC_REGNO_P (reg))
     reg_mode = V16QImode;
   else if (TARGET_E500_DOUBLE && mode == TFmode)
@@ -12976,7 +13194,7 @@ first_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 13; first_reg <= 31; first_reg++)
-    if (regs_ever_live[first_reg]
+    if (df_regs_ever_live_p (first_reg)
        && (! call_used_regs[first_reg]
            || (first_reg == RS6000_PIC_OFFSET_TABLE_REGNUM
                && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
@@ -13003,7 +13221,7 @@ first_fp_reg_to_save (void)
 
   /* Find lowest numbered live register.  */
   for (first_reg = 14 + 32; first_reg <= 63; first_reg++)
-    if (regs_ever_live[first_reg])
+    if (df_regs_ever_live_p (first_reg))
       break;
 
   return first_reg;
@@ -13020,9 +13238,16 @@ first_altivec_reg_to_save (void)
   if (! TARGET_ALTIVEC_ABI)
     return LAST_ALTIVEC_REGNO + 1;
 
+  /* On Darwin, the unwind routines are compiled without
+     TARGET_ALTIVEC, and use save_world to save/restore the
+     altivec registers when necessary.  */
+  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
+      && ! TARGET_ALTIVEC)
+    return FIRST_ALTIVEC_REGNO + 20;
+
   /* Find lowest numbered live register.  */
   for (i = FIRST_ALTIVEC_REGNO + 20; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       break;
 
   return i;
@@ -13037,9 +13262,16 @@ compute_vrsave_mask (void)
 {
   unsigned int i, mask = 0;
 
+  /* On Darwin, the unwind routines are compiled without
+     TARGET_ALTIVEC, and use save_world to save/restore the
+     call-saved altivec registers when necessary.  */
+  if (DEFAULT_ABI == ABI_DARWIN && current_function_calls_eh_return
+      && ! TARGET_ALTIVEC)
+    mask |= 0xFFF;
+
   /* First, find out if we use _any_ altivec registers.  */
   for (i = FIRST_ALTIVEC_REGNO; i <= LAST_ALTIVEC_REGNO; ++i)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       mask |= ALTIVEC_REG_BIT (i);
 
   if (mask == 0)
@@ -13300,13 +13532,13 @@ rs6000_stack_info (void)
       || rs6000_ra_ever_killed ())
     {
       info_ptr->lr_save_p = 1;
-      regs_ever_live[LINK_REGISTER_REGNUM] = 1;
+      df_set_regs_ever_live (LR_REGNO, true);
     }
 
   /* Determine if we need to save the condition code registers.  */
-  if (regs_ever_live[CR2_REGNO]
-      || regs_ever_live[CR3_REGNO]
-      || regs_ever_live[CR4_REGNO])
+  if (df_regs_ever_live_p (CR2_REGNO)
+      || df_regs_ever_live_p (CR3_REGNO)
+      || df_regs_ever_live_p (CR4_REGNO))
     {
       info_ptr->cr_save_p = 1;
       if (DEFAULT_ABI == ABI_V4)
@@ -13378,10 +13610,11 @@ rs6000_stack_info (void)
          info_ptr->vrsave_save_offset
            = info_ptr->gp_save_offset - info_ptr->vrsave_size;
 
-         /* Align stack so vector save area is on a quadword boundary.  */
+         /* Align stack so vector save area is on a quadword boundary.
+            The padding goes above the vectors.  */
          if (info_ptr->altivec_size != 0)
            info_ptr->altivec_padding_size
-             = 16 - (-info_ptr->vrsave_save_offset % 16);
+             = info_ptr->vrsave_save_offset & 0xF;
          else
            info_ptr->altivec_padding_size = 0;
 
@@ -13389,6 +13622,8 @@ rs6000_stack_info (void)
            = info_ptr->vrsave_save_offset
            - info_ptr->altivec_padding_size
            - info_ptr->altivec_size;
+         gcc_assert (info_ptr->altivec_size == 0
+                     || info_ptr->altivec_save_offset % 16 == 0);
 
          /* Adjust for AltiVec case.  */
          info_ptr->ehrd_offset = info_ptr->altivec_save_offset - ehrd_size;
@@ -13721,7 +13956,7 @@ rs6000_return_addr (int count, rtx frame)
     }
 
   cfun->machine->ra_need_lr = 1;
-  return get_hard_reg_initial_val (Pmode, LINK_REGISTER_REGNUM);
+  return get_hard_reg_initial_val (Pmode, LR_REGNO);
 }
 
 /* Say whether a function is a candidate for sibcall handling or not.
@@ -13747,7 +13982,8 @@ rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
            }
        }
       if (DEFAULT_ABI == ABI_DARWIN
-         || (*targetm.binds_local_p) (decl))
+         || ((*targetm.binds_local_p) (decl)
+             && (DEFAULT_ABI != ABI_AIX || !DECL_EXTERNAL (decl))))
        {
          tree attr_list = TYPE_ATTRIBUTES (TREE_TYPE (decl));
 
@@ -13806,7 +14042,7 @@ rs6000_ra_ever_killed (void)
   push_topmost_sequence ();
   top = get_insns ();
   pop_topmost_sequence ();
-  reg = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+  reg = gen_rtx_REG (Pmode, LR_REGNO);
 
   for (insn = NEXT_INSN (top); insn != NULL_RTX; insn = NEXT_INSN (insn))
     {
@@ -13817,7 +14053,7 @@ rs6000_ra_ever_killed (void)
              if (!SIBLING_CALL_P (insn))
                return 1;
            }
-         else if (find_regno_note (insn, REG_INC, LINK_REGISTER_REGNUM))
+         else if (find_regno_note (insn, REG_INC, LR_REGNO))
            return 1;
          else if (set_of (reg, insn) != NULL_RTX
                   && !prologue_epilogue_contains (insn))
@@ -13827,15 +14063,6 @@ rs6000_ra_ever_killed (void)
   return 0;
 }
 \f
-/* Add a REG_MAYBE_DEAD note to the insn.  */
-static void
-rs6000_maybe_dead (rtx insn)
-{
-  REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
-                                       const0_rtx,
-                                       REG_NOTES (insn));
-}
-
 /* Emit instructions needed to load the TOC register.
    This is only needed when TARGET_TOC, TARGET_MINIMAL_TOC, and there is
    a constant pool; or for SVR4 -fpic.  */
@@ -13843,13 +14070,13 @@ rs6000_maybe_dead (rtx insn)
 void
 rs6000_emit_load_toc_table (int fromprolog)
 {
-  rtx dest, insn;
+  rtx dest;
   dest = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
 
   if (TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic)
     {
       char buf[30];
-      rtx lab, tmp1, tmp2, got, tempLR;
+      rtx lab, tmp1, tmp2, got;
 
       ASM_GENERATE_INTERNAL_LABEL (buf, "LCF", rs6000_pic_labelno);
       lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
@@ -13863,41 +14090,20 @@ rs6000_emit_load_toc_table (int fromprolog)
          tmp1 = gen_reg_rtx (Pmode);
          tmp2 = gen_reg_rtx (Pmode);
        }
-      tempLR = (fromprolog
-               ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-               : gen_reg_rtx (Pmode));
-      insn = emit_insn (gen_load_toc_v4_PIC_1 (tempLR, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_move_insn (tmp1, tempLR);
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_load_toc_v4_PIC_1 (lab));
+      emit_move_insn (tmp1,
+                            gen_rtx_REG (Pmode, LR_REGNO));
+      emit_insn (gen_load_toc_v4_PIC_3b (tmp2, tmp1, got, lab));
+      emit_insn (gen_load_toc_v4_PIC_3c (dest, tmp2, got, lab));
     }
   else if (TARGET_ELF && DEFAULT_ABI == ABI_V4 && flag_pic == 1)
     {
-      rtx tempLR = (fromprolog
-                   ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                   : gen_reg_rtx (Pmode));
-
-      insn = emit_insn (gen_load_toc_v4_pic_si (tempLR));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_move_insn (dest, tempLR);
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_load_toc_v4_pic_si ());
+      emit_move_insn (dest, gen_rtx_REG (Pmode, LR_REGNO));
     }
   else if (TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2)
     {
       char buf[30];
-      rtx tempLR = (fromprolog
-                   ? gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)
-                   : gen_reg_rtx (Pmode));
       rtx temp0 = (fromprolog
                   ? gen_rtx_REG (Pmode, 0)
                   : gen_reg_rtx (Pmode));
@@ -13912,25 +14118,22 @@ rs6000_emit_load_toc_table (int fromprolog)
          ASM_GENERATE_INTERNAL_LABEL (buf, "LCL", rs6000_pic_labelno);
          symL = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
 
-         rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_1 (tempLR,
-                                                              symF)));
-         rs6000_maybe_dead (emit_move_insn (dest, tempLR));
-         rs6000_maybe_dead (emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest,
-                                                              symL,
-                                                              symF)));
+         emit_insn (gen_load_toc_v4_PIC_1 (symF));
+         emit_move_insn (dest,
+                         gen_rtx_REG (Pmode, LR_REGNO));
+         emit_insn (gen_load_toc_v4_PIC_2 (temp0, dest, symL, symF));
        }
       else
        {
          rtx tocsym;
 
          tocsym = gen_rtx_SYMBOL_REF (Pmode, toc_label_name);
-         emit_insn (gen_load_toc_v4_PIC_1b (tempLR, tocsym));
-         emit_move_insn (dest, tempLR);
+         emit_insn (gen_load_toc_v4_PIC_1b (tocsym));
+         emit_move_insn (dest,
+                         gen_rtx_REG (Pmode, LR_REGNO));
          emit_move_insn (temp0, gen_rtx_MEM (Pmode, dest));
        }
-      insn = emit_insn (gen_addsi3 (dest, temp0, dest));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_addsi3 (dest, temp0, dest));
     }
   else if (TARGET_ELF && !TARGET_AIX && flag_pic == 0 && TARGET_MINIMAL_TOC)
     {
@@ -13940,23 +14143,17 @@ rs6000_emit_load_toc_table (int fromprolog)
       ASM_GENERATE_INTERNAL_LABEL (buf, "LCTOC", 1);
       realsym = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
 
-      insn = emit_insn (gen_elf_high (dest, realsym));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
-      insn = emit_insn (gen_elf_low (dest, dest, realsym));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+      emit_insn (gen_elf_high (dest, realsym));
+      emit_insn (gen_elf_low (dest, dest, realsym));
     }
   else
     {
       gcc_assert (DEFAULT_ABI == ABI_AIX);
 
       if (TARGET_32BIT)
-       insn = emit_insn (gen_load_toc_aix_si (dest));
+       emit_insn (gen_load_toc_aix_si (dest));
       else
-       insn = emit_insn (gen_load_toc_aix_di (dest));
-      if (fromprolog)
-       rs6000_maybe_dead (insn);
+       emit_insn (gen_load_toc_aix_di (dest));
     }
 }
 
@@ -13994,7 +14191,7 @@ rs6000_emit_eh_reg_restore (rtx source, rtx scratch)
       emit_move_insn (tmp, operands[0]);
     }
   else
-    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM), operands[0]);
+    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), operands[0]);
 }
 
 static GTY(()) int set = -1;
@@ -14042,8 +14239,8 @@ uses_TOC (void)
 rtx
 create_TOC_reference (rtx symbol)
 {
-  if (no_new_pseudos)
-    regs_ever_live[TOC_REGISTER] = 1;
+  if (!can_create_pseudo_p ())
+    df_set_regs_ever_live (TOC_REGISTER, true);
   return gen_rtx_PLUS (Pmode,
           gen_rtx_REG (Pmode, TOC_REGISTER),
             gen_rtx_CONST (Pmode,
@@ -14481,6 +14678,20 @@ no_global_regs_above (int first_greg)
 #define TARGET_FIX_AND_CONTINUE 0
 #endif
 
+/* Determine whether the gp REG is really used.  */
+
+static bool
+rs6000_reg_live_or_pic_offset_p (int reg)
+{
+  return ((df_regs_ever_live_p (reg)
+           && (!call_used_regs[reg]
+               || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+                   && TARGET_TOC && TARGET_MINIMAL_TOC)))
+          || (reg == RS6000_PIC_OFFSET_TABLE_REGNUM
+              && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
+                  || (DEFAULT_ABI == ABI_DARWIN && flag_pic))));
+}
+
 /* Emit function prologue as insns.  */
 
 void
@@ -14529,7 +14740,8 @@ rs6000_emit_prologue (void)
                        || cfun->machine->ra_need_lr);
 
   /* For V.4, update stack before we do any saving and set back pointer.  */
-  if (info->push_p
+  if (! WORLD_SAVE_P (info)
+      && info->push_p
       && (DEFAULT_ABI == ABI_V4
          || current_function_calls_eh_return))
     {
@@ -14554,12 +14766,14 @@ rs6000_emit_prologue (void)
       int i, j, sz;
       rtx treg;
       rtvec p;
+      rtx reg0;
 
       /* save_world expects lr in r0. */
+      reg0 = gen_rtx_REG (Pmode, 0);
       if (info->lr_save_p)
        {
-         insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
-                                gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+         insn = emit_move_insn (reg0,
+                                gen_rtx_REG (Pmode, LR_REGNO));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
 
@@ -14575,7 +14789,7 @@ rs6000_emit_prologue (void)
                  && (!current_function_calls_eh_return
                       || info->ehrd_offset == -432)
                  && info->vrsave_save_offset == -224
-                 && info->altivec_save_offset == (-224 -16 -192));
+                 && info->altivec_save_offset == -416);
 
       treg = gen_rtx_REG (SImode, 11);
       emit_move_insn (treg, GEN_INT (-info->total_size));
@@ -14584,15 +14798,15 @@ rs6000_emit_prologue (void)
         in R11.  It also clobbers R12, so beware!  */
 
       /* Preserve CR2 for save_world prologues */
-      sz = 6;
+      sz = 5;
       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));
+                                           gen_rtx_REG (SImode,
+                                                        LR_REGNO));
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
                                        gen_rtx_SYMBOL_REF (Pmode,
                                                            "*save_world"));
@@ -14639,108 +14853,47 @@ rs6000_emit_prologue (void)
 
        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)
+      /* Explain about use of R0.  */
+      if (info->lr_save_p)
        {
-         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 (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
-    {
-      int i;
-
-      /* There should be a non inline version of this, for when we
-        are saving lots of vector registers.  */
-      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
-       if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
-         {
-           rtx areg, savereg, mem;
-           int offset;
-
-           offset = info->altivec_save_offset + sp_offset
-             + 16 * (i - info->first_altivec_reg_save);
-
-           savereg = gen_rtx_REG (V4SImode, i);
-
-           areg = gen_rtx_REG (Pmode, 0);
-           emit_move_insn (areg, GEN_INT (offset));
-
-           /* AltiVec addressing mode is [reg+reg].  */
-           mem = gen_frame_mem (V4SImode,
-                                gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
-
-           insn = emit_move_insn (mem, savereg);
-
-           rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                 areg, GEN_INT (offset));
-         }
-    }
-
-  /* VRSAVE is a bit vector representing which AltiVec registers
-     are used.  The OS uses this to determine which vector
-     registers to save on a context switch.  We need to save
-     VRSAVE on the stack frame, add whatever AltiVec registers we
-     used in this function, and do the corresponding magic in the
-     epilogue.  */
-
-  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
-      && info->vrsave_mask != 0)
-    {
-      rtx reg, mem, vrsave;
-      int offset;
-
-      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
-        as frame_reg_rtx and r11 as the static chain pointer for
-        nested functions.  */
-      reg = gen_rtx_REG (SImode, 0);
-      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
-      if (TARGET_MACHO)
-       emit_insn (gen_get_vrsave_internal (reg));
-      else
-       emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
+         rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                  GEN_INT (info->lr_save_offset
+                                           + sp_offset));
+         rtx mem = gen_frame_mem (reg_mode, addr);
 
-      if (!WORLD_SAVE_P (info))
-       {
-          /* Save VRSAVE.  */
-          offset = info->vrsave_save_offset + sp_offset;
-          mem = gen_frame_mem (SImode,
-                              gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                            GEN_INT (offset)));
-          insn = emit_move_insn (mem, reg);
+         RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, mem, reg0);
        }
+      /* Explain what happens to the stack pointer.  */
+      {
+       rtx newval = gen_rtx_PLUS (Pmode, sp_reg_rtx, treg);
+       RTVEC_ELT (p, j++) = gen_rtx_SET (VOIDmode, sp_reg_rtx, newval);
+      }
 
-      /* Include the registers in the mask.  */
-      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
-
-      insn = emit_insn (generate_set_vrsave (reg, info, 0));
+      insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
+      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                           treg, GEN_INT (-info->total_size));
+      sp_offset = info->total_size;
     }
 
   /* If we use the link register, get it into r0.  */
   if (!WORLD_SAVE_P (info) && info->lr_save_p)
     {
+      rtx addr, reg, mem;
+
       insn = emit_move_insn (gen_rtx_REG (Pmode, 0),
-                            gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
+                            gen_rtx_REG (Pmode, LR_REGNO));
       RTX_FRAME_RELATED_P (insn) = 1;
+
+      addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                              GEN_INT (info->lr_save_offset + sp_offset));
+      reg = gen_rtx_REG (Pmode, 0);
+      mem = gen_rtx_MEM (Pmode, addr);
+      /* This should not be of rs6000_sr_alias_set, because of
+        __builtin_return_address.  */
+
+      insn = emit_move_insn (mem, reg);
+      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                           NULL_RTX, NULL_RTX);
     }
 
   /* If we need to save CR, put it into r12.  */
@@ -14770,7 +14923,7 @@ rs6000_emit_prologue (void)
     {
       int i;
       for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-       if ((regs_ever_live[info->first_fp_reg_save+i]
+       if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
             && ! call_used_regs[info->first_fp_reg_save+i]))
          emit_frame_save (frame_reg_rtx, frame_ptr_rtx, DFmode,
                           info->first_fp_reg_save + i,
@@ -14787,7 +14940,7 @@ rs6000_emit_prologue (void)
 
       RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
                                          gen_rtx_REG (Pmode,
-                                                      LINK_REGISTER_REGNUM));
+                                                      LR_REGNO));
       sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
               info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
       alloc_rname = ggc_strdup (rname);
@@ -14833,64 +14986,104 @@ rs6000_emit_prologue (void)
       rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
                            NULL_RTX, NULL_RTX);
     }
+   else if (!WORLD_SAVE_P (info)
+            && TARGET_SPE_ABI
+            && info->spe_64bit_regs_used != 0
+            && info->first_gp_reg_save != 32)
+     {
+       int i;
+       rtx spe_save_area_ptr;
+       int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE
+                                   && df_regs_ever_live_p (STATIC_CHAIN_REGNUM)
+                                   && !call_used_regs[STATIC_CHAIN_REGNUM]);
+       /* Determine whether we can address all of the registers that need
+          to be saved with an offset from the stack pointer that fits in
+          the small const field for SPE memory instructions.  */
+       int spe_regs_addressable_via_sp
+         = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                               + (32 - info->first_gp_reg_save - 1) * reg_size);
+       int spe_offset;
+       if (spe_regs_addressable_via_sp)
+         {
+           spe_save_area_ptr = sp_reg_rtx;
+           spe_offset = info->spe_gp_save_offset + sp_offset;
+         }
+       else
+         {
+           /* Make r11 point to the start of the SPE save area.  We need
+              to be careful here if r11 is holding the static chain.  If
+              it is, then temporarily save it in r0.  We would use r0 as
+              our base register here, but using r0 as a base register in
+              loads and stores means something different from what we
+              would like.  */
+           if (using_static_chain_p)
+             {
+               rtx r0 = gen_rtx_REG (Pmode, 0);
+               gcc_assert (info->first_gp_reg_save > 11);
+               emit_move_insn (r0, gen_rtx_REG (Pmode, 11));
+             }
+           spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+           emit_insn (gen_addsi3 (spe_save_area_ptr, sp_reg_rtx,
+                                  GEN_INT (info->spe_gp_save_offset + sp_offset)));
+           spe_offset = 0;
+         }
+       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+         if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+           {
+             rtx reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+             rtx offset, addr, mem;
+             /* We're doing all this to ensure that the offset fits into
+                the immediate offset of 'evstdd'.  */
+             gcc_assert (SPE_CONST_OFFSET_OK (reg_size * i + spe_offset));
+             offset = GEN_INT (reg_size * i + spe_offset);
+             addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+             mem = gen_rtx_MEM (V2SImode, addr);
+             insn = emit_move_insn (mem, reg);
+           
+             rs6000_frame_related (insn, spe_save_area_ptr,
+                                   info->spe_gp_save_offset
+                                   + sp_offset + reg_size * i,
+                                   offset, const0_rtx);
+           }
+       /* Move the static chain pointer back.  */
+       if (using_static_chain_p && !spe_regs_addressable_via_sp)
+         emit_move_insn (gen_rtx_REG (Pmode, 11), gen_rtx_REG (Pmode, 0));
+     }
   else if (!WORLD_SAVE_P (info))
     {
       int i;
       for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-       if ((regs_ever_live[info->first_gp_reg_save + i]
-            && (!call_used_regs[info->first_gp_reg_save + i]
-                || (i + info->first_gp_reg_save
-                    == RS6000_PIC_OFFSET_TABLE_REGNUM
-                    && TARGET_TOC && TARGET_MINIMAL_TOC)))
-           || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-               && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                   || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
-         {
-           rtx addr, reg, mem;
-           reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
-
-           if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-             {
-               int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-               rtx b;
-
-               if (!SPE_CONST_OFFSET_OK (offset))
-                 {
-                   b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                   emit_move_insn (b, GEN_INT (offset));
-                 }
-               else
-                 b = GEN_INT (offset);
-
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-               mem = gen_frame_mem (V2SImode, addr);
-               insn = emit_move_insn (mem, reg);
-
-               if (GET_CODE (b) == CONST_INT)
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       NULL_RTX, NULL_RTX);
-               else
-                 rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                       b, GEN_INT (offset));
-             }
-           else
-             {
-               addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                                    GEN_INT (info->gp_save_offset
-                                             + sp_offset
-                                             + reg_size * i));
-               mem = gen_frame_mem (reg_mode, addr);
-
-               insn = emit_move_insn (mem, reg);
-               rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                                     NULL_RTX, NULL_RTX);
-             }
-         }
+       if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx addr, reg, mem;
+            reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
+
+            addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                 GEN_INT (info->gp_save_offset
+                                          + sp_offset
+                                          + reg_size * i));
+            mem = gen_frame_mem (reg_mode, addr);
+
+            insn = emit_move_insn (mem, reg);
+            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                  NULL_RTX, NULL_RTX);
+          }
     }
 
   /* ??? There's no need to emit actual instructions here, but it's the
      easiest way to get the frame unwind information emitted.  */
-  if (!WORLD_SAVE_P (info) && current_function_calls_eh_return)
+  if (current_function_calls_eh_return)
     {
       unsigned int i, regno;
 
@@ -14923,21 +15116,6 @@ rs6000_emit_prologue (void)
        }
     }
 
-  /* Save lr if we used it.  */
-  if (!WORLD_SAVE_P (info) && info->lr_save_p)
-    {
-      rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
-                              GEN_INT (info->lr_save_offset + sp_offset));
-      rtx reg = gen_rtx_REG (Pmode, 0);
-      rtx mem = gen_rtx_MEM (Pmode, addr);
-      /* This should not be of frame_alias_set, because of
-        __builtin_return_address.  */
-
-      insn = emit_move_insn (mem, reg);
-      rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
-                           NULL_RTX, NULL_RTX);
-    }
-
   /* Save CR if we use any that must be preserved.  */
   if (!WORLD_SAVE_P (info) && info->cr_save_p)
     {
@@ -14972,7 +15150,19 @@ rs6000_emit_prologue (void)
      for which it was done previously.  */
   if (!WORLD_SAVE_P (info) && info->push_p
       && !(DEFAULT_ABI == ABI_V4 || current_function_calls_eh_return))
-    rs6000_emit_allocate_stack (info->total_size, FALSE);
+    {
+      if (info->total_size < 32767)
+      sp_offset = info->total_size;
+      else
+       frame_reg_rtx = frame_ptr_rtx;
+      rs6000_emit_allocate_stack (info->total_size,
+                                 (frame_reg_rtx != sp_reg_rtx
+                                  && ((info->altivec_size != 0)
+                                      || (info->vrsave_mask != 0)
+                                      )));
+      if (frame_reg_rtx != sp_reg_rtx)
+       rs6000_emit_stack_tie ();
+    }
 
   /* Set frame pointer, if needed.  */
   if (frame_pointer_needed)
@@ -14982,11 +15172,83 @@ rs6000_emit_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  /* Save AltiVec registers if needed.  Save here because the red zone does
+     not include AltiVec registers.  */
+  if (!WORLD_SAVE_P (info) && TARGET_ALTIVEC_ABI && info->altivec_size != 0)
+    {
+      int i;
+
+      /* There should be a non inline version of this, for when we
+         are saving lots of vector registers.  */
+      for (i = info->first_altivec_reg_save; i <= LAST_ALTIVEC_REGNO; ++i)
+        if (info->vrsave_mask & ALTIVEC_REG_BIT (i))
+          {
+            rtx areg, savereg, mem;
+            int offset;
+
+            offset = info->altivec_save_offset + sp_offset
+              + 16 * (i - info->first_altivec_reg_save);
+
+            savereg = gen_rtx_REG (V4SImode, i);
+
+            areg = gen_rtx_REG (Pmode, 0);
+            emit_move_insn (areg, GEN_INT (offset));
+
+            /* AltiVec addressing mode is [reg+reg].  */
+            mem = gen_frame_mem (V4SImode,
+                                 gen_rtx_PLUS (Pmode, frame_reg_rtx, areg));
+
+            insn = emit_move_insn (mem, savereg);
+
+            rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
+                                  areg, GEN_INT (offset));
+          }
+    }
+
+  /* VRSAVE is a bit vector representing which AltiVec registers
+     are used.  The OS uses this to determine which vector
+     registers to save on a context switch.  We need to save
+     VRSAVE on the stack frame, add whatever AltiVec registers we
+     used in this function, and do the corresponding magic in the
+     epilogue.  */
+
+  if (TARGET_ALTIVEC && TARGET_ALTIVEC_VRSAVE
+      && info->vrsave_mask != 0)
+    {
+      rtx reg, mem, vrsave;
+      int offset;
+
+      /* Get VRSAVE onto a GPR.  Note that ABI_V4 might be using r12
+         as frame_reg_rtx and r11 as the static chain pointer for
+         nested functions.  */
+      reg = gen_rtx_REG (SImode, 0);
+      vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO);
+      if (TARGET_MACHO)
+        emit_insn (gen_get_vrsave_internal (reg));
+      else
+        emit_insn (gen_rtx_SET (VOIDmode, reg, vrsave));
+
+      if (!WORLD_SAVE_P (info))
+        {
+          /* Save VRSAVE.  */
+          offset = info->vrsave_save_offset + sp_offset;
+          mem = gen_frame_mem (SImode,
+                               gen_rtx_PLUS (Pmode, frame_reg_rtx,
+                                             GEN_INT (offset)));
+          insn = emit_move_insn (mem, reg);
+        }
+
+      /* Include the registers in the mask.  */
+      emit_insn (gen_iorsi3 (reg, reg, GEN_INT ((int) info->vrsave_mask)));
+
+      insn = emit_insn (generate_set_vrsave (reg, info, 0));
+    }
+
   /* If we are using RS6000_PIC_OFFSET_TABLE_REGNUM, we need to set it up.  */
   if ((TARGET_TOC && TARGET_MINIMAL_TOC && get_pool_size () != 0)
       || (DEFAULT_ABI == ABI_V4
          && (flag_pic == 1 || (flag_pic && TARGET_SECURE_PLT))
-         && regs_ever_live[RS6000_PIC_OFFSET_TABLE_REGNUM]))
+         && df_regs_ever_live_p (RS6000_PIC_OFFSET_TABLE_REGNUM)))
     {
       /* If emit_load_toc_table will use the link register, we need to save
         it.  We use R12 for this purpose because emit_load_toc_table
@@ -14999,16 +15261,14 @@ rs6000_emit_prologue (void)
                                      && EDGE_COUNT (EXIT_BLOCK_PTR->preds) > 0);
       if (save_LR_around_toc_setup)
        {
-         rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+         rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
 
          insn = emit_move_insn (frame_ptr_rtx, lr);
-         rs6000_maybe_dead (insn);
          RTX_FRAME_RELATED_P (insn) = 1;
 
          rs6000_emit_load_toc_table (TRUE);
 
          insn = emit_move_insn (lr, frame_ptr_rtx);
-         rs6000_maybe_dead (insn);
          RTX_FRAME_RELATED_P (insn) = 1;
        }
       else
@@ -15019,22 +15279,21 @@ rs6000_emit_prologue (void)
   if (DEFAULT_ABI == ABI_DARWIN
       && flag_pic && current_function_uses_pic_offset_table)
     {
-      rtx lr = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
+      rtx lr = gen_rtx_REG (Pmode, LR_REGNO);
       rtx src = machopic_function_base_sym ();
 
       /* Save and restore LR locally around this call (in R0).  */
       if (!info->lr_save_p)
-       rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), lr));
+       emit_move_insn (gen_rtx_REG (Pmode, 0), lr);
 
-      rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (lr, src)));
+      emit_insn (gen_load_macho_picbase (src));
 
-      insn = emit_move_insn (gen_rtx_REG (Pmode,
-                                         RS6000_PIC_OFFSET_TABLE_REGNUM),
-                            lr);
-      rs6000_maybe_dead (insn);
+      emit_move_insn (gen_rtx_REG (Pmode,
+                                  RS6000_PIC_OFFSET_TABLE_REGNUM),
+                     lr);
 
       if (!info->lr_save_p)
-       rs6000_maybe_dead (emit_move_insn (lr, gen_rtx_REG (Pmode, 0)));
+       emit_move_insn (lr, gen_rtx_REG (Pmode, 0));
     }
 #endif
 }
@@ -15176,7 +15435,7 @@ rs6000_emit_epilogue (int sibcall)
       RTVEC_ELT (p, j++) = gen_rtx_RETURN (VOIDmode);
       RTVEC_ELT (p, j++) = gen_rtx_USE (VOIDmode,
                                        gen_rtx_REG (Pmode,
-                                                    LINK_REGISTER_REGNUM));
+                                                    LR_REGNO));
       RTVEC_ELT (p, j++)
        = gen_rtx_USE (VOIDmode, gen_rtx_SYMBOL_REF (Pmode, alloc_rname));
       /* The instruction pattern requires a clobber here;
@@ -15239,33 +15498,9 @@ rs6000_emit_epilogue (int sibcall)
       return;
     }
 
-  /* If we have a frame pointer, a call to alloca,  or a large stack
-     frame, restore the old stack pointer using the backchain.  Otherwise,
-     we know what size to update it with.  */
-  if (use_backchain_to_restore_sp)
-    {
-      /* Under V.4, don't reset the stack pointer until after we're done
-        loading the saved registers.  */
-      if (DEFAULT_ABI == ABI_V4)
-       frame_reg_rtx = gen_rtx_REG (Pmode, 11);
-
-      emit_move_insn (frame_reg_rtx,
-                     gen_rtx_MEM (Pmode, sp_reg_rtx));
-    }
-  else if (info->push_p)
-    {
-      if (DEFAULT_ABI == ABI_V4
-         || current_function_calls_eh_return)
-       sp_offset = info->total_size;
-      else
-       {
-         emit_insn (TARGET_32BIT
-                    ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
-                                  GEN_INT (info->total_size))
-                    : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
-                                  GEN_INT (info->total_size)));
-       }
-    }
+  /* Set sp_offset based on the stack push from the prologue.  */
+  if (info->total_size < 32767)
+    sp_offset = info->total_size;
 
   /* Restore AltiVec registers if needed.  */
   if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
@@ -15306,6 +15541,36 @@ rs6000_emit_epilogue (int sibcall)
       emit_insn (generate_set_vrsave (reg, info, 1));
     }
 
+  sp_offset = 0;
+
+  /* If we have a frame pointer, a call to alloca,  or a large stack
+     frame, restore the old stack pointer using the backchain.  Otherwise,
+     we know what size to update it with.  */
+  if (use_backchain_to_restore_sp)
+    {
+      /* Under V.4, don't reset the stack pointer until after we're done
+        loading the saved registers.  */
+      if (DEFAULT_ABI == ABI_V4)
+       frame_reg_rtx = gen_rtx_REG (Pmode, 11);
+
+      emit_move_insn (frame_reg_rtx,
+                     gen_rtx_MEM (Pmode, sp_reg_rtx));
+    }
+  else if (info->push_p)
+    {
+      if (DEFAULT_ABI == ABI_V4
+         || current_function_calls_eh_return)
+       sp_offset = info->total_size;
+      else
+       {
+         emit_insn (TARGET_32BIT
+                    ? gen_addsi3 (sp_reg_rtx, sp_reg_rtx,
+                                  GEN_INT (info->total_size))
+                    : gen_adddi3 (sp_reg_rtx, sp_reg_rtx,
+                                  GEN_INT (info->total_size)));
+       }
+    }
+
   /* Get the old lr if we saved it.  */
   if (info->lr_save_p)
     {
@@ -15327,7 +15592,7 @@ rs6000_emit_epilogue (int sibcall)
 
   /* Set LR here to try to overlap restores below.  */
   if (info->lr_save_p)
-    emit_move_insn (gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM),
+    emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO),
                    gen_rtx_REG (Pmode, 0));
 
   /* Load exception handler data registers, if needed.  */
@@ -15381,15 +15646,58 @@ rs6000_emit_epilogue (int sibcall)
        }
       emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
     }
+  else if (TARGET_SPE_ABI
+           && info->spe_64bit_regs_used != 0
+           && info->first_gp_reg_save != 32)
+    {
+      rtx spe_save_area_ptr;
+      /* Determine whether we can address all of the registers that need
+         to be saved with an offset from the stack pointer that fits in
+         the small const field for SPE memory instructions.  */
+      int spe_regs_addressable_via_sp
+        = SPE_CONST_OFFSET_OK(info->spe_gp_save_offset + sp_offset
+                              + (32 - info->first_gp_reg_save - 1) * reg_size);
+      int spe_offset;
+
+      if (spe_regs_addressable_via_sp)
+        {
+          spe_save_area_ptr = frame_reg_rtx;
+          spe_offset = info->spe_gp_save_offset + sp_offset;
+        }
+      else
+        {
+          /* Make r11 point to the start of the SPE save area.  We worried about
+             not clobbering it when we were saving registers in the prologue.
+             There's no need to worry here because the static chain is passed
+             anew to every function.  */
+          spe_save_area_ptr = gen_rtx_REG (Pmode, 11);
+
+          emit_insn (gen_addsi3 (spe_save_area_ptr, frame_reg_rtx,
+                                 GEN_INT (info->spe_gp_save_offset + sp_offset)));
+
+          spe_offset = 0;
+        }
+
+      for (i = 0; i < 32 - info->first_gp_reg_save; i++)
+        if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
+          {
+            rtx offset, addr, mem;
+
+            /* We're doing all this to ensure that the immediate offset
+               fits into the immediate field of 'evldd'.  */
+            gcc_assert (SPE_CONST_OFFSET_OK (spe_offset + reg_size * i));
+
+            offset = GEN_INT (spe_offset + reg_size * i);
+            addr = gen_rtx_PLUS (Pmode, spe_save_area_ptr, offset);
+            mem = gen_rtx_MEM (V2SImode, addr);
+
+            emit_move_insn (gen_rtx_REG (reg_mode, info->first_gp_reg_save + i),
+                            mem);
+          }
+    }
   else
     for (i = 0; i < 32 - info->first_gp_reg_save; i++)
-      if ((regs_ever_live[info->first_gp_reg_save + i]
-          && (!call_used_regs[info->first_gp_reg_save + i]
-              || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-                  && TARGET_TOC && TARGET_MINIMAL_TOC)))
-         || (i + info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
-             && ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
-                 || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
+      if (rs6000_reg_live_or_pic_offset_p (info->first_gp_reg_save + i))
        {
          rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
                                   GEN_INT (info->gp_save_offset
@@ -15397,24 +15705,6 @@ rs6000_emit_epilogue (int sibcall)
                                            + reg_size * i));
          rtx mem = gen_frame_mem (reg_mode, addr);
 
-         /* Restore 64-bit quantities for SPE.  */
-         if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
-           {
-             int offset = info->spe_gp_save_offset + sp_offset + 8 * i;
-             rtx b;
-
-             if (!SPE_CONST_OFFSET_OK (offset))
-               {
-                 b = gen_rtx_REG (Pmode, FIXED_SCRATCH);
-                 emit_move_insn (b, GEN_INT (offset));
-               }
-             else
-               b = GEN_INT (offset);
-
-             addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, b);
-             mem = gen_frame_mem (V2SImode, addr);
-           }
-
          emit_move_insn (gen_rtx_REG (reg_mode,
                                       info->first_gp_reg_save + i), mem);
        }
@@ -15422,7 +15712,7 @@ rs6000_emit_epilogue (int sibcall)
   /* Restore fpr's if we need to do it without calling a function.  */
   if (restoring_FPRs_inline)
     for (i = 0; i < 64 - info->first_fp_reg_save; i++)
-      if ((regs_ever_live[info->first_fp_reg_save+i]
+      if ((df_regs_ever_live_p (info->first_fp_reg_save+i)
           && ! call_used_regs[info->first_fp_reg_save+i]))
        {
          rtx addr, mem;
@@ -15446,7 +15736,7 @@ rs6000_emit_epilogue (int sibcall)
       if (using_mtcr_multiple)
        {
          for (i = 0; i < 8; i++)
-           if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+           if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
              count++;
          gcc_assert (count);
        }
@@ -15460,7 +15750,7 @@ rs6000_emit_epilogue (int sibcall)
 
          ndx = 0;
          for (i = 0; i < 8; i++)
-           if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+           if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
              {
                rtvec r = rtvec_alloc (2);
                RTVEC_ELT (r, 0) = r12_rtx;
@@ -15475,7 +15765,7 @@ rs6000_emit_epilogue (int sibcall)
        }
       else
        for (i = 0; i < 8; i++)
-         if (regs_ever_live[CR0_REGNO+i] && ! call_used_regs[CR0_REGNO+i])
+         if (df_regs_ever_live_p (CR0_REGNO+i) && ! call_used_regs[CR0_REGNO+i])
            {
              emit_insn (gen_movsi_to_cr_one (gen_rtx_REG (CCmode,
                                                           CR0_REGNO+i),
@@ -15490,7 +15780,13 @@ rs6000_emit_epilogue (int sibcall)
       /* This blockage is needed so that sched doesn't decide to move
         the sp change before the register restores.  */
       rs6000_emit_stack_tie ();
-      emit_move_insn (sp_reg_rtx, frame_reg_rtx);
+      if (TARGET_SPE_ABI
+          && info->spe_64bit_regs_used != 0
+          && info->first_gp_reg_save != 32)
+        emit_insn (gen_addsi3 (sp_reg_rtx, gen_rtx_REG (Pmode, 11),
+                               GEN_INT (-(info->spe_gp_save_offset + sp_offset))));
+      else
+        emit_move_insn (sp_reg_rtx, frame_reg_rtx);
     }
   else if (sp_offset != 0)
     emit_insn (TARGET_32BIT
@@ -15518,7 +15814,7 @@ rs6000_emit_epilogue (int sibcall)
       RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode);
       RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
                                      gen_rtx_REG (Pmode,
-                                                  LINK_REGISTER_REGNUM));
+                                                  LR_REGNO));
 
       /* If we have to restore more than two FP registers, branch to the
         restore function.  It will return to our caller.  */
@@ -15604,12 +15900,12 @@ rs6000_output_function_epilogue (FILE *file,
     rtx insn = get_last_insn ();
     while (insn
           && NOTE_P (insn)
-          && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED_LABEL)
+          && NOTE_KIND (insn) != NOTE_INSN_DELETED_LABEL)
       insn = PREV_INSN (insn);
     if (insn
        && (LABEL_P (insn)
            || (NOTE_P (insn)
-               && NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED_LABEL)))
+               && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL)))
       fputs ("\tnop\n", file);
   }
 #endif
@@ -15756,7 +16052,9 @@ rs6000_output_function_epilogue (FILE *file,
                          break;
 
                        case DFmode:
+                       case DDmode:
                        case TFmode:
+                       case TDmode:
                          bits = 0x3;
                          break;
 
@@ -15888,8 +16186,6 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 1;
   epilogue_completed = 1;
-  no_new_pseudos = 1;
-  reset_block_changes ();
 
   /* Mark the end of the (empty) prologue.  */
   emit_note (NOTE_INSN_PROLOGUE_END);
@@ -15959,7 +16255,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                        gen_rtx_USE (VOIDmode, const0_rtx),
                        gen_rtx_USE (VOIDmode,
                                     gen_rtx_REG (SImode,
-                                                 LINK_REGISTER_REGNUM)),
+                                                 LR_REGNO)),
                        gen_rtx_RETURN (VOIDmode))));
   SIBLING_CALL_P (insn) = 1;
   emit_barrier ();
@@ -15969,7 +16265,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1);
@@ -15977,7 +16273,6 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 0;
   epilogue_completed = 0;
-  no_new_pseudos = 0;
 }
 \f
 /* A quick summary of the various types of 'constant-pool tables'
@@ -16609,7 +16904,7 @@ output_profile_hook (int labelno ATTRIBUTE_UNUSED)
   else if (DEFAULT_ABI == ABI_DARWIN)
     {
       const char *mcount_name = RS6000_MCOUNT;
-      int caller_addr_regno = LINK_REGISTER_REGNUM;
+      int caller_addr_regno = LR_REGNO;
 
       /* Be conservative and always set this, at least for now.  */
       current_function_uses_pic_offset_table = 1;
@@ -16847,7 +17142,7 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
                  || rs6000_cpu_attr == CPU_CELL)
                 && recog_memoized (dep_insn)
                 && (INSN_CODE (dep_insn) >= 0))
-              
+
               switch (get_attr_type (dep_insn))
                 {
                 case TYPE_CMP:
@@ -17390,7 +17685,7 @@ rs6000_use_sched_lookahead_guard (rtx insn)
 
    if (insn == NULL_RTX || !INSN_P (insn))
      abort ();
-   
+
   if (!reload_completed
       || is_nonpipeline_insn (insn)
       || is_microcoded_insn (insn))
@@ -17527,9 +17822,11 @@ get_store_dest (rtx pat)
    costly by the given target.  */
 
 static bool
-rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
-                            int distance)
+rs6000_is_costly_dependence (dep_t dep, int cost, int distance)
 {
+  rtx insn;
+  rtx next;
+
   /* If the flag is not enabled - no dependence is considered costly;
      allow all dependent insns in the same group.
      This is the most aggressive option.  */
@@ -17542,6 +17839,9 @@ rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
   if (rs6000_sched_costly_dep == all_deps_costly)
     return true;
 
+  insn = DEP_PRO (dep);
+  next = DEP_CON (dep);
+
   if (rs6000_sched_costly_dep == store_to_load_dep_costly
       && is_load_insn (next)
       && is_store_insn (insn))
@@ -17551,7 +17851,7 @@ rs6000_is_costly_dependence (rtx insn, rtx next, rtx link, int cost,
   if (rs6000_sched_costly_dep == true_store_to_load_dep_costly
       && is_load_insn (next)
       && is_store_insn (insn)
-      && (!link || (int) REG_NOTE_KIND (link) == 0))
+      && DEP_KIND (dep) == REG_DEP_TRUE)
      /* Prevent load after store in the same group if it is a true
        dependence.  */
      return true;
@@ -18023,24 +18323,24 @@ static bool
 is_costly_group (rtx *group_insns, rtx next_insn)
 {
   int i;
-  rtx link;
-  int cost;
   int issue_rate = rs6000_issue_rate ();
 
   for (i = 0; i < issue_rate; i++)
     {
+      dep_link_t link;
       rtx insn = group_insns[i];
+
       if (!insn)
        continue;
-      for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
+
+      FOR_EACH_DEP_LINK (link, INSN_FORW_DEPS (insn))
        {
-         rtx next = XEXP (link, 0);
-         if (next == next_insn)
-           {
-             cost = insn_cost (insn, link, next_insn);
-             if (rs6000_is_costly_dependence (insn, next_insn, link, cost, 0))
-               return true;
-           }
+         dep_t dep = DEP_LINK_DEP (link);
+         rtx next = DEP_CON (dep);
+
+         if (next == next_insn
+             && rs6000_is_costly_dependence (dep, dep_cost (dep), 0))
+           return true;
        }
     }
 
@@ -18342,7 +18642,7 @@ static void
 rs6000_sched_init (FILE *dump ATTRIBUTE_UNUSED,
                     int sched_verbose ATTRIBUTE_UNUSED,
                     int max_ready ATTRIBUTE_UNUSED)
-{   
+{
   last_scheduled_insn = NULL_RTX;
   load_store_pendulum = 0;
 }
@@ -18781,37 +19081,6 @@ rs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
   else
     return default_elf_select_rtx_section (mode, x, align);
 }
-
-/* Implement TARGET_ASM_SELECT_SECTION for ELF targets.  */
-
-static section *
-rs6000_elf_select_section (tree decl, int reloc,
-                          unsigned HOST_WIDE_INT align)
-{
-  /* Pretend that we're always building for a shared library when
-     ABI_AIX, because otherwise we end up with dynamic relocations
-     in read-only sections.  This happens for function pointers,
-     references to vtables in typeinfo, and probably other cases.  */
-  return default_elf_select_section_1 (decl, reloc, align,
-                                      flag_pic || DEFAULT_ABI == ABI_AIX);
-}
-
-/* A C statement to build up a unique section name, expressed as a
-   STRING_CST node, and assign it to DECL_SECTION_NAME (decl).
-   RELOC indicates whether the initial value of EXP requires
-   link-time relocations.  If you do not define this macro, GCC will use
-   the symbol name prefixed by `.' as the section name.  Note - this
-   macro can now be called for uninitialized data items as well as
-   initialized data and functions.  */
-
-static void
-rs6000_elf_unique_section (tree decl, int reloc)
-{
-  /* As above, pretend that we're always building for a shared library
-     when ABI_AIX, to avoid dynamic relocations in read-only sections.  */
-  default_unique_section_1 (decl, reloc,
-                           flag_pic || DEFAULT_ABI == ABI_AIX);
-}
 \f
 /* For a SYMBOL_REF, set generic flags and then perform some
    target-specific processing.
@@ -19054,6 +19323,14 @@ get_prev_label (tree function_name)
   return 0;
 }
 
+#ifndef DARWIN_LINKER_GENERATES_ISLANDS
+#define DARWIN_LINKER_GENERATES_ISLANDS 0
+#endif
+
+/* KEXTs still need branch islands.  */
+#define DARWIN_GENERATE_ISLANDS (!DARWIN_LINKER_GENERATES_ISLANDS \
+                                || flag_mkernel || flag_apple_kext)
+
 /* INSN is either a function call or a millicode call.  It may have an
    unconditional jump in its delay slot.
 
@@ -19064,7 +19341,8 @@ output_call (rtx insn, rtx *operands, int dest_operand_number,
             int cookie_operand_number)
 {
   static char buf[256];
-  if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
+  if (DARWIN_GENERATE_ISLANDS
+      && GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
       && (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
     {
       tree labelname;
@@ -19072,17 +19350,13 @@ output_call (rtx insn, rtx *operands, int dest_operand_number,
 
       if (no_previous_def (funname))
        {
-         int line_number = 0;
          rtx label_rtx = gen_label_rtx ();
          char *label_buf, temp_buf[256];
          ASM_GENERATE_INTERNAL_LABEL (temp_buf, "L",
                                       CODE_LABEL_NUMBER (label_rtx));
          label_buf = temp_buf[0] == '*' ? temp_buf + 1 : temp_buf;
          labelname = get_identifier (label_buf);
-         for (; insn && GET_CODE (insn) != NOTE; insn = PREV_INSN (insn));
-         if (insn)
-           line_number = NOTE_LINE_NUMBER (insn);
-         add_compiler_branch_island (labelname, funname, line_number);
+         add_compiler_branch_island (labelname, funname, insn_line (insn));
        }
       else
        labelname = get_prev_label (funname);
@@ -19199,7 +19473,7 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
 
       /* Use a different reg for the intermediate value, as
         it will be marked UNCHANGING.  */
-      reg_temp = no_new_pseudos ? reg : gen_reg_rtx (Pmode);
+      reg_temp = !can_create_pseudo_p () ? reg : gen_reg_rtx (Pmode);
       base = rs6000_machopic_legitimize_pic_address (XEXP (XEXP (orig, 0), 0),
                                                     Pmode, reg_temp);
       offset =
@@ -19281,11 +19555,15 @@ rs6000_darwin_file_start (void)
 #endif /* TARGET_MACHO */
 
 #if TARGET_ELF
-static unsigned int
-rs6000_elf_section_type_flags (tree decl, const char *name, int reloc)
+static int
+rs6000_elf_reloc_rw_mask (void)
 {
-  return default_section_type_flags_1 (decl, name, reloc,
-                                      flag_pic || DEFAULT_ABI == ABI_AIX);
+  if (flag_pic)
+    return 3;
+  else if (DEFAULT_ABI == ABI_AIX)
+    return 2;
+  else
+    return 0;
 }
 
 /* Record an element in the table of global constructors.  SYMBOL is
@@ -19523,6 +19801,12 @@ rs6000_xcoff_asm_init_sections (void)
   exception_section = data_section;
 }
 
+static int
+rs6000_xcoff_reloc_rw_mask (void)
+{
+  return 3;
+}
+
 static void
 rs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
                                tree decl ATTRIBUTE_UNUSED)
@@ -19546,7 +19830,7 @@ static section *
 rs6000_xcoff_select_section (tree decl, int reloc,
                             unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  if (decl_readonly_section_1 (decl, reloc, 1))
+  if (decl_readonly_section (decl, reloc))
     {
       if (TREE_PUBLIC (decl))
        return read_only_data_section;
@@ -19618,7 +19902,7 @@ static unsigned int
 rs6000_xcoff_section_type_flags (tree decl, const char *name, int reloc)
 {
   unsigned int align;
-  unsigned int flags = default_section_type_flags_1 (decl, name, reloc, 1);
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
 
   /* Align to at least UNIT size.  */
   if (flags & SECTION_CODE)
@@ -20081,7 +20365,7 @@ rs6000_register_move_cost (enum machine_mode mode,
 
   /* Moving between two similar registers is just one instruction.  */
   else if (reg_classes_intersect_p (to, from))
-    return mode == TFmode ? 4 : 2;
+    return (mode == TFmode || mode == TDmode) ? 4 : 2;
 
   /* Everything else has to go through GENERAL_REGS.  */
   else
@@ -20209,6 +20493,102 @@ rs6000_emit_swdivdf (rtx res, rtx n, rtx d)
                                        gen_rtx_MULT (DFmode, v0, y3), u0)));
 }
 
+
+/* Emit popcount intrinsic on TARGET_POPCNTB targets.  DST is the
+   target, and SRC is the argument operand.  */
+
+void
+rs6000_emit_popcount (rtx dst, rtx src)
+{
+  enum machine_mode mode = GET_MODE (dst);
+  rtx tmp1, tmp2;
+
+  tmp1 = gen_reg_rtx (mode);
+
+  if (mode == SImode)
+    {
+      emit_insn (gen_popcntbsi2 (tmp1, src));
+      tmp2 = expand_mult (SImode, tmp1, GEN_INT (0x01010101),
+                          NULL_RTX, 0);
+      tmp2 = force_reg (SImode, tmp2);
+      emit_insn (gen_lshrsi3 (dst, tmp2, GEN_INT (24)));
+    }
+  else
+    {
+      emit_insn (gen_popcntbdi2 (tmp1, src));
+      tmp2 = expand_mult (DImode, tmp1,
+                         GEN_INT ((HOST_WIDE_INT)
+                                  0x01010101 << 32 | 0x01010101),
+                         NULL_RTX, 0);
+      tmp2 = force_reg (DImode, tmp2);
+      emit_insn (gen_lshrdi3 (dst, tmp2, GEN_INT (56)));
+    }
+}
+
+
+/* Emit parity intrinsic on TARGET_POPCNTB targets.  DST is the
+   target, and SRC is the argument operand.  */
+
+void
+rs6000_emit_parity (rtx dst, rtx src)
+{
+  enum machine_mode mode = GET_MODE (dst);
+  rtx tmp;
+
+  tmp = gen_reg_rtx (mode);
+  if (mode == SImode)
+    {
+      /* Is mult+shift >= shift+xor+shift+xor?  */
+      if (rs6000_cost->mulsi_const >= COSTS_N_INSNS (3))
+       {
+         rtx tmp1, tmp2, tmp3, tmp4;
+
+         tmp1 = gen_reg_rtx (SImode);
+         emit_insn (gen_popcntbsi2 (tmp1, src));
+
+         tmp2 = gen_reg_rtx (SImode);
+         emit_insn (gen_lshrsi3 (tmp2, tmp1, GEN_INT (16)));
+         tmp3 = gen_reg_rtx (SImode);
+         emit_insn (gen_xorsi3 (tmp3, tmp1, tmp2));
+
+         tmp4 = gen_reg_rtx (SImode);
+         emit_insn (gen_lshrsi3 (tmp4, tmp3, GEN_INT (8)));
+         emit_insn (gen_xorsi3 (tmp, tmp3, tmp4));
+       }
+      else
+       rs6000_emit_popcount (tmp, src);
+      emit_insn (gen_andsi3 (dst, tmp, const1_rtx));
+    }
+  else
+    {
+      /* Is mult+shift >= shift+xor+shift+xor+shift+xor?  */
+      if (rs6000_cost->muldi >= COSTS_N_INSNS (5))
+       {
+         rtx tmp1, tmp2, tmp3, tmp4, tmp5, tmp6;
+
+         tmp1 = gen_reg_rtx (DImode);
+         emit_insn (gen_popcntbdi2 (tmp1, src));
+
+         tmp2 = gen_reg_rtx (DImode);
+         emit_insn (gen_lshrdi3 (tmp2, tmp1, GEN_INT (32)));
+         tmp3 = gen_reg_rtx (DImode);
+         emit_insn (gen_xordi3 (tmp3, tmp1, tmp2));
+
+         tmp4 = gen_reg_rtx (DImode);
+         emit_insn (gen_lshrdi3 (tmp4, tmp3, GEN_INT (16)));
+         tmp5 = gen_reg_rtx (DImode);
+         emit_insn (gen_xordi3 (tmp5, tmp3, tmp4));
+
+         tmp6 = gen_reg_rtx (DImode);
+         emit_insn (gen_lshrdi3 (tmp6, tmp5, GEN_INT (8)));
+         emit_insn (gen_xordi3 (tmp, tmp5, tmp6));
+       }
+      else
+        rs6000_emit_popcount (tmp, src);
+      emit_insn (gen_anddi3 (dst, tmp, const1_rtx));
+    }
+}
+
 /* Return an RTX representing where to find the function value of a
    function returning MODE.  */
 static rtx
@@ -20310,15 +20690,34 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
                                      GEN_INT (12))));
     }
 
-  if ((INTEGRAL_TYPE_P (valtype)
-       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
+  mode = TYPE_MODE (valtype);
+  if ((INTEGRAL_TYPE_P (valtype) && GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
     mode = TARGET_32BIT ? SImode : DImode;
-  else
-    mode = TYPE_MODE (valtype);
 
   if (DECIMAL_FLOAT_MODE_P (mode))
-    regno = GP_ARG_RETURN;
+    {
+      if (TARGET_HARD_FLOAT && TARGET_FPRS)
+       {
+         switch (mode)
+           {
+           default:
+             gcc_unreachable ();
+           case SDmode:
+             regno = GP_ARG_RETURN;
+             break;
+           case DDmode:
+             regno = FP_ARG_RETURN;
+             break;
+           case TDmode:
+             /* Use f2:f3 specified by the ABI.  */
+             regno = FP_ARG_RETURN + 1;
+             break;
+           }
+       }
+      else
+       regno = GP_ARG_RETURN;
+    }
   else if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
   else if (TREE_CODE (valtype) == COMPLEX_TYPE
@@ -20360,7 +20759,28 @@ rs6000_libcall_value (enum machine_mode mode)
     }
 
   if (DECIMAL_FLOAT_MODE_P (mode))
-    regno = GP_ARG_RETURN;
+    {
+      if (TARGET_HARD_FLOAT && TARGET_FPRS)
+       {
+         switch (mode)
+           {
+           default:
+             gcc_unreachable ();
+           case SDmode:
+             regno = GP_ARG_RETURN;
+             break;
+           case DDmode:
+             regno = FP_ARG_RETURN;
+             break;
+           case TDmode:
+             /* Use f2:f3 specified by the ABI.  */
+             regno = FP_ARG_RETURN + 1;
+             break;
+           }
+       }
+      else
+       regno = GP_ARG_RETURN;
+    }
   else if (SCALAR_FLOAT_MODE_P (mode)
           && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
@@ -20450,6 +20870,30 @@ rs6000_dwarf_register_span (rtx reg)
                                   gen_rtx_REG (SImode, regno + 1200)));
 }
 
+/* Fill in sizes for SPE register high parts in table used by unwinder.  */
+
+static void
+rs6000_init_dwarf_reg_sizes_extra (tree address)
+{
+  if (TARGET_SPE)
+    {
+      int i;
+      enum machine_mode mode = TYPE_MODE (char_type_node);
+      rtx addr = expand_expr (address, NULL_RTX, VOIDmode, 0);
+      rtx mem = gen_rtx_MEM (BLKmode, addr);
+      rtx value = gen_int_mode (4, mode);
+
+      for (i = 1201; i < 1232; i++)
+       {
+         int column = DWARF_REG_TO_UNWIND_COLUMN (i);
+         HOST_WIDE_INT offset
+           = DWARF_FRAME_REGNUM (column) * GET_MODE_SIZE (mode);
+
+         emit_move_insn (adjust_address (mem, mode, offset), value);
+       }
+    }
+}
+
 /* Map internal gcc register numbers to DWARF2 register numbers.  */
 
 unsigned int
@@ -20459,9 +20903,9 @@ rs6000_dbx_register_number (unsigned int regno)
     return regno;
   if (regno == MQ_REGNO)
     return 100;
-  if (regno == LINK_REGISTER_REGNUM)
+  if (regno == LR_REGNO)
     return 108;
-  if (regno == COUNT_REGISTER_REGNUM)
+  if (regno == CTR_REGNO)
     return 109;
   if (CR_REGNO_P (regno))
     return regno - CR0_REGNO + 86;