hooks.c (hook_int_rtx_mode_as_bool_0): New function.
[platform/upstream/gcc.git] / gcc / config / rs6000 / rs6000.c
index ffb0023..430125f 100644 (file)
@@ -1,8 +1,5 @@
 /* Subroutines used for code generation on IBM RS/6000.
-   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
-   2012
-   Free Software Foundation, Inc.
+   Copyright (C) 1991-2012 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
    This file is part of GCC.
@@ -52,7 +49,6 @@
 #include "common/common-target.h"
 #include "langhooks.h"
 #include "reload.h"
-#include "cfglayout.h"
 #include "cfgloop.h"
 #include "sched-int.h"
 #include "gimple.h"
@@ -61,6 +57,7 @@
 #include "params.h"
 #include "tm-constrs.h"
 #include "opts.h"
+#include "tree-vectorizer.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
@@ -355,44 +352,6 @@ struct processor_costs size64_cost = {
   0,
 };
 
-/* Instruction costs on RIOS1 processors.  */
-static const
-struct processor_costs rios1_cost = {
-  COSTS_N_INSNS (5),    /* mulsi */
-  COSTS_N_INSNS (4),    /* mulsi_const */
-  COSTS_N_INSNS (3),    /* mulsi_const9 */
-  COSTS_N_INSNS (5),    /* muldi */
-  COSTS_N_INSNS (19),   /* divsi */
-  COSTS_N_INSNS (19),   /* divdi */
-  COSTS_N_INSNS (2),    /* fp */
-  COSTS_N_INSNS (2),    /* dmul */
-  COSTS_N_INSNS (19),   /* sdiv */
-  COSTS_N_INSNS (19),   /* ddiv */
-  128,                 /* cache line size */
-  64,                  /* l1 cache */
-  512,                 /* l2 cache */
-  0,                   /* streams */
-};
-
-/* Instruction costs on RIOS2 processors.  */
-static const
-struct processor_costs rios2_cost = {
-  COSTS_N_INSNS (2),    /* mulsi */
-  COSTS_N_INSNS (2),    /* mulsi_const */
-  COSTS_N_INSNS (2),    /* mulsi_const9 */
-  COSTS_N_INSNS (2),    /* muldi */
-  COSTS_N_INSNS (13),   /* divsi */
-  COSTS_N_INSNS (13),   /* divdi */
-  COSTS_N_INSNS (2),    /* fp */
-  COSTS_N_INSNS (2),    /* dmul */
-  COSTS_N_INSNS (17),   /* sdiv */
-  COSTS_N_INSNS (17),   /* ddiv */
-  256,                 /* cache line size */
-  256,                 /* l1 cache */
-  1024,                        /* l2 cache */
-  0,                   /* streams */
-};
-
 /* Instruction costs on RS64A processors.  */
 static const
 struct processor_costs rs64a_cost = {
@@ -969,7 +928,8 @@ static tree rs6000_builtin_vectorized_libmass (tree, tree, tree);
 static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT);
 static int rs6000_memory_move_cost (enum machine_mode, reg_class_t, bool);
 static bool rs6000_debug_rtx_costs (rtx, int, int, int, int *, bool);
-static int rs6000_debug_address_cost (rtx, bool);
+static int rs6000_debug_address_cost (rtx, enum machine_mode, addr_space_t,
+                                     bool);
 static int rs6000_debug_adjust_cost (rtx, rtx, rtx, int);
 static bool is_microcoded_insn (rtx);
 static bool is_nonpipeline_insn (rtx);
@@ -1274,10 +1234,6 @@ static const struct attribute_spec rs6000_attribute_table[] =
 
 #undef TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD
 #define TARGET_VECTORIZE_BUILTIN_MASK_FOR_LOAD rs6000_builtin_mask_for_load
-#undef TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN
-#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_SUPPORT_VECTOR_MISALIGNMENT
 #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT           \
   rs6000_builtin_support_vector_misalignment
@@ -1289,6 +1245,14 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
 #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE \
   rs6000_preferred_simd_mode
+#undef TARGET_VECTORIZE_INIT_COST
+#define TARGET_VECTORIZE_INIT_COST rs6000_init_cost
+#undef TARGET_VECTORIZE_ADD_STMT_COST
+#define TARGET_VECTORIZE_ADD_STMT_COST rs6000_add_stmt_cost
+#undef TARGET_VECTORIZE_FINISH_COST
+#define TARGET_VECTORIZE_FINISH_COST rs6000_finish_cost
+#undef TARGET_VECTORIZE_DESTROY_COST_DATA
+#define TARGET_VECTORIZE_DESTROY_COST_DATA rs6000_destroy_cost_data
 
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS rs6000_init_builtins
@@ -1331,7 +1295,7 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS rs6000_rtx_costs
 #undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
+#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
 
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN rs6000_dwarf_register_span
@@ -1339,6 +1303,9 @@ static const struct attribute_spec rs6000_attribute_table[] =
 #undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
 #define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
 
+#undef TARGET_MEMBER_TYPE_FORCES_BLK
+#define TARGET_MEMBER_TYPE_FORCES_BLK rs6000_member_type_forces_blk
+
 /* On rs6000, function arguments are promoted, as are function return
    values.  */
 #undef TARGET_PROMOTE_FUNCTION_MODE
@@ -1494,8 +1461,7 @@ static const struct attribute_spec rs6000_attribute_table[] =
 /* Simplifications for entries below.  */
 
 enum {
-  POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS,
-  POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC
+  POWERPC_7400_MASK = MASK_PPC_GFXOPT | MASK_ALTIVEC
 };
 
 /* Some OSs don't support saving the high part of 64-bit registers on context
@@ -1505,8 +1471,7 @@ enum {
    the user's specification.  */
 
 enum {
-  POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
-  POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN
+  POWERPC_MASKS = (MASK_PPC_GPOPT | MASK_STRICT_ALIGN
                   | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
                   | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
                   | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP
@@ -1789,7 +1754,6 @@ rs6000_debug_reg_global (void)
   rs6000_debug_reg_print (LR_REGNO, LR_REGNO, "lr");
   rs6000_debug_reg_print (CTR_REGNO, CTR_REGNO, "ctr");
   rs6000_debug_reg_print (CR0_REGNO, CR7_REGNO, "cr");
-  rs6000_debug_reg_print (MQ_REGNO, MQ_REGNO, "mq");
   rs6000_debug_reg_print (CA_REGNO, CA_REGNO, "ca");
   rs6000_debug_reg_print (VRSAVE_REGNO, VRSAVE_REGNO, "vrsave");
   rs6000_debug_reg_print (VSCR_REGNO, VSCR_REGNO, "vscr");
@@ -2012,7 +1976,6 @@ rs6000_init_hard_regno_mode_ok (bool global_init_p)
   for (r = CR1_REGNO; r <= CR7_REGNO; ++r)
     rs6000_regno_regclass[r] = CR_REGS;
 
-  rs6000_regno_regclass[MQ_REGNO] = MQ_REGS;
   rs6000_regno_regclass[LR_REGNO] = LINK_REGS;
   rs6000_regno_regclass[CTR_REGNO] = CTR_REGS;
   rs6000_regno_regclass[CA_REGNO] = CA_REGS;
@@ -2402,7 +2365,6 @@ rs6000_builtin_mask_calculate (void)
          | ((TARGET_FRSQRTE)               ? RS6000_BTM_FRSQRTE  : 0)
          | ((TARGET_FRSQRTES)              ? RS6000_BTM_FRSQRTES : 0)
          | ((TARGET_POPCNTD)               ? RS6000_BTM_POPCNTD  : 0)
-         | ((TARGET_POWERPC)               ? RS6000_BTM_POWERPC  : 0)
          | ((rs6000_cpu == PROCESSOR_CELL) ? RS6000_BTM_CELL     : 0));
 }
 
@@ -2455,7 +2417,7 @@ rs6000_option_override_internal (bool global_init_p)
       rs6000_pointer_size = 32;
     }
 
-  set_masks = POWER_MASKS | POWERPC_MASKS | MASK_SOFT_FLOAT;
+  set_masks = POWERPC_MASKS | MASK_SOFT_FLOAT;
 #ifdef OS_MISSING_POWERPC64
   if (OS_MISSING_POWERPC64)
     set_masks &= ~MASK_POWERPC64;
@@ -2998,14 +2960,6 @@ rs6000_option_override_internal (bool global_init_p)
   else
     switch (rs6000_cpu)
       {
-      case PROCESSOR_RIOS1:
-       rs6000_cost = &rios1_cost;
-       break;
-
-      case PROCESSOR_RIOS2:
-       rs6000_cost = &rios2_cost;
-       break;
-
       case PROCESSOR_RS64A:
        rs6000_cost = &rs64a_cost;
        break;
@@ -3286,53 +3240,6 @@ rs6000_loop_align_max_skip (rtx label)
   return (1 << rs6000_loop_align (label)) - 1;
 }
 
-/* Implement targetm.vectorize.builtin_mul_widen_even.  */
-static tree
-rs6000_builtin_mul_widen_even (tree type)
-{
-  if (!TARGET_ALTIVEC)
-    return NULL_TREE;
-
-  switch (TYPE_MODE (type))
-    {
-    case V8HImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULEUH_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULESH];
-
-    case V16QImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULEUB_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULESB];
-    default:
-      return NULL_TREE;
-    }
-}
-
-/* Implement targetm.vectorize.builtin_mul_widen_odd.  */
-static tree
-rs6000_builtin_mul_widen_odd (tree type)
-{
-  if (!TARGET_ALTIVEC)
-    return NULL_TREE;
-
-  switch (TYPE_MODE (type))
-    {
-    case V8HImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOUH_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOSH];
-
-    case V16QImode:
-      return TYPE_UNSIGNED (type)
-            ? rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOUB_UNS]
-            : rs6000_builtin_decls[ALTIVEC_BUILTIN_VMULOSB];
-    default:
-      return NULL_TREE;
-    }
-}
-
-
 /* 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.  */
@@ -3405,6 +3312,7 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
                                    tree vectype, int misalign)
 {
   unsigned elements;
+  tree elem_type;
 
   switch (type_of_cost)
     {
@@ -3421,13 +3329,13 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
 
       case vec_perm:
        if (TARGET_VSX)
-         return 4;
+         return 3;
        else
          return 1;
 
       case vec_promote_demote:
         if (TARGET_VSX)
-          return 5;
+          return 4;
         else
           return 1;
 
@@ -3504,6 +3412,18 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
 
         return 2;
 
+      case vec_construct:
+       elements = TYPE_VECTOR_SUBPARTS (vectype);
+       elem_type = TREE_TYPE (vectype);
+       /* 32-bit vectors loaded into registers are stored as double
+          precision, so we need n/2 converts in addition to the usual
+          n/2 merges to construct a vector of short floats from them.  */
+       if (SCALAR_FLOAT_TYPE_P (elem_type)
+           && TYPE_PRECISION (elem_type) == 32)
+         return elements + 1;
+       else
+         return elements / 2 + 1;
+
       default:
         gcc_unreachable ();
     }
@@ -3551,6 +3471,126 @@ rs6000_preferred_simd_mode (enum machine_mode mode)
   return word_mode;
 }
 
+typedef struct _rs6000_cost_data
+{
+  struct loop *loop_info;
+  unsigned cost[3];
+} rs6000_cost_data;
+
+/* Test for likely overcommitment of vector hardware resources.  If a
+   loop iteration is relatively large, and too large a percentage of
+   instructions in the loop are vectorized, the cost model may not
+   adequately reflect delays from unavailable vector resources.
+   Penalize the loop body cost for this case.  */
+
+static void
+rs6000_density_test (rs6000_cost_data *data)
+{
+  const int DENSITY_PCT_THRESHOLD = 85;
+  const int DENSITY_SIZE_THRESHOLD = 70;
+  const int DENSITY_PENALTY = 10;
+  struct loop *loop = data->loop_info;
+  basic_block *bbs = get_loop_body (loop);
+  int nbbs = loop->num_nodes;
+  int vec_cost = data->cost[vect_body], not_vec_cost = 0;
+  int i, density_pct;
+
+  for (i = 0; i < nbbs; i++)
+    {
+      basic_block bb = bbs[i];
+      gimple_stmt_iterator gsi;
+
+      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+       {
+         gimple stmt = gsi_stmt (gsi);
+         stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+
+         if (!STMT_VINFO_RELEVANT_P (stmt_info)
+             && !STMT_VINFO_IN_PATTERN_P (stmt_info))
+           not_vec_cost++;
+       }
+    }
+
+  free (bbs);
+  density_pct = (vec_cost * 100) / (vec_cost + not_vec_cost);
+
+  if (density_pct > DENSITY_PCT_THRESHOLD
+      && vec_cost + not_vec_cost > DENSITY_SIZE_THRESHOLD)
+    {
+      data->cost[vect_body] = vec_cost * (100 + DENSITY_PENALTY) / 100;
+      if (vect_print_dump_info (REPORT_DETAILS))
+       fprintf (vect_dump,
+                "density %d%%, cost %d exceeds threshold, penalizing "
+                "loop body cost by %d%%", density_pct, 
+                vec_cost + not_vec_cost, DENSITY_PENALTY);
+    }
+}
+
+/* Implement targetm.vectorize.init_cost.  */
+
+static void *
+rs6000_init_cost (struct loop *loop_info)
+{
+  rs6000_cost_data *data = XNEW (struct _rs6000_cost_data);
+  data->loop_info = loop_info;
+  data->cost[vect_prologue] = 0;
+  data->cost[vect_body]     = 0;
+  data->cost[vect_epilogue] = 0;
+  return data;
+}
+
+/* Implement targetm.vectorize.add_stmt_cost.  */
+
+static unsigned
+rs6000_add_stmt_cost (void *data, int count, enum vect_cost_for_stmt kind,
+                     struct _stmt_vec_info *stmt_info, int misalign,
+                     enum vect_cost_model_location where)
+{
+  rs6000_cost_data *cost_data = (rs6000_cost_data*) data;
+  unsigned retval = 0;
+
+  if (flag_vect_cost_model)
+    {
+      tree vectype = stmt_info ? stmt_vectype (stmt_info) : NULL_TREE;
+      int stmt_cost = rs6000_builtin_vectorization_cost (kind, vectype,
+                                                        misalign);
+      /* Statements in an inner loop relative to the loop being
+        vectorized are weighted more heavily.  The value here is
+        arbitrary and could potentially be improved with analysis.  */
+      if (where == vect_body && stmt_info && stmt_in_inner_loop_p (stmt_info))
+       count *= 50;  /* FIXME.  */
+
+      retval = (unsigned) (count * stmt_cost);
+      cost_data->cost[where] += retval;
+    }
+
+  return retval;
+}
+
+/* Implement targetm.vectorize.finish_cost.  */
+
+static void
+rs6000_finish_cost (void *data, unsigned *prologue_cost,
+                   unsigned *body_cost, unsigned *epilogue_cost)
+{
+  rs6000_cost_data *cost_data = (rs6000_cost_data*) data;
+
+  if (cost_data->loop_info)
+    rs6000_density_test (cost_data);
+
+  *prologue_cost = cost_data->cost[vect_prologue];
+  *body_cost     = cost_data->cost[vect_body];
+  *epilogue_cost = cost_data->cost[vect_epilogue];
+}
+
+/* Implement targetm.vectorize.destroy_cost_data.  */
+
+static void
+rs6000_destroy_cost_data (void *data)
+{
+  free (data);
+}
+
 /* Handler for the Mathematical Acceleration Subsystem (mass) interface to a
    library with vectorized intrinsics.  */
 
@@ -3987,11 +4027,11 @@ direct_return (void)
 int
 num_insns_constant_wide (HOST_WIDE_INT value)
 {
-  /* signed constant loadable with {cal|addi} */
+  /* signed constant loadable with addi */
   if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
     return 1;
 
-  /* constant loadable with {cau|addis} */
+  /* constant loadable with addis */
   else if ((value & 0xffff) == 0
           && (value >> 31 == -1 || value >> 31 == 0))
     return 1;
@@ -4995,6 +5035,78 @@ gpr_or_gpr_p (rtx op0, rtx op1)
          || (REG_P (op1) && INT_REGNO_P (REGNO (op1))));
 }
 
+/* Given an address, return a constant offset term if one exists.  */
+
+static rtx
+address_offset (rtx op)
+{
+  if (GET_CODE (op) == PRE_INC
+      || GET_CODE (op) == PRE_DEC)
+    op = XEXP (op, 0);
+  else if (GET_CODE (op) == PRE_MODIFY
+          || GET_CODE (op) == LO_SUM)
+    op = XEXP (op, 1);
+
+  if (GET_CODE (op) == CONST)
+    op = XEXP (op, 0);
+
+  if (GET_CODE (op) == PLUS)
+    op = XEXP (op, 1);
+
+  if (CONST_INT_P (op))
+    return op;
+
+  return NULL_RTX;
+}
+
+/* Return true if the MEM operand is a memory operand suitable for use
+   with a (full width, possibly multiple) gpr load/store.  On
+   powerpc64 this means the offset must be divisible by 4.
+   Implements 'Y' constraint.
+
+   Accept direct, indexed, offset, lo_sum and tocref.  Since this is
+   a constraint function we know the operand has satisfied a suitable
+   memory predicate.  Also accept some odd rtl generated by reload
+   (see rs6000_legitimize_reload_address for various forms).  It is
+   important that reload rtl be accepted by appropriate constraints
+   but not by the operand predicate.
+
+   Offsetting a lo_sum should not be allowed, except where we know by
+   alignment that a 32k boundary is not crossed, but see the ???
+   comment in rs6000_legitimize_reload_address.  Note that by
+   "offsetting" here we mean a further offset to access parts of the
+   MEM.  It's fine to have a lo_sum where the inner address is offset
+   from a sym, since the same sym+offset will appear in the high part
+   of the address calculation.  */
+
+bool
+mem_operand_gpr (rtx op, enum machine_mode mode)
+{
+  unsigned HOST_WIDE_INT offset;
+  int extra;
+  rtx addr = XEXP (op, 0);
+
+  op = address_offset (addr);
+  if (op == NULL_RTX)
+    return true;
+
+  offset = INTVAL (op);
+  if (TARGET_POWERPC64 && (offset & 3) != 0)
+    return false;
+
+  if (GET_CODE (addr) == LO_SUM)
+    /* We know by alignment that ABI_AIX medium/large model toc refs
+       will not cross a 32k boundary, since all entries in the
+       constant pool are naturally aligned and we check alignment for
+       other medium model toc-relative addresses.  For ABI_V4 and
+       ABI_DARWIN lo_sum addresses, we just check that 64-bit
+       offsets are 4-byte aligned.  */
+    return true;
+
+  extra = GET_MODE_SIZE (mode) - UNITS_PER_WORD;
+  gcc_assert (extra >= 0);
+  return offset + 0x8000 < 0x10000u - extra;
+}
 \f
 /* Subroutines of rs6000_legitimize_address and rs6000_legitimate_address_p.  */
 
@@ -5212,13 +5324,15 @@ legitimate_small_data_p (enum machine_mode mode, rtx x)
 #define SPE_CONST_OFFSET_OK(x) (((x) & ~0xf8) == 0)
 
 bool
-rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
+rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x,
+                                   bool strict, bool worst_case)
 {
-  unsigned HOST_WIDE_INT offset, extra;
+  unsigned HOST_WIDE_INT offset;
+  unsigned int extra;
 
   if (GET_CODE (x) != PLUS)
     return false;
-  if (GET_CODE (XEXP (x, 0)) != REG)
+  if (!REG_P (XEXP (x, 0)))
     return false;
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
@@ -5241,14 +5355,6 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
       return SPE_CONST_OFFSET_OK (offset);
 
     case DFmode:
-      if (TARGET_E500_DOUBLE)
-       return SPE_CONST_OFFSET_OK (offset);
-
-      /* If we are using VSX scalar loads, restrict ourselves to reg+reg
-        addressing.  */
-      if (VECTOR_MEM_VSX_P (DFmode))
-       return false;
-
     case DDmode:
     case DImode:
       /* On e500v2, we may have:
@@ -5259,25 +5365,33 @@ 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 || mode == DDmode || !TARGET_POWERPC64)
+      /* If we are using VSX scalar loads, restrict ourselves to reg+reg
+        addressing.  */
+      if (mode == DFmode && VECTOR_MEM_VSX_P (DFmode))
+       return false;
+
+      if (!worst_case)
+       break;
+      if (!TARGET_POWERPC64)
        extra = 4;
       else if (offset & 3)
        return false;
       break;
 
     case TFmode:
+    case TDmode:
+    case TImode:
       if (TARGET_E500_DOUBLE)
        return (SPE_CONST_OFFSET_OK (offset)
                && SPE_CONST_OFFSET_OK (offset + 8));
 
-    case TDmode:
-    case TImode:
-      if (mode == TFmode || mode == TDmode || !TARGET_POWERPC64)
+      extra = 8;
+      if (!worst_case)
+       break;
+      if (!TARGET_POWERPC64)
        extra = 12;
       else if (offset & 3)
        return false;
-      else
-       extra = 8;
       break;
 
     default:
@@ -5357,9 +5471,7 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
   if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
     return false;
   /* Restrict addressing for DI because of our SUBREG hackery.  */
-  if (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                            || mode == DDmode || mode == TDmode
-                            || mode == DImode))
+  if (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)
     return false;
   x = XEXP (x, 1);
 
@@ -5371,10 +5483,10 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
        return false;
       if (GET_MODE_NUNITS (mode) != 1)
        return false;
-      if (GET_MODE_BITSIZE (mode) > 64
-         || (GET_MODE_BITSIZE (mode) > 32 && !TARGET_POWERPC64
-             && !(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
-                  && (mode == DFmode || mode == DDmode))))
+      if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+         && !(/* ??? Assume floating point reg based on mode?  */
+              TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+              && (mode == DFmode || mode == DDmode)))
        return false;
 
       return CONSTANT_P (x);
@@ -5409,7 +5521,7 @@ static rtx
 rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
                           enum machine_mode mode)
 {
-  unsigned int extra = 0;
+  unsigned int extra;
 
   if (!reg_offset_addressing_ok_p (mode))
     {
@@ -5436,22 +5548,18 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
        return rs6000_legitimize_tls_address (x, model);
     }
 
+  extra = 0;
   switch (mode)
     {
-    case DFmode:
-    case DDmode:
-      extra = 4;
-      break;
-    case DImode:
-      if (!TARGET_POWERPC64)
-       extra = 4;
-      break;
     case TFmode:
     case TDmode:
-      extra = 12;
-      break;
     case TImode:
-      extra = TARGET_POWERPC64 ? 8 : 12;
+      /* As in legitimate_offset_address_p we do not assume
+        worst-case.  The mode here is just a hint as to the registers
+        used.  A TImode is usually in gprs, but may actually be in
+        fprs.  Leave worst-case scenario for reload to handle via
+        insn constraints.  */
+      extra = 8;
       break;
     default:
       break;
@@ -5462,13 +5570,8 @@ 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 - extra)
-      && !((TARGET_POWERPC64
-           && (mode == DImode || mode == TImode)
-           && (INTVAL (XEXP (x, 1)) & 3) != 0)
-          || SPE_VECTOR_MODE (mode)
-          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                                     || mode == DImode || mode == DDmode
-                                     || mode == TDmode))))
+      && !(SPE_VECTOR_MODE (mode)
+          || (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD)))
     {
       HOST_WIDE_INT high_int, low_int;
       rtx sum;
@@ -5484,23 +5587,17 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_CODE (XEXP (x, 0)) == REG
           && GET_CODE (XEXP (x, 1)) != CONST_INT
           && GET_MODE_NUNITS (mode) == 1
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
-              || TARGET_POWERPC64
-              || ((mode != DImode && mode != DFmode && mode != DDmode)
-                  || (TARGET_E500_DOUBLE && mode != DDmode)))
-          && (TARGET_POWERPC64 || mode != DImode)
-          && !avoiding_indexed_address_p (mode)
-          && mode != TImode
-          && mode != TFmode
-          && mode != TDmode)
+          && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+              || (/* ??? Assume floating point reg based on mode?  */
+                  (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
+                  && (mode == DFmode || mode == DDmode)))
+          && !avoiding_indexed_address_p (mode))
     {
       return gen_rtx_PLUS (Pmode, XEXP (x, 0),
                           force_reg (Pmode, force_operand (XEXP (x, 1), 0)));
     }
   else if (SPE_VECTOR_MODE (mode)
-          || (TARGET_E500_DOUBLE && (mode == DFmode || mode == TFmode
-                                     || mode == DDmode || mode == TDmode
-                                     || mode == DImode)))
+          || (TARGET_E500_DOUBLE && GET_MODE_SIZE (mode) > UNITS_PER_WORD))
     {
       if (mode == DImode)
        return x;
@@ -5533,7 +5630,11 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 
       return force_reg (Pmode, x);
     }
-  else if (TARGET_ELF
+  else if ((TARGET_ELF
+#if TARGET_MACHO
+           || !MACHO_DYNAMIC_NO_PIC_P
+#endif
+           )
           && TARGET_32BIT
           && TARGET_NO_TOC
           && ! flag_pic
@@ -5541,30 +5642,16 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
           && GET_CODE (x) != CONST_DOUBLE
           && CONSTANT_P (x)
           && GET_MODE_NUNITS (mode) == 1
-          && (GET_MODE_BITSIZE (mode) <= 32
-              || ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
+          && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD
+              || (/* ??? Assume floating point reg based on mode?  */
+                  (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
                   && (mode == DFmode || mode == DDmode))))
     {
       rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_elf_high (reg, x));
-      return gen_rtx_LO_SUM (Pmode, reg, x);
-    }
-  else if (TARGET_MACHO && TARGET_32BIT && TARGET_NO_TOC
-          && ! flag_pic
-#if TARGET_MACHO
-          && ! MACHO_DYNAMIC_NO_PIC_P
-#endif
-          && GET_CODE (x) != CONST_INT
-          && GET_CODE (x) != CONST_DOUBLE
-          && CONSTANT_P (x)
-          && GET_MODE_NUNITS (mode) == 1
-          && ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT)
-              || (mode != DFmode && mode != DDmode))
-          && mode != DImode
-          && mode != TImode)
-    {
-      rtx reg = gen_reg_rtx (Pmode);
-      emit_insn (gen_macho_high (reg, x));
+      if (TARGET_ELF)
+       emit_insn (gen_elf_high (reg, x));
+      else
+       emit_insn (gen_macho_high (reg, x));
       return gen_rtx_LO_SUM (Pmode, reg, x);
     }
   else if (TARGET_TOC
@@ -6155,7 +6242,18 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
 #endif
       /* 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 and DDmode
-        without fprs.  */
+        without fprs.
+        ??? Assume floating point reg based on mode?  This assumption is
+        violated by eg. powerpc-linux -m32 compile of gcc.dg/pr28796-2.c
+        where reload ends up doing a DFmode load of a constant from
+        mem using two gprs.  Unfortunately, at this point reload
+        hasn't yet selected regs so poking around in reload data
+        won't help and even if we could figure out the regs reliably,
+        we'd still want to allow this transformation when the mem is
+        naturally aligned.  Since we say the address is good here, we
+        can't disable offsets from LO_SUMs in mem_operand_gpr.
+        FIXME: Allow offset from lo_sum for other modes too, when
+        mem is sufficiently aligned.  */
       && mode != TFmode
       && mode != TDmode
       && (mode != DImode || TARGET_POWERPC64)
@@ -6305,7 +6403,7 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
          || XEXP (x, 0) == arg_pointer_rtx)
       && GET_CODE (XEXP (x, 1)) == CONST_INT)
     return 1;
-  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict))
+  if (rs6000_legitimate_offset_address_p (mode, x, reg_ok_strict, false))
     return 1;
   if (mode != TImode
       && mode != TFmode
@@ -6333,7 +6431,8 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict)
           && (mode == DFmode || mode == DDmode || 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)
+      && (rs6000_legitimate_offset_address_p (mode, XEXP (x, 1),
+                                             reg_ok_strict, false)
          || (!avoiding_indexed_address_p (mode)
              && legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict)))
       && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
@@ -6397,7 +6496,7 @@ rs6000_mode_dependent_address (const_rtx addr)
          && GET_CODE (XEXP (addr, 1)) == CONST_INT)
        {
          unsigned HOST_WIDE_INT val = INTVAL (XEXP (addr, 1));
-         return val + 12 + 0x8000 >= 0x10000;
+         return val + 0x8000 >= 0x10000 - (TARGET_POWERPC64 ? 8 : 12);
        }
       break;
 
@@ -6467,14 +6566,16 @@ rs6000_find_base_term (rtx op)
 
    in 32-bit mode, that the recog predicate rejects.  */
 
-bool
-rs6000_offsettable_memref_p (rtx op)
+static bool
+rs6000_offsettable_memref_p (rtx op, enum machine_mode reg_mode)
 {
+  bool worst_case;
+
   if (!MEM_P (op))
     return false;
 
   /* First mimic offsettable_memref_p.  */
-  if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
+  if (offsettable_address_p (true, GET_MODE (op), XEXP (op, 0)))
     return true;
 
   /* offsettable_address_p invokes rs6000_mode_dependent_address, but
@@ -6482,8 +6583,13 @@ rs6000_offsettable_memref_p (rtx op)
      reference and, therefore, assumes that it is the largest supported
      mode (TFmode).  As a consequence, legitimate offsettable memory
      references are rejected.  rs6000_legitimate_offset_address_p contains
-     the correct logic for the PLUS case of rs6000_mode_dependent_address.  */
-  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0), 1);
+     the correct logic for the PLUS case of rs6000_mode_dependent_address,
+     at least with a little bit of help here given that we know the
+     actual registers used.  */
+  worst_case = ((TARGET_POWERPC64 && GET_MODE_CLASS (reg_mode) == MODE_INT)
+               || GET_MODE_SIZE (reg_mode) == 4);
+  return rs6000_legitimate_offset_address_p (GET_MODE (op), XEXP (op, 0),
+                                            true, worst_case);
 }
 
 /* Change register usage conditional on target flags.  */
@@ -6495,11 +6601,9 @@ rs6000_conditional_register_usage (void)
   if (TARGET_DEBUG_TARGET)
     fprintf (stderr, "rs6000_conditional_register_usage called\n");
 
-  /* Set MQ register fixed (already call_used) if not POWER
-     architecture (RIOS1, RIOS2, RSC, and PPC601) so that it will not
-     be allocated.  */
-  if (! TARGET_POWER)
-    fixed_regs[64] = 1;
+  /* Set MQ register fixed (already call_used) so that it will not be
+     allocated.  */
+  fixed_regs[64] = 1;
 
   /* 64-bit AIX and Linux reserve GPR13 for thread-private data.  */
   if (TARGET_64BIT)
@@ -6852,32 +6956,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
       && !gpc_reg_operand (operands[1], mode))
     operands[1] = force_reg (mode, operands[1]);
 
-  if (mode == SFmode && ! TARGET_POWERPC
-      && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT 
-      && GET_CODE (operands[0]) == MEM)
-    {
-      int regnum;
-
-      if (reload_in_progress || reload_completed)
-       regnum = true_regnum (operands[1]);
-      else if (GET_CODE (operands[1]) == REG)
-       regnum = REGNO (operands[1]);
-      else
-       regnum = -1;
-
-      /* If operands[1] is a register, on POWER it may have
-        double-precision data in it, so truncate it to single
-        precision.  */
-      if (FP_REGNO_P (regnum) || regnum >= FIRST_PSEUDO_REGISTER)
-       {
-         rtx newreg;
-         newreg = (!can_create_pseudo_p () ? copy_rtx (operands[1])
-                   : gen_reg_rtx (mode));
-         emit_insn (gen_aux_truncdfsf2 (newreg, operands[1]));
-         operands[1] = newreg;
-       }
-    }
-
   /* Recognize the case where operand[1] is a reference to thread-local
      data and load its address to a register.  */
   if (rs6000_tls_referenced_p (operands[1]))
@@ -7171,17 +7249,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 
     case TImode:
       rs6000_eliminate_indexed_memrefs (operands);
-
-      if (TARGET_POWER)
-       {
-         emit_insn (gen_rtx_PARALLEL (VOIDmode,
-                      gen_rtvec (2,
-                                 gen_rtx_SET (VOIDmode,
-                                              operands[0], operands[1]),
-                                 gen_rtx_CLOBBER (VOIDmode,
-                                                  gen_rtx_SCRATCH (SImode)))));
-         return;
-       }
       break;
 
     default:
@@ -7197,6 +7264,26 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
  emit_set:
   emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[1]));
 }
+
+/* Return true if a structure, union or array containing FIELD should be
+   accessed using `BLKMODE'.
+
+   For the SPE, simd types are V2SI, and gcc can be tempted to put the
+   entire thing in a DI and use subregs to access the internals.
+   store_bit_field() will force (subreg:DI (reg:V2SI x))'s to the
+   back-end.  Because a single GPR can hold a V2SI, but not a DI, the
+   best thing to do is set structs to BLKmode and avoid Severe Tire
+   Damage.
+
+   On e500 v2, DF and DI modes suffer from the same anomaly.  DF can
+   fit into 1, whereas DI still needs two.  */
+
+static bool
+rs6000_member_type_forces_blk (const_tree field, enum machine_mode mode)
+{
+  return ((TARGET_SPE && TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+         || (TARGET_E500_DOUBLE && mode == DFmode));
+}
 \f
 /* Nonzero if we can use a floating-point register to pass this arg.  */
 #define USE_FP_FOR_ARG_P(CUM,MODE,TYPE)                \
@@ -12595,16 +12682,6 @@ rs6000_common_init_builtins (void)
 static void
 rs6000_init_libfuncs (void)
 {
-  if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
-      && !TARGET_POWER2 && !TARGET_POWERPC)
-    {
-      /* AIX library routines for float->int conversion.  */
-      set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
-      set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
-      set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
-      set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
-    }
-
   if (!TARGET_IEEEQUAD)
       /* AIX/Darwin/64-bit Linux quad floating point routines.  */
     if (!TARGET_XL_COMPAT)
@@ -12653,7 +12730,7 @@ rs6000_init_libfuncs (void)
       set_optab_libfunc (neg_optab, TFmode, "_q_neg");
       set_optab_libfunc (smul_optab, TFmode, "_q_mul");
       set_optab_libfunc (sdiv_optab, TFmode, "_q_div");
-      if (TARGET_PPC_GPOPT || TARGET_POWER2)
+      if (TARGET_PPC_GPOPT)
        set_optab_libfunc (sqrt_optab, TFmode, "_q_sqrt");
 
       set_optab_libfunc (eq_optab, TFmode, "_q_feq");
@@ -12974,7 +13051,7 @@ rs6000_output_load_multiple (rtx operands[3])
   rtx xop[10];
 
   if (XVECLEN (operands[0], 0) == 1)
-    return "{l|lwz} %2,0(%1)";
+    return "lwz %2,0(%1)";
 
   for (i = 0; i < words; i++)
     if (refers_to_regno_p (REGNO (operands[2]) + i,
@@ -12985,7 +13062,7 @@ rs6000_output_load_multiple (rtx operands[3])
            xop[0] = GEN_INT (4 * (words-1));
            xop[1] = operands[1];
            xop[2] = operands[2];
-           output_asm_insn ("{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,%0(%1)", xop);
+           output_asm_insn ("lswi %2,%1,%0\n\tlwz %1,%0(%1)", xop);
            return "";
          }
        else if (i == 0)
@@ -12993,7 +13070,7 @@ rs6000_output_load_multiple (rtx operands[3])
            xop[0] = GEN_INT (4 * (words-1));
            xop[1] = operands[1];
            xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
-           output_asm_insn ("{cal %1,4(%1)|addi %1,%1,4}\n\t{lsi|lswi} %2,%1,%0\n\t{l|lwz} %1,-4(%1)", xop);
+           output_asm_insn ("addi %1,%1,4\n\tlswi %2,%1,%0\n\tlwz %1,-4(%1)", xop);
            return "";
          }
        else
@@ -13004,16 +13081,16 @@ rs6000_output_load_multiple (rtx operands[3])
                  xop[0] = GEN_INT (j * 4);
                  xop[1] = operands[1];
                  xop[2] = gen_rtx_REG (SImode, REGNO (operands[2]) + j);
-                 output_asm_insn ("{l|lwz} %2,%0(%1)", xop);
+                 output_asm_insn ("lwz %2,%0(%1)", xop);
                }
            xop[0] = GEN_INT (i * 4);
            xop[1] = operands[1];
-           output_asm_insn ("{l|lwz} %1,%0(%1)", xop);
+           output_asm_insn ("lwz %1,%0(%1)", xop);
            return "";
          }
       }
 
-  return "{lsi|lswi} %2,%1,%N0";
+  return "lswi %2,%1,%N0";
 }
 
 \f
@@ -13494,7 +13571,8 @@ rs6000_secondary_reload (bool in_p,
          if (rclass == GENERAL_REGS || rclass == BASE_REGS)
            {
              if (!legitimate_indirect_address_p (addr, false)
-                 && !rs6000_legitimate_offset_address_p (TImode, addr, false))
+                 && !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                         false, true))
                {
                  sri->icode = icode;
                  /* account for splitting the loads, and converting the
@@ -13567,18 +13645,12 @@ rs6000_secondary_reload (bool in_p,
           && MEM_P (x)
           && GET_MODE_SIZE (GET_MODE (x)) >= UNITS_PER_WORD)
     {
-      rtx addr = XEXP (x, 0);
-
-      if (GET_CODE (addr) == PRE_MODIFY)
-       addr = XEXP (addr, 1);
-      else if (GET_CODE (addr) == LO_SUM
-              && GET_CODE (XEXP (addr, 0)) == REG
-              && GET_CODE (XEXP (addr, 1)) == CONST)
-       addr = XEXP (XEXP (addr, 1), 0);
+      rtx off = address_offset (XEXP (x, 0));
+      unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
 
-      if (GET_CODE (addr) == PLUS
-         && GET_CODE (XEXP (addr, 1)) == CONST_INT
-         && (INTVAL (XEXP (addr, 1)) & 3) != 0)
+      if (off != NULL_RTX
+         && (INTVAL (off) & 3) != 0
+         && (unsigned HOST_WIDE_INT) INTVAL (off) + 0x8000 < 0x10000 - extra)
        {
          if (in_p)
            sri->icode = CODE_FOR_reload_di_load;
@@ -13590,6 +13662,34 @@ rs6000_secondary_reload (bool in_p,
       else
        default_p = true;
     }
+  else if (!TARGET_POWERPC64
+          && rs6000_reload_register_type (rclass) == GPR_REGISTER_TYPE
+          && MEM_P (x)
+          && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+    {
+      rtx off = address_offset (XEXP (x, 0));
+      unsigned int extra = GET_MODE_SIZE (GET_MODE (x)) - UNITS_PER_WORD;
+
+      /* We need a secondary reload only when our legitimate_address_p
+        says the address is good (as otherwise the entire address
+        will be reloaded).  So for mode sizes of 8 and 16 this will
+        be when the offset is in the ranges [0x7ffc,0x7fff] and
+        [0x7ff4,0x7ff7] respectively.  Note that the address we see
+        here may have been manipulated by legitimize_reload_address.  */
+      if (off != NULL_RTX
+         && ((unsigned HOST_WIDE_INT) INTVAL (off) - (0x8000 - extra)
+             < UNITS_PER_WORD))
+       {
+         if (in_p)
+           sri->icode = CODE_FOR_reload_si_load;
+         else
+           sri->icode = CODE_FOR_reload_si_store;
+         sri->extra_cost = 2;
+         ret = NO_REGS;
+       }
+      else
+       default_p = true;
+    }
   else
     default_p = true;
 
@@ -13678,8 +13778,9 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
        }
 
       if (GET_CODE (addr) == PLUS
-         && (!rs6000_legitimate_offset_address_p (TImode, addr, false)
-             || and_op2 != NULL_RTX))
+         && (and_op2 != NULL_RTX
+             || !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                     false, true)))
        {
          addr_op1 = XEXP (addr, 0);
          addr_op2 = XEXP (addr, 1);
@@ -13711,7 +13812,8 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
          scratch_or_premodify = scratch;
        }
       else if (!legitimate_indirect_address_p (addr, false)
-              && !rs6000_legitimate_offset_address_p (TImode, addr, false))
+              && !rs6000_legitimate_offset_address_p (TImode, addr,
+                                                      false, true))
        {
          if (TARGET_DEBUG_ADDR)
            {
@@ -13770,7 +13872,7 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
              && GET_MODE_SIZE (mode) == 8
              && and_op2 == NULL_RTX
              && scratch_or_premodify == scratch
-             && rs6000_legitimate_offset_address_p (mode, addr, false)))
+             && rs6000_legitimate_offset_address_p (mode, addr, false, false)))
        ;
 
       else if (GET_CODE (addr) == PLUS)
@@ -13879,10 +13981,11 @@ rs6000_secondary_reload_inner (rtx reg, rtx mem, rtx scratch, bool store_p)
 }
 
 /* Convert reloads involving 64-bit gprs and misaligned offset
-   addressing to use indirect addressing.  */
+   addressing, or multiple 32-bit gprs and offsets that are too large,
+   to use indirect addressing.  */
 
 void
-rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
+rs6000_secondary_reload_gpr (rtx reg, rtx mem, rtx scratch, bool store_p)
 {
   int regno = true_regnum (reg);
   enum reg_class rclass;
@@ -13891,7 +13994,7 @@ rs6000_secondary_reload_ppc64 (rtx reg, rtx mem, rtx scratch, bool store_p)
 
   if (TARGET_DEBUG_ADDR)
     {
-      fprintf (stderr, "\nrs6000_secondary_reload_ppc64, type = %s\n",
+      fprintf (stderr, "\nrs6000_secondary_reload_gpr, type = %s\n",
               store_p ? "store" : "load");
       fprintf (stderr, "reg:\n");
       debug_rtx (reg);
@@ -14878,7 +14981,7 @@ print_operand (FILE *file, rtx x, int code)
                                  && REGNO (x) != CTR_REGNO))
        output_operand_lossage ("invalid %%T value");
       else if (REGNO (x) == LR_REGNO)
-       fputs (TARGET_NEW_MNEMONICS ? "lr" : "r", file);
+       fputs ("lr", file);
       else
        fputs ("ctr", file);
       return;
@@ -15419,6 +15522,16 @@ rs6000_generate_compare (rtx cmp, enum machine_mode mode)
   else
     comp_mode = CCmode;
 
+  /* If we have an unsigned compare, make sure we don't have a signed value as
+     an immediate.  */
+  if (comp_mode == CCUNSmode && GET_CODE (op1) == CONST_INT
+      && INTVAL (op1) < 0)
+    {
+      op0 = copy_rtx_if_shared (op0);
+      op1 = force_reg (GET_MODE (op0), op1);
+      cmp = gen_rtx_fmt_ee (code, GET_MODE (cmp), op0, op1);
+    }
+
   /* First, the compare.  */
   compare_result = gen_reg_rtx (comp_mode);
 
@@ -15833,8 +15946,7 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
       gcc_unreachable ();
     }
 
-  /* Maybe we have a guess as to how likely the branch is.
-     The old mnemonics don't have a way to specify this information.  */
+  /* Maybe we have a guess as to how likely the branch is.  */
   pred = "";
   note = find_reg_note (insn, REG_BR_PROB, NULL_RTX);
   if (note != NULL_RTX)
@@ -15861,9 +15973,9 @@ output_cbranch (rtx op, const char *label, int reversed, rtx insn)
     }
 
   if (label == NULL)
-    s += sprintf (s, "{b%sr|b%slr%s} ", ccode, ccode, pred);
+    s += sprintf (s, "b%slr%s ", ccode, pred);
   else
-    s += sprintf (s, "{b%s|b%s%s} ", ccode, ccode, pred);
+    s += sprintf (s, "b%s%s ", ccode, pred);
 
   /* We need to escape any '%' characters in the reg_names string.
      Assume they'd only be the first character....  */
@@ -16172,6 +16284,11 @@ rs6000_emit_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
   if (GET_MODE (false_cond) != result_mode)
     return 0;
 
+  /* Don't allow using floating point comparisons for integer results for
+     now.  */
+  if (FLOAT_MODE_P (compare_mode) && !FLOAT_MODE_P (result_mode))
+    return 0;
+
   /* First, work out if the hardware can do this at all, or
      if it's too slow....  */
   if (!FLOAT_MODE_P (compare_mode))
@@ -16500,9 +16617,19 @@ emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
 
 /* Expand barriers before and after a load_locked/store_cond sequence.  */
 
-static void
-rs6000_pre_atomic_barrier (enum memmodel model)
+static rtx
+rs6000_pre_atomic_barrier (rtx mem, enum memmodel model)
 {
+  rtx addr = XEXP (mem, 0);
+  int strict_p = (reload_in_progress || reload_completed);
+
+  if (!legitimate_indirect_address_p (addr, strict_p)
+      && !legitimate_indexed_address_p (addr, strict_p))
+    {
+      addr = force_reg (Pmode, addr);
+      mem = replace_equiv_address_nv (mem, addr);
+    }
+
   switch (model)
     {
     case MEMMODEL_RELAXED:
@@ -16519,6 +16646,7 @@ rs6000_pre_atomic_barrier (enum memmodel model)
     default:
       gcc_unreachable ();
     }
+  return mem;
 }
 
 static void
@@ -16657,7 +16785,7 @@ rs6000_expand_atomic_compare_and_swap (rtx operands[])
   else if (reg_overlap_mentioned_p (retval, oldval))
     oldval = copy_to_reg (oldval);
 
-  rs6000_pre_atomic_barrier (mod_s);
+  mem = rs6000_pre_atomic_barrier (mem, mod_s);
 
   label1 = NULL_RTX;
   if (!is_weak)
@@ -16742,7 +16870,7 @@ rs6000_expand_atomic_exchange (rtx operands[])
       mode = SImode;
     }
 
-  rs6000_pre_atomic_barrier (model);
+  mem = rs6000_pre_atomic_barrier (mem, model);
 
   label = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
   emit_label (XEXP (label, 0));
@@ -16826,7 +16954,7 @@ rs6000_expand_atomic_op (enum rtx_code code, rtx mem, rtx val,
       mode = SImode;
     }
 
-  rs6000_pre_atomic_barrier (model);
+  mem = rs6000_pre_atomic_barrier (mem, model);
 
   label = gen_label_rtx ();
   emit_label (label);
@@ -16945,7 +17073,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              emit_insn (gen_add3_insn (breg, breg, delta_rtx));
              src = replace_equiv_address (src, breg);
            }
-         else if (! rs6000_offsettable_memref_p (src))
+         else if (! rs6000_offsettable_memref_p (src, reg_mode))
            {
              if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY)
                {
@@ -17011,7 +17139,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                emit_insn (gen_add3_insn (breg, breg, delta_rtx));
              dst = replace_equiv_address (dst, breg);
            }
-         else if (!rs6000_offsettable_memref_p (dst)
+         else if (!rs6000_offsettable_memref_p (dst, reg_mode)
                   && GET_CODE (XEXP (dst, 0)) != LO_SUM)
            {
              if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY)
@@ -17049,7 +17177,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                }
            }
          else if (GET_CODE (XEXP (dst, 0)) != LO_SUM)
-           gcc_assert (rs6000_offsettable_memref_p (dst));
+           gcc_assert (rs6000_offsettable_memref_p (dst, reg_mode));
        }
 
       for (i = 0; i < nregs; i++)
@@ -17632,7 +17760,7 @@ rs6000_stack_info (void)
                                 - info_ptr->first_altivec_reg_save);
 
   /* Does this function call anything?  */
-  info_ptr->calls_p = (! current_function_is_leaf
+  info_ptr->calls_p = (! crtl->is_leaf 
                       || cfun->machine->ra_needs_full_frame);
 
   /* Determine if we need to save the condition code registers.  */
@@ -18683,9 +18811,9 @@ output_probe_stack_range (rtx reg1, rtx reg2)
   xops[0] = reg1;
   xops[1] = reg2;
   if (TARGET_64BIT)
-    output_asm_insn ("{cmp|cmpd} 0,%0,%1", xops);
+    output_asm_insn ("cmpd 0,%0,%1", xops);
   else
-    output_asm_insn ("{cmp|cmpw} 0,%0,%1", xops);
+    output_asm_insn ("cmpw 0,%0,%1", xops);
 
   fputs ("\tbeq 0,", asm_out_file);
   assemble_name_raw (asm_out_file, end_lab);
@@ -18693,11 +18821,11 @@ output_probe_stack_range (rtx reg1, rtx reg2)
 
   /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL.  */
   xops[1] = GEN_INT (-PROBE_INTERVAL);
-  output_asm_insn ("{cal %0,%1(%0)|addi %0,%0,%1}", xops);
+  output_asm_insn ("addi %0,%0,%1", xops);
 
   /* Probe at TEST_ADDR and branch.  */
   xops[1] = gen_rtx_REG (Pmode, 0);
-  output_asm_insn ("{st|stw} %1,0(%0)", xops);
+  output_asm_insn ("stw %1,0(%0)", xops);
   fprintf (asm_out_file, "\tb ");
   assemble_name_raw (asm_out_file, loop_lab);
   fputc ('\n', asm_out_file);
@@ -20164,18 +20292,6 @@ rs6000_output_function_prologue (FILE *file,
        }
     }
 
-  /* Write .extern for AIX common mode routines, if needed.  */
-  if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
-    {
-      fputs ("\t.extern __mulh\n", file);
-      fputs ("\t.extern __mull\n", file);
-      fputs ("\t.extern __divss\n", file);
-      fputs ("\t.extern __divus\n", file);
-      fputs ("\t.extern __quoss\n", file);
-      fputs ("\t.extern __quous\n", file);
-      common_mode_defined = 1;
-    }
-
   rs6000_pic_labelno++;
 }
 
@@ -22258,7 +22374,7 @@ output_function_profiler (FILE *file, int labelno)
       fprintf (file, "\tmflr %s\n", reg_names[0]);
       if (NO_PROFILE_COUNTERS)
        {
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
        }
       else if (TARGET_SECURE_PLT && flag_pic)
@@ -22271,29 +22387,29 @@ output_function_profiler (FILE *file, int labelno)
            }
          else
            asm_fprintf (file, "\tbcl 20,31,1f\n1:\n");
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
-         asm_fprintf (file, "\t{cau|addis} %s,%s,",
+         asm_fprintf (file, "\taddis %s,%s,",
                       reg_names[12], reg_names[12]);
          assemble_name (file, buf);
-         asm_fprintf (file, "-1b@ha\n\t{cal|la} %s,", reg_names[0]);
+         asm_fprintf (file, "-1b@ha\n\tla %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "-1b@l(%s)\n", reg_names[12]);
        }
       else if (flag_pic == 1)
        {
          fputs ("\tbl _GLOBAL_OFFSET_TABLE_@local-4\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          asm_fprintf (file, "\tmflr %s\n", reg_names[12]);
-         asm_fprintf (file, "\t{l|lwz} %s,", reg_names[0]);
+         asm_fprintf (file, "\tlwz %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@got(%s)\n", reg_names[12]);
        }
       else if (flag_pic > 1)
        {
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
          /* Now, we need to get the address of the label.  */
          if (TARGET_LINK_STACK)
@@ -22314,19 +22430,19 @@ output_function_profiler (FILE *file, int labelno)
              fputs ("-.\n1:", file);
              asm_fprintf (file, "\tmflr %s\n", reg_names[11]);
            }
-         asm_fprintf (file, "\t{l|lwz} %s,0(%s)\n",
+         asm_fprintf (file, "\tlwz %s,0(%s)\n",
                       reg_names[0], reg_names[11]);
-         asm_fprintf (file, "\t{cax|add} %s,%s,%s\n",
+         asm_fprintf (file, "\tadd %s,%s,%s\n",
                       reg_names[0], reg_names[0], reg_names[11]);
        }
       else
        {
-         asm_fprintf (file, "\t{liu|lis} %s,", reg_names[12]);
+         asm_fprintf (file, "\tlis %s,", reg_names[12]);
          assemble_name (file, buf);
          fputs ("@ha\n", file);
-         asm_fprintf (file, "\t{st|stw} %s,4(%s)\n",
+         asm_fprintf (file, "\tstw %s,4(%s)\n",
                       reg_names[0], reg_names[1]);
-         asm_fprintf (file, "\t{cal|la} %s,", reg_names[0]);
+         asm_fprintf (file, "\tla %s,", reg_names[0]);
          assemble_name (file, buf);
          asm_fprintf (file, "@l(%s)\n", reg_names[12]);
        }
@@ -22468,7 +22584,7 @@ rs6000_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
                scheduling pass will not know about this latency since
                the mtctr instruction, which has the latency associated
                to it, will be generated by reload.  */
-            return TARGET_POWER ? 5 : 4;
+            return 4;
           case TYPE_BRANCH:
             /* Leave some extra cycles between a compare and its
                dependent branch, to inhibit expensive mispredicts.  */
@@ -23041,7 +23157,6 @@ rs6000_issue_rate (void)
     return 1;
 
   switch (rs6000_cpu_attr) {
-  case CPU_RIOS1:  /* ? */
   case CPU_RS64A:
   case CPU_PPC601: /* ? */
   case CPU_PPC7450:
@@ -23061,7 +23176,6 @@ rs6000_issue_rate (void)
   case CPU_PPCE6500:
   case CPU_TITAN:
     return 2;
-  case CPU_RIOS2:
   case CPU_PPC476:
   case CPU_PPC604:
   case CPU_PPC604E:
@@ -24813,7 +24927,7 @@ macho_branch_islands (void)
 
   while (!VEC_empty (branch_island, branch_islands))
     {
-      branch_island *bi = VEC_last (branch_island, branch_islands);
+      branch_island *bi = &VEC_last (branch_island, branch_islands);
       const char *label = IDENTIFIER_POINTER (bi->label_name);
       const char *name = IDENTIFIER_POINTER (bi->function_name);
       char name_buf[512];
@@ -25957,7 +26071,8 @@ rs6000_debug_rtx_costs (rtx x, int code, int outer_code, int opno, int *total,
 /* Debug form of ADDRESS_COST that is selected if -mdebug=cost.  */
 
 static int
-rs6000_debug_address_cost (rtx x, bool speed)
+rs6000_debug_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
+                          addr_space_t as ATTRIBUTE_UNUSED, bool speed)
 {
   int ret = TARGET_ADDRESS_COST (x, speed);
 
@@ -27112,8 +27227,6 @@ rs6000_dbx_register_number (unsigned int regno)
 {
   if (regno <= 63 || write_symbols != DWARF2_DEBUG)
     return regno;
-  if (regno == MQ_REGNO)
-    return 100;
   if (regno == LR_REGNO)
     return 108;
   if (regno == CTR_REGNO)
@@ -27282,9 +27395,6 @@ static struct rs6000_opt_mask const rs6000_opt_masks[] =
 #ifdef MASK_STRICT_ALIGN
   { "strict-align",    MASK_STRICT_ALIGN,      false, false },
 #endif
-  { "power",           MASK_POWER,             false, false },
-  { "power2",          MASK_POWER2,            false, false },
-  { "powerpc",         MASK_POWERPC,           false, false },
   { "soft-float",      MASK_SOFT_FLOAT,        false, false },
   { "string",          MASK_STRING,            false, false },
 };
@@ -27301,7 +27411,6 @@ static struct rs6000_opt_mask const rs6000_builtin_mask_names[] =
   { "frsqrte",          RS6000_BTM_FRSQRTE,    false, false },
   { "frsqrtes",                 RS6000_BTM_FRSQRTES,   false, false },
   { "popcntd",          RS6000_BTM_POPCNTD,    false, false },
-  { "powerpc",          RS6000_BTM_POWERPC,    false, false },
   { "cell",             RS6000_BTM_CELL,       false, false },
 };
 
@@ -27887,7 +27996,7 @@ rs6000_allocate_stack_temp (enum machine_mode mode,
   if (!legitimate_indirect_address_p (addr, strict_p))
     {
       if (offsettable_p
-         && !rs6000_legitimate_offset_address_p (mode, addr, strict_p))
+         && !rs6000_legitimate_offset_address_p (mode, addr, strict_p, true))
        stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
 
       else if (reg_reg_p && !legitimate_indexed_address_p (addr, strict_p))