OSDN Git Service

* config/rs6000/rs6000.c (rs6000_output_function_epilogue): Update
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 586c481..3793976 100644 (file)
@@ -171,7 +171,7 @@ int rs6000_long_double_type_size;
 /* IEEE quad extended precision long double. */
 int rs6000_ieeequad;
 
-/* Whether -mabi=altivec has appeared.  */
+/* Nonzero to use AltiVec ABI.  */
 int rs6000_altivec_abi;
 
 /* Nonzero if we want SPE ABI extensions.  */
@@ -262,12 +262,14 @@ int rs6000_alignment_flags;
 struct {
   bool aix_struct_ret;         /* True if -maix-struct-ret was used.  */
   bool alignment;              /* True if -malign- was used.  */
-  bool abi;                    /* True if -mabi=spe/nospe was used.  */
+  bool spe_abi;                        /* True if -mabi=spe/no-spe was used.  */
+  bool altivec_abi;            /* True if -mabi=altivec/no-altivec used.  */
   bool spe;                    /* True if -mspe= was used.  */
   bool float_gprs;             /* True if -mfloat-gprs= was used.  */
   bool isel;                   /* True if -misel was used. */
   bool long_double;            /* True if -mlong-double- was used.  */
   bool ieee;                   /* True if -mabi=ieee/ibmlongdouble used.  */
+  bool vrsave;                 /* True if -mvrsave was used.  */
 } rs6000_explicit_options;
 
 struct builtin_description
@@ -356,7 +358,7 @@ struct processor_costs rios1_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (19),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   64,                  /* l1 cache */
   512,                 /* l2 cache */
   0,                   /* streams */
@@ -375,7 +377,7 @@ struct processor_costs rios2_cost = {
   COSTS_N_INSNS (2),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
-  256,
+  256,                 /* cache line size */
   256,                 /* l1 cache */
   1024,                        /* l2 cache */
   0,                   /* streams */
@@ -394,7 +396,7 @@ struct processor_costs rs64a_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (31),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   128,                 /* l1 cache */
   2048,                        /* l2 cache */
   1,                   /* streams */
@@ -413,7 +415,7 @@ struct processor_costs mpccore_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (10),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   4,                   /* l1 cache */
   16,                  /* l2 cache */
   1,                   /* streams */
@@ -432,7 +434,7 @@ struct processor_costs ppc403_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   4,                   /* l1 cache */
   16,                  /* l2 cache */
   1,                   /* streams */
@@ -451,7 +453,7 @@ struct processor_costs ppc405_cost = {
   COSTS_N_INSNS (11),   /* dmul */
   COSTS_N_INSNS (11),   /* sdiv */
   COSTS_N_INSNS (11),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   16,                  /* l1 cache */
   128,                 /* l2 cache */
   1,                   /* streams */
@@ -470,7 +472,7 @@ struct processor_costs ppc440_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (19),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   256,                 /* l2 cache */
   1,                   /* streams */
@@ -489,7 +491,7 @@ struct processor_costs ppc601_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   256,                 /* l2 cache */
   1,                   /* streams */
@@ -508,7 +510,7 @@ struct processor_costs ppc603_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (33),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   8,                   /* l1 cache */
   64,                  /* l2 cache */
   1,                   /* streams */
@@ -527,7 +529,7 @@ struct processor_costs ppc604_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   16,                  /* l1 cache */
   512,                 /* l2 cache */
   1,                   /* streams */
@@ -546,7 +548,7 @@ struct processor_costs ppc604e_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   1024,                        /* l2 cache */
   1,                   /* streams */
@@ -565,7 +567,7 @@ struct processor_costs ppc620_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (18),   /* sdiv */
   COSTS_N_INSNS (32),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   32,                  /* l1 cache */
   1024,                        /* l2 cache */
   1,                   /* streams */
@@ -584,7 +586,7 @@ struct processor_costs ppc630_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (21),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   64,                  /* l1 cache */
   1024,                        /* l2 cache */
   1,                   /* streams */
@@ -604,7 +606,7 @@ struct processor_costs ppccell_cost = {
   COSTS_N_INSNS (10/2),   /* dmul */
   COSTS_N_INSNS (74/2),   /* sdiv */
   COSTS_N_INSNS (74/2),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   32,                  /* l1 cache */
   512,                 /* l2 cache */
   6,                   /* streams */
@@ -623,7 +625,7 @@ struct processor_costs ppc750_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (31),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   512,                 /* l2 cache */
   1,                   /* streams */
@@ -642,7 +644,7 @@ struct processor_costs ppc7450_cost = {
   COSTS_N_INSNS (5),    /* dmul */
   COSTS_N_INSNS (21),   /* sdiv */
   COSTS_N_INSNS (35),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   1024,                        /* l2 cache */
   1,                   /* streams */
@@ -661,12 +663,31 @@ struct processor_costs ppc8540_cost = {
   COSTS_N_INSNS (4),    /* dmul */
   COSTS_N_INSNS (29),   /* sdiv */
   COSTS_N_INSNS (29),   /* ddiv */
-  32,
+  32,                  /* cache line size */
   32,                  /* l1 cache */
   256,                 /* l2 cache */
   1,                   /* prefetch streams /*/
 };
 
+/* Instruction costs on E300C2 and E300C3 cores.  */
+static const
+struct processor_costs ppce300c2c3_cost = {
+  COSTS_N_INSNS (4),    /* mulsi */
+  COSTS_N_INSNS (4),    /* mulsi_const */
+  COSTS_N_INSNS (4),    /* mulsi_const9 */
+  COSTS_N_INSNS (4),    /* muldi */
+  COSTS_N_INSNS (19),   /* divsi */
+  COSTS_N_INSNS (19),   /* divdi */
+  COSTS_N_INSNS (3),    /* fp */
+  COSTS_N_INSNS (4),    /* dmul */
+  COSTS_N_INSNS (18),   /* sdiv */
+  COSTS_N_INSNS (33),   /* ddiv */
+  32,
+  16,                  /* l1 cache */
+  16,                  /* l2 cache */
+  1,                   /* prefetch streams /*/
+};
+
 /* Instruction costs on POWER4 and POWER5 processors.  */
 static const
 struct processor_costs power4_cost = {
@@ -680,7 +701,7 @@ struct processor_costs power4_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (17),   /* sdiv */
   COSTS_N_INSNS (17),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   32,                  /* l1 cache */
   1024,                        /* l2 cache */
   8,                   /* prefetch streams /*/
@@ -699,7 +720,7 @@ struct processor_costs power6_cost = {
   COSTS_N_INSNS (3),    /* dmul */
   COSTS_N_INSNS (13),   /* sdiv */
   COSTS_N_INSNS (16),   /* ddiv */
-  128,
+  128,                 /* cache line size */
   64,                  /* l1 cache */
   2048,                        /* l2 cache */
   16,                  /* prefetch streams */
@@ -711,7 +732,6 @@ static const char *rs6000_invalid_within_doloop (const_rtx);
 static rtx rs6000_generate_compare (enum rtx_code);
 static void rs6000_emit_stack_tie (void);
 static void rs6000_frame_related (rtx, rtx, HOST_WIDE_INT, rtx, rtx);
-static rtx spe_synthesize_frame_save (rtx);
 static bool spe_func_has_64bit_regs_p (void);
 static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int,
                             int, HOST_WIDE_INT);
@@ -1418,6 +1438,8 @@ rs6000_override_options (const char *default_cpu)
         {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
         /* 8548 has a dummy entry for now.  */
         {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN},
+        {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
+        {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK},
         {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT},
         {"970", PROCESSOR_POWER4,
          POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64},
@@ -1524,6 +1546,14 @@ rs6000_override_options (const char *default_cpu)
   if (TARGET_E500)
     rs6000_isel = 1;
 
+  if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3)
+    {
+      if (TARGET_ALTIVEC)
+       error ("AltiVec not supported in this target");
+      if (TARGET_SPE)
+       error ("Spe not supported in this target");
+    }
+
   /* If we are optimizing big endian systems for space, use the load/store
      multiple and string instructions.  */
   if (BYTES_BIG_ENDIAN && optimize_size)
@@ -1590,11 +1620,18 @@ rs6000_override_options (const char *default_cpu)
   if (TARGET_XCOFF && TARGET_ALTIVEC)
     rs6000_altivec_abi = 1;
 
-  /* Set Altivec ABI as default for PowerPC64 Linux.  */
-  if (TARGET_ELF && TARGET_64BIT)
+  /* The AltiVec ABI is the default for PowerPC-64 GNU/Linux.  For
+     PowerPC-32 GNU/Linux, -maltivec implies the AltiVec ABI.  It can
+     be explicitly overridden in either case.  */
+  if (TARGET_ELF)
     {
-      rs6000_altivec_abi = 1;
-      TARGET_ALTIVEC_VRSAVE = 1;
+      if (!rs6000_explicit_options.altivec_abi
+         && (TARGET_64BIT || TARGET_ALTIVEC))
+       rs6000_altivec_abi = 1;
+
+      /* Enable VRSAVE for AltiVec ABI, unless explicitly overridden.  */
+      if (!rs6000_explicit_options.vrsave)
+       TARGET_ALTIVEC_VRSAVE = rs6000_altivec_abi;
     }
 
   /* Set the Darwin64 ABI as default for 64-bit Darwin.  */
@@ -1638,7 +1675,7 @@ rs6000_override_options (const char *default_cpu)
       /* For the powerpc-eabispe configuration, we set all these by
         default, so let's unset them if we manually set another
         CPU that is not the E500.  */
-      if (!rs6000_explicit_options.abi)
+      if (!rs6000_explicit_options.spe_abi)
        rs6000_spe_abi = 0;
       if (!rs6000_explicit_options.spe)
        rs6000_spe = 0;
@@ -1836,6 +1873,11 @@ rs6000_override_options (const char *default_cpu)
        rs6000_cost = &ppc8540_cost;
        break;
 
+      case PROCESSOR_PPCE300C2:
+      case PROCESSOR_PPCE300C3:
+       rs6000_cost = &ppce300c2c3_cost;
+       break;
+
       case PROCESSOR_POWER4:
       case PROCESSOR_POWER5:
        rs6000_cost = &power4_cost;
@@ -2131,6 +2173,7 @@ rs6000_handle_option (size_t code, const char *arg, int value)
       break;
 
     case OPT_mvrsave_:
+      rs6000_explicit_options.vrsave = true;
       rs6000_parse_yes_no_option ("vrsave", arg, &(TARGET_ALTIVEC_VRSAVE));
       break;
 
@@ -2188,19 +2231,20 @@ rs6000_handle_option (size_t code, const char *arg, int value)
     case OPT_mabi_:
       if (!strcmp (arg, "altivec"))
        {
-         rs6000_explicit_options.abi = true;
+         rs6000_explicit_options.altivec_abi = true;
          rs6000_altivec_abi = 1;
+
+         /* Enabling the AltiVec ABI turns off the SPE ABI.  */
          rs6000_spe_abi = 0;
        }
       else if (! strcmp (arg, "no-altivec"))
        {
-         /* ??? Don't set rs6000_explicit_options.abi here, to allow
-            the default for rs6000_spe_abi to be chosen later.  */
+         rs6000_explicit_options.altivec_abi = true;
          rs6000_altivec_abi = 0;
        }
       else if (! strcmp (arg, "spe"))
        {
-         rs6000_explicit_options.abi = true;
+         rs6000_explicit_options.spe_abi = true;
          rs6000_spe_abi = 1;
          rs6000_altivec_abi = 0;
          if (!TARGET_SPE_ABI)
@@ -2208,7 +2252,7 @@ rs6000_handle_option (size_t code, const char *arg, int value)
        }
       else if (! strcmp (arg, "no-spe"))
        {
-         rs6000_explicit_options.abi = true;
+         rs6000_explicit_options.spe_abi = true;
          rs6000_spe_abi = 0;
        }
 
@@ -2921,6 +2965,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
 
   if (n_var == 0)
     {
+      rtx const_vec = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
       if (mode != V4SFmode && all_const_zero)
        {
          /* Zero register.  */
@@ -2928,10 +2973,10 @@ rs6000_expand_vector_init (rtx target, rtx vals)
                                  gen_rtx_XOR (mode, target, target)));
          return;
        }
-      else if (mode != V4SFmode && easy_vector_constant (vals, mode))
+      else if (mode != V4SFmode && easy_vector_constant (const_vec, mode))
        {
          /* Splat immediate.  */
-         emit_insn (gen_rtx_SET (VOIDmode, target, vals));
+         emit_insn (gen_rtx_SET (VOIDmode, target, const_vec));
          return;
        }
       else if (all_same)
@@ -2939,7 +2984,7 @@ rs6000_expand_vector_init (rtx target, rtx vals)
       else
        {
          /* Load from constant pool.  */
-         emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
+         emit_move_insn (target, const_vec);
          return;
        }
     }
@@ -3238,6 +3283,13 @@ small_data_operand (rtx op ATTRIBUTE_UNUSED,
   if (DEFAULT_ABI != ABI_V4)
     return 0;
 
+  /* Vector and float memory instructions have a limited offset on the
+     SPE, so using a vector or float variable directly as an operand is
+     not useful.  */
+  if (TARGET_SPE
+      && (SPE_VECTOR_MODE (mode) || FLOAT_MODE_P (mode)))
+    return 0;
+
   if (GET_CODE (op) == SYMBOL_REF)
     sym_ref = op;
 
@@ -3564,6 +3616,7 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       && GET_CODE (XEXP (x, 1)) == CONST_INT
       && (unsigned HOST_WIDE_INT) (INTVAL (XEXP (x, 1)) + 0x8000) >= 0x10000
       && !(SPE_VECTOR_MODE (mode)
+          || ALTIVEC_VECTOR_MODE (mode)
           || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
                                      || mode == DImode))))
     {
@@ -3581,11 +3634,12 @@ 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 && mode != DDmode)
-                   || TARGET_E500_DOUBLE)
-                  && mode != TFmode && mode != TDmode))
+              || ((mode != DImode && mode != DFmode && mode != DDmode)
+                  || TARGET_E500_DOUBLE))
           && (TARGET_POWERPC64 || mode != DImode)
-          && mode != TImode)
+          && mode != TImode
+          && mode != TFmode
+          && mode != TDmode)
     {
       return gen_rtx_PLUS (Pmode, XEXP (x, 0),
                           force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
@@ -3612,19 +3666,29 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       /* We accept [reg + reg] and [reg + OFFSET].  */
 
       if (GET_CODE (x) == PLUS)
-       {
-         rtx op1 = XEXP (x, 0);
-         rtx op2 = XEXP (x, 1);
+       {
+         rtx op1 = XEXP (x, 0);
+         rtx op2 = XEXP (x, 1);
+         rtx y;
 
-         op1 = force_reg (Pmode, op1);
+         op1 = force_reg (Pmode, op1);
 
-         if (GET_CODE (op2) != REG
-             && (GET_CODE (op2) != CONST_INT
-                 || !SPE_CONST_OFFSET_OK (INTVAL (op2))))
-           op2 = force_reg (Pmode, op2);
+         if (GET_CODE (op2) != REG
+             && (GET_CODE (op2) != CONST_INT
+                 || !SPE_CONST_OFFSET_OK (INTVAL (op2))
+                 || (GET_MODE_SIZE (mode) > 8
+                     && !SPE_CONST_OFFSET_OK (INTVAL (op2) + 8))))
+           op2 = force_reg (Pmode, op2);
 
-         return gen_rtx_PLUS (Pmode, op1, op2);
-       }
+         /* We can't always do [reg + reg] for these, because [reg +
+            reg + offset] is not a legitimate addressing mode.  */
+         y = gen_rtx_PLUS (Pmode, op1, op2);
+
+         if (GET_MODE_SIZE (mode) > 8 && REG_P (op2))
+           return force_reg (Pmode, y);
+         else
+           return y;
+       }
 
       return force_reg (Pmode, x);
     }
@@ -6592,10 +6656,10 @@ rs6000_va_start (tree valist, rtx nextarg)
   sav = build3 (COMPONENT_REF, TREE_TYPE (f_sav), valist, f_sav, NULL_TREE);
 
   /* Count number of gp and fp argument registers used.  */
-  words = current_function_args_info.words;
-  n_gpr = MIN (current_function_args_info.sysv_gregno - GP_ARG_MIN_REG,
+  words = crtl->args.info.words;
+  n_gpr = MIN (crtl->args.info.sysv_gregno - GP_ARG_MIN_REG,
               GP_ARG_NUM_REG);
-  n_fpr = MIN (current_function_args_info.fregno - FP_ARG_MIN_REG,
+  n_fpr = MIN (crtl->args.info.fregno - FP_ARG_MIN_REG,
               FP_ARG_NUM_REG);
 
   if (TARGET_DEBUG_ARG)
@@ -6768,7 +6832,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       else if (reg == fpr && TYPE_MODE (type) == TDmode)
        {
          regalign = 1;
-         t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg, size_int (1));
+         t = build2 (BIT_IOR_EXPR, TREE_TYPE (reg), reg,
+                     build_int_cst (TREE_TYPE (reg), 1));
          u = build2 (MODIFY_EXPR, void_type_node, reg, t);
        }
 
@@ -6806,7 +6871,8 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
        {
          /* Ensure that we don't find any more args in regs.
             Alignment has taken care of for special cases.  */
-         t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (reg), reg, size_int (8));
+         t = build_gimple_modify_stmt (reg,
+                                       build_int_cst (TREE_TYPE (reg), 8));
          gimplify_and_add (t, pre_p);
        }
     }
@@ -7027,9 +7093,9 @@ static struct builtin_description bdesc_2arg[] =
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlb, "__builtin_altivec_vrlb", ALTIVEC_BUILTIN_VRLB },
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlh, "__builtin_altivec_vrlh", ALTIVEC_BUILTIN_VRLH },
   { MASK_ALTIVEC, CODE_FOR_altivec_vrlw, "__builtin_altivec_vrlw", ALTIVEC_BUILTIN_VRLW },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslb, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslh, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
-  { MASK_ALTIVEC, CODE_FOR_altivec_vslw, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
+  { MASK_ALTIVEC, CODE_FOR_ashlv16qi3, "__builtin_altivec_vslb", ALTIVEC_BUILTIN_VSLB },
+  { MASK_ALTIVEC, CODE_FOR_ashlv8hi3, "__builtin_altivec_vslh", ALTIVEC_BUILTIN_VSLH },
+  { MASK_ALTIVEC, CODE_FOR_ashlv4si3, "__builtin_altivec_vslw", ALTIVEC_BUILTIN_VSLW },
   { MASK_ALTIVEC, CODE_FOR_altivec_vsl, "__builtin_altivec_vsl", ALTIVEC_BUILTIN_VSL },
   { MASK_ALTIVEC, CODE_FOR_altivec_vslo, "__builtin_altivec_vslo", ALTIVEC_BUILTIN_VSLO },
   { MASK_ALTIVEC, CODE_FOR_altivec_vspltb, "__builtin_altivec_vspltb", ALTIVEC_BUILTIN_VSPLTB },
@@ -9159,6 +9225,10 @@ rs6000_init_builtins (void)
   if (built_in_decls [BUILT_IN_CLOG])
     set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
 #endif
+
+#ifdef SUBTARGET_INIT_BUILTINS
+  SUBTARGET_INIT_BUILTINS;
+#endif
 }
 
 /* Search through a set of builtins and enable the mask bits.
@@ -11156,6 +11226,9 @@ rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
       return NULL_TREE;
     }
 
+  gcc_assert (TREE_CODE (*tp) != ALIGN_INDIRECT_REF);
+  gcc_assert (TREE_CODE (*tp) != MISALIGNED_INDIRECT_REF);
+
   switch (TREE_CODE (*tp))
     {
     case VAR_DECL:
@@ -11163,6 +11236,8 @@ rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
     case FIELD_DECL:
     case RESULT_DECL:
     case REAL_CST:
+    case INDIRECT_REF:
+    case VIEW_CONVERT_EXPR:
       if (TYPE_MODE (TREE_TYPE (*tp)) == SDmode)
        return *tp;
       break;
@@ -13836,6 +13911,9 @@ rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
   emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
                                                    oldval, newval, mem));
 
+  /* Shift the result back.  */
+  emit_insn (gen_lshrsi3 (wdst, wdst, shift));
+
   emit_move_insn (dst, gen_lowpart (mode, wdst));
 }
 
@@ -14129,7 +14207,7 @@ compute_vrsave_mask (void)
      them in again.  More importantly, the mask we compute here is
      used to generate CLOBBERs in the set_vrsave insn, and we do not
      wish the argument registers to die.  */
-  for (i = cfun->args_info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
+  for (i = crtl->args.info.vregno - 1; i >= ALTIVEC_ARG_MIN_REG; --i)
     mask &= ~ALTIVEC_REG_BIT (i);
 
   /* Similarly, remove the return value from the set.  */
@@ -14379,7 +14457,6 @@ rs6000_stack_info (void)
 #endif
       || (info_ptr->first_fp_reg_save != 64
          && !FP_SAVE_INLINE (info_ptr->first_fp_reg_save))
-      || info_ptr->first_altivec_reg_save <= LAST_ALTIVEC_REGNO
       || (DEFAULT_ABI == ABI_V4 && current_function_calls_alloca)
       || info_ptr->calls_p
       || rs6000_ra_ever_killed ())
@@ -14419,7 +14496,7 @@ rs6000_stack_info (void)
   info_ptr->reg_size     = reg_size;
   info_ptr->fixed_size   = RS6000_SAVE_AREA;
   info_ptr->vars_size    = RS6000_ALIGN (get_frame_size (), 8);
-  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
+  info_ptr->parm_size    = RS6000_ALIGN (crtl->outgoing_args_size,
                                         TARGET_ALTIVEC ? 16 : 8);
   if (FRAME_GROWS_DOWNWARD)
     info_ptr->vars_size
@@ -15320,77 +15397,12 @@ rs6000_frame_related (rtx insn, rtx reg, HOST_WIDE_INT val,
          }
     }
 
-  if (TARGET_SPE)
-    real = spe_synthesize_frame_save (real);
-
   RTX_FRAME_RELATED_P (insn) = 1;
   REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
                                        real,
                                        REG_NOTES (insn));
 }
 
-/* Given an SPE frame note, return a PARALLEL of SETs with the
-   original note, plus a synthetic register save.  */
-
-static rtx
-spe_synthesize_frame_save (rtx real)
-{
-  rtx synth, offset, reg, real2;
-
-  if (GET_CODE (real) != SET
-      || GET_MODE (SET_SRC (real)) != V2SImode)
-    return real;
-
-  /* For the SPE, registers saved in 64-bits, get a PARALLEL for their
-     frame related note.  The parallel contains a set of the register
-     being saved, and another set to a synthetic register (n+1200).
-     This is so we can differentiate between 64-bit and 32-bit saves.
-     Words cannot describe this nastiness.  */
-
-  gcc_assert (GET_CODE (SET_DEST (real)) == MEM
-             && GET_CODE (XEXP (SET_DEST (real), 0)) == PLUS
-             && GET_CODE (SET_SRC (real)) == REG);
-
-  /* Transform:
-       (set (mem (plus (reg x) (const y)))
-            (reg z))
-     into:
-       (set (mem (plus (reg x) (const y+4)))
-            (reg z+1200))
-  */
-
-  real2 = copy_rtx (real);
-  PUT_MODE (SET_DEST (real2), SImode);
-  reg = SET_SRC (real2);
-  real2 = replace_rtx (real2, reg, gen_rtx_REG (SImode, REGNO (reg)));
-  synth = copy_rtx (real2);
-
-  if (BYTES_BIG_ENDIAN)
-    {
-      offset = XEXP (XEXP (SET_DEST (real2), 0), 1);
-      real2 = replace_rtx (real2, offset, GEN_INT (INTVAL (offset) + 4));
-    }
-
-  reg = SET_SRC (synth);
-
-  synth = replace_rtx (synth, reg,
-                      gen_rtx_REG (SImode, REGNO (reg) + 1200));
-
-  offset = XEXP (XEXP (SET_DEST (synth), 0), 1);
-  synth = replace_rtx (synth, offset,
-                      GEN_INT (INTVAL (offset)
-                               + (BYTES_BIG_ENDIAN ? 0 : 4)));
-
-  RTX_FRAME_RELATED_P (synth) = 1;
-  RTX_FRAME_RELATED_P (real2) = 1;
-  if (BYTES_BIG_ENDIAN)
-    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, synth, real2));
-  else
-    real = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, real2, synth));
-
-  return real;
-}
-
 /* Returns an insn that has a vrsave set operation with the
    appropriate CLOBBERs.  */
 
@@ -16826,7 +16838,7 @@ rs6000_output_function_epilogue (FILE *file,
       if (! strcmp (language_string, "GNU C"))
        i = 0;
       else if (! strcmp (language_string, "GNU F77")
-              || ! strcmp (language_string, "GNU F95"))
+              || ! strcmp (language_string, "GNU Fortran"))
        i = 1;
       else if (! strcmp (language_string, "GNU Pascal"))
        i = 2;
@@ -17119,6 +17131,7 @@ rs6000_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   final_start_function (insn, file, 1);
   final (insn, file, 1);
   final_end_function ();
+  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -18495,6 +18508,8 @@ rs6000_issue_rate (void)
   case CPU_PPC7400:
   case CPU_PPC8540:
   case CPU_CELL:
+  case CPU_PPCE300C2:
+  case CPU_PPCE300C3:
     return 2;
   case CPU_RIOS2:
   case CPU_PPC604: