OSDN Git Service

* config/rs6000/rs6000.c (rs6000_override_options): Enable
[pf3gnuchains/gcc-fork.git] / gcc / config / rs6000 / rs6000.c
index 3000753..53b1082 100644 (file)
@@ -1,6 +1,7 @@
 /* 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 Free Software Foundation, Inc.
+   2000, 2001, 2002, 2003, 2004, 2005, 2006
+   Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
    This file is part of GCC.
@@ -55,6 +56,7 @@
 #include "tree-gimple.h"
 #include "intl.h"
 #include "params.h"
+#include "tm-constrs.h"
 #if TARGET_XCOFF
 #include "xcoffout.h"  /* get declarations of xcoff_*_section_name */
 #endif
@@ -154,10 +156,13 @@ enum rs6000_nop_insertion rs6000_sched_insert_nops;
 /* Support targetm.vectorize.builtin_mask_for_load.  */
 static GTY(()) tree altivec_builtin_mask_for_load;
 
-/* Size of long double */
+/* Size of long double */
 int rs6000_long_double_type_size;
 
-/* Whether -mabi=altivec has appeared */
+/* IEEE quad extended precision long double. */
+int rs6000_ieeequad;
+
+/* Whether -mabi=altivec has appeared.  */
 int rs6000_altivec_abi;
 
 /* Nonzero if we want SPE ABI extensions.  */
@@ -230,6 +235,12 @@ static enum {
 int toc_initialized;
 char toc_label_name[10];
 
+static GTY(()) section *read_only_data_section;
+static GTY(()) section *private_data_section;
+static GTY(()) section *read_only_private_data_section;
+static GTY(()) section *sdata2_section;
+static GTY(()) section *toc_section;
+
 /* Control alignment for fields within structures.  */
 /* String from -malign-XXXXX.  */
 int rs6000_alignment_flags;
@@ -238,11 +249,12 @@ 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= was used.  */
+  bool abi;                    /* True if -mabi=spe/nospe was 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.  */
 } rs6000_explicit_options;
 
 struct builtin_description
@@ -578,6 +590,7 @@ static unsigned toc_hash_function (const void *);
 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);
@@ -589,6 +602,8 @@ static void rs6000_assemble_visibility (tree, int);
 static int rs6000_ra_ever_killed (void);
 static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
 static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
+static bool rs6000_ms_bitfield_layout_p (tree);
+static tree rs6000_handle_struct_attribute (tree *, tree, tree, int, bool *);
 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[];
@@ -605,20 +620,25 @@ static unsigned int rs6000_elf_section_type_flags (tree, const char *, int);
 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_select_section (tree, int, unsigned HOST_WIDE_INT);
+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 void rs6000_elf_select_rtx_section (enum machine_mode, rtx,
-                                          unsigned HOST_WIDE_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)
      ATTRIBUTE_UNUSED;
 #endif
+static bool rs6000_use_blocks_for_constant_p (enum machine_mode, rtx);
 #if TARGET_XCOFF
+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 void rs6000_xcoff_asm_named_section (const char *, unsigned int, tree);
-static void rs6000_xcoff_select_section (tree, int, unsigned HOST_WIDE_INT);
-static void rs6000_xcoff_unique_section (tree, int);
-static void rs6000_xcoff_select_rtx_section (enum machine_mode, rtx,
+static section *rs6000_xcoff_select_section (tree, int,
                                             unsigned HOST_WIDE_INT);
+static void rs6000_xcoff_unique_section (tree, int);
+static section *rs6000_xcoff_select_rtx_section
+  (enum machine_mode, rtx, unsigned HOST_WIDE_INT);
 static const char * rs6000_xcoff_strip_name_encoding (const char *);
 static unsigned int rs6000_xcoff_section_type_flags (tree, const char *, int);
 static void rs6000_xcoff_file_start (void);
@@ -733,6 +753,7 @@ static void rs6000_darwin_file_start (void);
 static tree rs6000_build_builtin_va_list (void);
 static tree rs6000_gimplify_va_arg (tree, tree, tree *, tree *);
 static bool rs6000_must_pass_in_stack (enum machine_mode, tree);
+static bool rs6000_scalar_mode_supported_p (enum machine_mode);
 static bool rs6000_vector_mode_supported_p (enum machine_mode);
 static int get_vec_cmp_insn (enum rtx_code, enum machine_mode,
                             enum machine_mode);
@@ -913,6 +934,9 @@ static const char alt_reg_names[][8] =
 #define TARGET_BINDS_LOCAL_P darwin_binds_local_p
 #endif
 
+#undef TARGET_MS_BITFIELD_LAYOUT_P
+#define TARGET_MS_BITFIELD_LAYOUT_P rs6000_ms_bitfield_layout_p
+
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK rs6000_output_mi_thunk
 
@@ -972,6 +996,9 @@ static const char alt_reg_names[][8] =
 #undef TARGET_EH_RETURN_FILTER_MODE
 #define TARGET_EH_RETURN_FILTER_MODE rs6000_eh_return_filter_mode
 
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P rs6000_scalar_mode_supported_p
+
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P rs6000_vector_mode_supported_p
 
@@ -983,7 +1010,7 @@ static const char alt_reg_names[][8] =
 
 #undef TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS \
-  (TARGET_DEFAULT | MASK_SCHED_PROLOG)
+  (TARGET_DEFAULT)
 
 #undef TARGET_STACK_PROTECT_FAIL
 #define TARGET_STACK_PROTECT_FAIL rs6000_stack_protect_fail
@@ -1004,6 +1031,20 @@ static const char alt_reg_names[][8] =
 #define TARGET_ASM_OUTPUT_DWARF_DTPREL rs6000_output_dwarf_dtprel
 #endif
 
+/* Use a 32-bit anchor range.  This leads to sequences like:
+
+       addis   tmp,anchor,high
+       add     dest,tmp,low
+
+   where tmp itself acts as an anchor, and can be shared between
+   accesses to the same 64k page.  */
+#undef TARGET_MIN_ANCHOR_OFFSET
+#define TARGET_MIN_ANCHOR_OFFSET -0x7fffffff - 1
+#undef TARGET_MAX_ANCHOR_OFFSET
+#define TARGET_MAX_ANCHOR_OFFSET 0x7fffffff
+#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P
+#define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 
@@ -1017,10 +1058,12 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode)
   if (INT_REGNO_P (regno))
     return INT_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1);
 
-  /* The float registers can only hold floating modes and DImode.  */
+  /* The float registers can only hold floating modes and DImode.
+     This also excludes decimal float modes.  */
   if (FP_REGNO_P (regno))
     return
       (SCALAR_FLOAT_MODE_P (mode)
+       && !DECIMAL_FLOAT_MODE_P (mode)
        && FP_REGNO_P (regno + HARD_REGNO_NREGS (regno, mode) - 1))
       || (GET_MODE_CLASS (mode) == MODE_INT
          && GET_MODE_SIZE (mode) == UNITS_PER_FP_WORD);
@@ -1100,11 +1143,13 @@ rs6000_override_options (const char *default_cpu)
         {"403", PROCESSOR_PPC403,
          POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN},
         {"405", PROCESSOR_PPC405,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW},
-        {"405fp", PROCESSOR_PPC405, POWERPC_BASE_MASK | MASK_MULHW},
+         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
+        {"405fp", PROCESSOR_PPC405,
+         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
         {"440", PROCESSOR_PPC440,
-         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW},
-        {"440fp", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_MULHW},
+         POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB},
+        {"440fp", PROCESSOR_PPC440,
+         POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB},
         {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK},
         {"601", PROCESSOR_PPC601,
          MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING},
@@ -1174,7 +1219,8 @@ rs6000_override_options (const char *default_cpu)
     POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING,
     POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT
                     | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC
-                    | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW)
+                    | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW
+                    | MASK_DLMZB)
   };
 
   rs6000_init_hard_regno_mode_ok ();
@@ -1281,6 +1327,11 @@ rs6000_override_options (const char *default_cpu)
   if (!rs6000_explicit_options.long_double)
     rs6000_long_double_type_size = RS6000_DEFAULT_LONG_DOUBLE_SIZE;
 
+#ifndef POWERPC_LINUX
+  if (!rs6000_explicit_options.ieee)
+    rs6000_ieeequad = 1;
+#endif
+
   /* Set Altivec ABI as default for powerpc64 linux.  */
   if (TARGET_ELF && TARGET_64BIT)
     {
@@ -1299,6 +1350,11 @@ rs6000_override_options (const char *default_cpu)
       rs6000_alignment_flags = MASK_ALIGN_NATURAL;
     }
 
+  /* Place FP constants in the constant pool instead of TOC
+     if section anchors enabled.  */
+  if (flag_section_anchors)
+    TARGET_NO_FP_IN_TOC = 1;
+
   /* Handle -mtls-size option.  */
   rs6000_parse_tls_size_option ();
 
@@ -1394,8 +1450,7 @@ rs6000_override_options (const char *default_cpu)
   if (!rs6000_explicit_options.aix_struct_ret)
     aix_struct_return = (DEFAULT_ABI != ABI_V4 || DRAFT_V4_STRUCT_RET);
 
-  if (TARGET_LONG_DOUBLE_128
-      && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN))
+  if (TARGET_LONG_DOUBLE_128 && !TARGET_IEEEQUAD)
     REAL_MODE_FORMAT (TFmode) = &ibm_extended_format;
 
   if (TARGET_TOC)
@@ -1571,6 +1626,12 @@ optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
 
   /* Double growth factor to counter reduced min jump length.  */
   set_param_value ("max-grow-copy-bb-insns", 16);
+
+  /* Enable section anchors by default.
+     Skip section anchors for Objective C and Objective C++
+     until front-ends fixed.  */
+  if (lang_hooks.name[4] != 'O')
+    flag_section_anchors = 1;
 }
 
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -1593,10 +1654,10 @@ rs6000_handle_option (size_t code, const char *arg, int value)
                                | MASK_PPC_GFXOPT | MASK_POWERPC64);
       break;
     case OPT_mfull_toc:
-      target_flags &= ~(MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC
-                       | MASK_NO_SUM_IN_TOC);
-      target_flags_explicit |= (MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC
-                               | MASK_NO_SUM_IN_TOC);
+      target_flags &= ~MASK_MINIMAL_TOC;
+      TARGET_NO_FP_IN_TOC = 0;
+      TARGET_NO_SUM_IN_TOC = 0;
+      target_flags_explicit |= MASK_MINIMAL_TOC;
 #ifdef TARGET_USES_SYSV4_OPT
       /* Note, V.4 no longer uses a normal TOC, so make -mfull-toc, be
         just the same as -mminimal-toc.  */
@@ -1639,8 +1700,8 @@ rs6000_handle_option (size_t code, const char *arg, int value)
     case OPT_mminimal_toc:
       if (value == 1)
        {
-         target_flags &= ~(MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC);
-         target_flags_explicit |= (MASK_NO_FP_IN_TOC | MASK_NO_SUM_IN_TOC);
+         TARGET_NO_FP_IN_TOC = 0;
+         TARGET_NO_SUM_IN_TOC = 0;
        }
       break;
 
@@ -1711,18 +1772,18 @@ rs6000_handle_option (size_t code, const char *arg, int value)
     case OPT_mrelocatable:
       if (value == 1)
        {
-         target_flags |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC;
-         target_flags_explicit |= MASK_MINIMAL_TOC | MASK_NO_FP_IN_TOC;
+         target_flags |= MASK_MINIMAL_TOC;
+         target_flags_explicit |= MASK_MINIMAL_TOC;
+         TARGET_NO_FP_IN_TOC = 1;
        }
       break;
 
     case OPT_mrelocatable_lib:
       if (value == 1)
        {
-         target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC
-           | MASK_NO_FP_IN_TOC;
-         target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC
-           | MASK_NO_FP_IN_TOC;
+         target_flags |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
+         target_flags_explicit |= MASK_RELOCATABLE | MASK_MINIMAL_TOC;
+         TARGET_NO_FP_IN_TOC = 1;
        }
       else
        {
@@ -1733,23 +1794,31 @@ rs6000_handle_option (size_t code, const char *arg, int value)
 #endif
 
     case OPT_mabi_:
-      rs6000_explicit_options.abi = true;
       if (!strcmp (arg, "altivec"))
        {
+         rs6000_explicit_options.abi = true;
          rs6000_altivec_abi = 1;
          rs6000_spe_abi = 0;
        }
       else if (! strcmp (arg, "no-altivec"))
-       rs6000_altivec_abi = 0;
+       {
+         /* ??? Don't set rs6000_explicit_options.abi here, to allow
+            the default for rs6000_spe_abi to be chosen later.  */
+         rs6000_altivec_abi = 0;
+       }
       else if (! strcmp (arg, "spe"))
        {
+         rs6000_explicit_options.abi = true;
          rs6000_spe_abi = 1;
          rs6000_altivec_abi = 0;
          if (!TARGET_SPE_ABI)
            error ("not configured for ABI: '%s'", arg);
        }
       else if (! strcmp (arg, "no-spe"))
-       rs6000_spe_abi = 0;
+       {
+         rs6000_explicit_options.abi = true;
+         rs6000_spe_abi = 0;
+       }
 
       /* These are here for testing during development only, do not
         document in the manual please.  */
@@ -1764,6 +1833,19 @@ rs6000_handle_option (size_t code, const char *arg, int value)
          warning (0, "Using old darwin ABI");
        }
 
+      else if (! strcmp (arg, "ibmlongdouble"))
+       {
+         rs6000_explicit_options.ieee = true;
+         rs6000_ieeequad = 0;
+         warning (0, "Using IBM extended precision long double");
+       }
+      else if (! strcmp (arg, "ieeelongdouble"))
+       {
+         rs6000_explicit_options.ieee = true;
+         rs6000_ieeequad = 1;
+         warning (0, "Using IEEE extended precision long double");
+       }
+
       else
        {
          error ("unknown ABI specified: '%s'", arg);
@@ -1903,8 +1985,8 @@ rs6000_file_start (void)
 
   if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
     {
-      toc_section ();
-      text_section ();
+      switch_to_section (toc_section);
+      switch_to_section (text_section);
     }
 }
 
@@ -1938,11 +2020,12 @@ int
 num_insns_constant_wide (HOST_WIDE_INT value)
 {
   /* signed constant loadable with {cal|addi} */
-  if (CONST_OK_FOR_LETTER_P (value, 'I'))
+  if ((unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000)
     return 1;
 
   /* constant loadable with {cau|addis} */
-  else if (CONST_OK_FOR_LETTER_P (value, 'L'))
+  else if ((value & 0xffff) == 0
+          && (value >> 31 == -1 || value >> 31 == 0))
     return 1;
 
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -2037,7 +2120,7 @@ num_insns_constant (rtx op, enum machine_mode mode)
 }
 
 
-/* Return true if OP can be synthesized with a particular vspltisb, vspltish 
+/* Return true if OP can be synthesized with a particular vspltisb, vspltish
    or vspltisw instruction.  OP is a CONST_VECTOR.  Which instruction is used
    depends on STEP and COPIES, one of which will be 1.  If COPIES > 1,
    all items are set to the same value and contain COPIES replicas of the
@@ -2104,7 +2187,7 @@ vspltis_constant (rtx op, unsigned step, unsigned copies)
 }
 
 
-/* Return true if OP is of the given MODE and can be synthesized 
+/* Return true if OP is of the given MODE and can be synthesized
    with a vspltisb, vspltish or vspltisw.  */
 
 bool
@@ -2496,18 +2579,27 @@ invalid_e500_subreg (rtx op, enum machine_mode mode)
    field is an FP double while the FP fields remain word aligned.  */
 
 unsigned int
-rs6000_special_round_type_align (tree type, int computed, int specified)
+rs6000_special_round_type_align (tree type, unsigned int computed,
+                                unsigned int specified)
 {
+  unsigned int align = MAX (computed, specified);
   tree field = TYPE_FIELDS (type);
 
   /* Skip all non field decls */
   while (field != NULL && TREE_CODE (field) != FIELD_DECL)
     field = TREE_CHAIN (field);
 
-  if (field == NULL || field == type || DECL_MODE (field) != DFmode)
-    return MAX (computed, specified);
+  if (field != NULL && field != type)
+    {
+      type = TREE_TYPE (field);
+      while (TREE_CODE (type) == ARRAY_TYPE)
+       type = TREE_TYPE (type);
+
+      if (type != error_mark_node && TYPE_MODE (type) == DFmode)
+       align = MAX (align, 64);
+    }
 
-  return MAX (MAX (computed, specified), 64);
+  return align;
 }
 
 /* Return 1 for an operand in small memory on V.4/eabi.  */
@@ -2630,8 +2722,8 @@ legitimate_constant_pool_address_p (rtx x)
          && constant_pool_expr_p (XEXP (x, 1)));
 }
 
-bool
-rs6000_legitimate_small_data_p (enum machine_mode mode, rtx x)
+static bool
+legitimate_small_data_p (enum machine_mode mode, rtx x)
 {
   return (DEFAULT_ABI == ABI_V4
          && !flag_pic && !TARGET_TOC
@@ -2726,23 +2818,19 @@ legitimate_indexed_address_p (rtx x, int strict)
   op0 = XEXP (x, 0);
   op1 = XEXP (x, 1);
 
-  if (REG_P (op0) && REG_P (op1))
-    return ((INT_REG_OK_FOR_BASE_P (op0, strict)
-            && INT_REG_OK_FOR_INDEX_P (op1, strict))
-           || (INT_REG_OK_FOR_BASE_P (op1, strict)
-               && INT_REG_OK_FOR_INDEX_P (op0, strict)));
-
   /* Recognize the rtl generated by reload which we know will later be
-     replaced by a base reg.  We rely on nothing but reload generating
-     this particular pattern, a reasonable assumption because it is not
-     canonical.  */
-  else if (reload_in_progress
-          && GET_CODE (op0) == PLUS
-          && REG_P (XEXP (op0, 0))
-          && GET_CODE (XEXP (op0, 1)) == CONST_INT
-          && REG_P (op1))
-    return INT_REG_OK_FOR_INDEX_P (op1, strict);
-  return false;
+     replaced with proper base and index regs.  */
+  if (!strict
+      && reload_in_progress
+      && (REG_P (op0) || GET_CODE (op0) == PLUS)
+      && REG_P (op1))
+    return true;
+
+  return (REG_P (op0) && REG_P (op1)
+         && ((INT_REG_OK_FOR_BASE_P (op0, strict)
+              && INT_REG_OK_FOR_INDEX_P (op1, strict))
+             || (INT_REG_OK_FOR_BASE_P (op1, strict)
+                 && INT_REG_OK_FOR_INDEX_P (op0, strict))));
 }
 
 inline bool
@@ -3325,9 +3413,12 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && !flag_pic
 #endif
       /* Don't do this for TFmode, since the result isn't offsettable.
-        The same goes for DImode without 64-bit gprs.  */
+        The same goes for DImode without 64-bit gprs and DFmode
+        without fprs.  */
       && mode != TFmode
-      && (mode != DImode || TARGET_POWERPC64))
+      && (mode != DImode || TARGET_POWERPC64)
+      && (mode != DFmode || TARGET_POWERPC64
+         || (TARGET_FPRS && TARGET_HARD_FLOAT)))
     {
 #if TARGET_MACHO
       if (flag_pic)
@@ -3372,7 +3463,7 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
       && constant_pool_expr_p (x)
       && ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (get_pool_constant (x), mode))
     {
-      (x) = create_TOC_reference (x);
+      x = create_TOC_reference (x);
       *win = 1;
       return x;
     }
@@ -3420,7 +3511,7 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
       && TARGET_UPDATE
       && legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
     return 1;
-  if (rs6000_legitimate_small_data_p (mode, x))
+  if (legitimate_small_data_p (mode, x))
     return 1;
   if (legitimate_constant_pool_address_p (x))
     return 1;
@@ -3485,6 +3576,33 @@ rs6000_mode_dependent_address (rtx addr)
   return false;
 }
 
+/* More elaborate version of recog's offsettable_memref_p predicate
+   that works around the ??? note of rs6000_mode_dependent_address.
+   In particular it accepts
+
+     (mem:DI (plus:SI (reg/f:SI 31 31) (const_int 32760 [0x7ff8])))
+
+   in 32-bit mode, that the recog predicate rejects.  */
+
+bool
+rs6000_offsettable_memref_p (rtx op)
+{
+  if (!MEM_P (op))
+    return false;
+
+  /* First mimic offsettable_memref_p.  */
+  if (offsettable_address_p (1, GET_MODE (op), XEXP (op, 0)))
+    return true;
+
+  /* offsettable_address_p invokes rs6000_mode_dependent_address, but
+     the latter predicate knows nothing about the mode of the memory
+     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);
+}
+
 /* Return number of consecutive hard regs needed starting at reg REGNO
    to hold something of mode MODE.
    This is ordinarily the length in words of a value of mode MODE
@@ -3881,7 +3999,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
 
   /* 128-bit constant floating-point values on Darwin should really be
      loaded as two parts.  */
-  if ((DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+  if (!TARGET_IEEEQUAD
       && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128
       && mode == TFmode && GET_CODE (operands[1]) == CONST_DOUBLE)
     {
@@ -3981,7 +4099,7 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
                = CONSTANT_POOL_ADDRESS_P (operands[1]);
              SYMBOL_REF_FLAGS (new_ref) = SYMBOL_REF_FLAGS (operands[1]);
              SYMBOL_REF_USED (new_ref) = SYMBOL_REF_USED (operands[1]);
-             SYMBOL_REF_DECL (new_ref) = SYMBOL_REF_DECL (operands[1]);
+             SYMBOL_REF_DATA (new_ref) = SYMBOL_REF_DATA (operands[1]);
              operands[1] = new_ref;
            }
 
@@ -4126,6 +4244,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)             \
    && (CUM)->fregno <= FP_ARG_MAX_REG          \
    && TARGET_HARD_FLOAT && TARGET_FPRS)
 
@@ -4205,7 +4324,7 @@ rs6000_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
       return true;
     }
 
-  if (DEFAULT_ABI == ABI_V4 && TYPE_MODE (type) == TFmode)
+  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && TYPE_MODE (type) == TFmode)
     return true;
 
   return false;
@@ -4592,13 +4711,15 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else if (DEFAULT_ABI == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
-         && (mode == SFmode || mode == DFmode))
+         && (mode == SFmode || mode == DFmode
+             || (mode == TFmode && !TARGET_IEEEQUAD)))
        {
-         if (cum->fregno <= FP_ARG_V4_MAX_REG)
-           cum->fregno++;
+         if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
+           cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
          else
            {
-             if (mode == DFmode)
+             cum->fregno = FP_ARG_V4_MAX_REG + 1;
+             if (mode == DFmode || mode == TFmode)
                cum->words += cum->words & 1;
              cum->words += rs6000_arg_size (mode, type);
            }
@@ -4650,6 +4771,7 @@ 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)
          && TARGET_HARD_FLOAT && TARGET_FPRS)
        cum->fregno += (GET_MODE_SIZE (mode) + 7) >> 3;
 
@@ -4950,17 +5072,13 @@ rs6000_mixed_function_arg (enum machine_mode mode, tree type, int align_words)
   if (align_words + n_units > GP_ARG_NUM_REG)
     /* Not all of the arg fits in gprs.  Say that it goes in memory too,
        using a magic NULL_RTX component.
-       FIXME: This is not strictly correct.  Only some of the arg
-       belongs in memory, not all of it.  However, there isn't any way
-       to do this currently, apart from building rtx descriptions for
-       the pieces of memory we want stored.  Due to bugs in the generic
-       code we can't use the normal function_arg_partial_nregs scheme
-       with the PARALLEL arg description we emit here.
-       In any case, the code to store the whole arg to memory is often
-       more efficient than code to store pieces, and we know that space
-       is available in the right place for the whole arg.  */
-    /* FIXME: This should be fixed since the conversion to
-       TARGET_ARG_PARTIAL_BYTES.  */
+       This is not strictly correct.  Only some of the arg belongs in
+       memory, not all of it.  However, the normal scheme using
+       function_arg_partial_nregs can result in unusual subregs, eg.
+       (subreg:SI (reg:DF) 4), which are not handled well.  The code to
+       store the whole arg to memory is often more efficient than code
+       to store pieces, and we know that space is available in the right
+       place for the whole arg.  */
     rvec[k++] = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
 
   i = 0;
@@ -5123,9 +5241,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
   else if (abi == ABI_V4)
     {
       if (TARGET_HARD_FLOAT && TARGET_FPRS
-         && (mode == SFmode || mode == DFmode))
+         && (mode == SFmode || mode == DFmode
+             || (mode == TFmode && !TARGET_IEEEQUAD)))
        {
-         if (cum->fregno <= FP_ARG_V4_MAX_REG)
+         if (cum->fregno + (mode == TFmode ? 1 : 0) <= FP_ARG_V4_MAX_REG)
            return gen_rtx_REG (mode, cum->fregno);
          else
            return NULL_RTX;
@@ -5201,9 +5320,8 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
                         include the portion actually in registers here.  */
                      enum machine_mode rmode = TARGET_32BIT ? SImode : DImode;
                      rtx off;
-                     int i=0;
-                     if (align_words + n_words > GP_ARG_NUM_REG
-                         && (TARGET_32BIT && TARGET_POWERPC64))
+                     int i = 0;
+                     if (align_words + n_words > GP_ARG_NUM_REG)
                        /* Not all of the arg fits in gprs.  Say that it
                           goes in memory too, using a magic NULL_RTX
                           component.  Also see comment in
@@ -5282,18 +5400,20 @@ rs6000_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
   align_words = rs6000_parm_start (mode, type, cum->words);
 
-  if (USE_FP_FOR_ARG_P (cum, mode, type)
+  if (USE_FP_FOR_ARG_P (cum, mode, type))
+    {
       /* If we are passing this arg in the fixed parameter save area
         (gprs or memory) as well as fprs, then this function should
-        return the number of bytes passed in the parameter save area
-        rather than bytes passed in fprs.  */
-      && !(type
-          && (cum->nargs_prototype <= 0
-              || (DEFAULT_ABI == ABI_AIX
-                  && TARGET_XL_COMPAT
-                  && align_words >= GP_ARG_NUM_REG))))
-    {
-      if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3) > FP_ARG_MAX_REG + 1)
+        return the number of partial bytes passed in the parameter
+        save area rather than partial bytes passed in fprs.  */
+      if (type
+         && (cum->nargs_prototype <= 0
+             || (DEFAULT_ABI == ABI_AIX
+                 && TARGET_XL_COMPAT
+                 && align_words >= GP_ARG_NUM_REG)))
+       return 0;
+      else if (cum->fregno + ((GET_MODE_SIZE (mode) + 7) >> 3)
+              > FP_ARG_MAX_REG + 1)
        ret = (FP_ARG_MAX_REG + 1 - cum->fregno) * 8;
       else if (cum->nargs_prototype >= 0)
        return 0;
@@ -5328,7 +5448,7 @@ rs6000_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
                          enum machine_mode mode, tree type,
                          bool named ATTRIBUTE_UNUSED)
 {
-  if (DEFAULT_ABI == ABI_V4 && mode == TFmode)
+  if (DEFAULT_ABI == ABI_V4 && TARGET_IEEEQUAD && mode == TFmode)
     {
       if (TARGET_DEBUG_ARG)
        fprintf (stderr, "function_arg_pass_by_reference: V4 long double\n");
@@ -5779,14 +5899,16 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   align = 1;
 
   if (TARGET_HARD_FLOAT && TARGET_FPRS
-      && (TYPE_MODE (type) == SFmode || TYPE_MODE (type) == DFmode))
+      && (TYPE_MODE (type) == SFmode
+         || TYPE_MODE (type) == DFmode
+         || TYPE_MODE (type) == TFmode))
     {
       /* FP args go in FP registers, if present.  */
       reg = fpr;
-      n_reg = 1;
+      n_reg = (size + 7) / 8;
       sav_ofs = 8*4;
       sav_scale = 8;
-      if (TYPE_MODE (type) == DFmode)
+      if (TYPE_MODE (type) != SFmode)
        align = 8;
     }
   else
@@ -5818,7 +5940,7 @@ rs6000_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
         As are any other 2 gpr item such as complex int due to a
         historical mistake.  */
       u = reg;
-      if (n_reg == 2)
+      if (n_reg == 2 && reg == gpr)
        {
          u = build2 (BIT_AND_EXPR, TREE_TYPE (reg), reg,
                     size_int (n_reg - 1));
@@ -5849,10 +5971,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)
+      if ((n_reg == 2 && reg != gpr) || n_reg > 2)
        {
          /* Ensure that we don't find any more args in regs.
-            Alignment has taken care of the n_reg == 2 case.  */
+            Alignment has taken care of the n_reg == 2 gpr case.  */
          t = build2 (MODIFY_EXPR, TREE_TYPE (reg), reg, size_int (8));
          gimplify_and_add (t, pre_p);
        }
@@ -6516,7 +6638,7 @@ rs6000_expand_unop_builtin (enum insn_code icode, tree arglist, rtx target)
 {
   rtx pat;
   tree arg0 = TREE_VALUE (arglist);
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 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;
 
@@ -6565,7 +6687,7 @@ altivec_expand_abs_builtin (enum insn_code icode, tree arglist, rtx target)
 {
   rtx pat, scratch1, scratch2;
   tree arg0 = TREE_VALUE (arglist);
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 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;
 
@@ -6598,8 +6720,8 @@ rs6000_expand_binop_builtin (enum insn_code icode, tree arglist, rtx target)
   rtx pat;
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
@@ -6673,8 +6795,8 @@ altivec_expand_predicate_builtin (enum insn_code icode, const char *opcode,
   tree cr6_form = TREE_VALUE (arglist);
   tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
   tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
   enum machine_mode tmode = SImode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
@@ -6751,8 +6873,8 @@ altivec_expand_lv_builtin (enum insn_code icode, tree arglist, rtx target)
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = Pmode;
   enum machine_mode mode1 = Pmode;
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
 
   if (icode == CODE_FOR_nothing)
     /* Builtin not supported on this processor.  */
@@ -6794,9 +6916,9 @@ spe_expand_stv_builtin (enum insn_code icode, tree arglist)
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
   tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
   rtx pat;
   enum machine_mode mode0 = insn_data[icode].operand[0].mode;
   enum machine_mode mode1 = insn_data[icode].operand[1].mode;
@@ -6827,9 +6949,9 @@ altivec_expand_stv_builtin (enum insn_code icode, tree arglist)
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
   tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
   rtx pat, addr;
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode1 = Pmode;
@@ -6869,9 +6991,9 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree arglist, rtx target)
   tree arg0 = TREE_VALUE (arglist);
   tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
   tree arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
@@ -6956,7 +7078,7 @@ altivec_expand_ld_builtin (tree exp, rtx target, bool *expandedp)
   *expandedp = true;
 
   arg0 = TREE_VALUE (arglist);
-  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  op0 = expand_normal (arg0);
   tmode = insn_data[icode].operand[0].mode;
   mode0 = insn_data[icode].operand[1].mode;
 
@@ -7009,8 +7131,8 @@ altivec_expand_st_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
 
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  op0 = expand_normal (arg0);
+  op1 = expand_normal (arg1);
   mode0 = insn_data[icode].operand[0].mode;
   mode1 = insn_data[icode].operand[1].mode;
 
@@ -7051,9 +7173,9 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
        arg0 = TREE_VALUE (arglist);
        arg1 = TREE_VALUE (TREE_CHAIN (arglist));
        arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-       op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-       op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+       op0 = expand_normal (arg0);
+       op1 = expand_normal (arg1);
+       op2 = expand_normal (arg2);
        mode0 = insn_data[d->icode].operand[0].mode;
        mode1 = insn_data[d->icode].operand[1].mode;
        mode2 = insn_data[d->icode].operand[2].mode;
@@ -7101,7 +7223,7 @@ altivec_expand_vec_init_builtin (tree type, tree arglist, rtx target)
 
   for (i = 0; i < n_elt; ++i, arglist = TREE_CHAIN (arglist))
     {
-      rtx x = expand_expr (TREE_VALUE (arglist), NULL_RTX, VOIDmode, 0);
+      rtx x = expand_normal (TREE_VALUE (arglist));
       RTVEC_ELT (v, i) = gen_lowpart (inner_mode, x);
     }
 
@@ -7176,7 +7298,7 @@ altivec_expand_vec_ext_builtin (tree arglist, rtx target)
   arg0 = TREE_VALUE (arglist);
   arg1 = TREE_VALUE (TREE_CHAIN (arglist));
 
-  op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  op0 = expand_normal (arg0);
   elt = get_element_number (TREE_TYPE (arg0), arg1);
 
   tmode = TYPE_MODE (TREE_TYPE (TREE_TYPE (arg0)));
@@ -7262,7 +7384,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
     case ALTIVEC_BUILTIN_MTVSCR:
       icode = CODE_FOR_altivec_mtvscr;
       arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
 
       /* If we got invalid arguments bail out before generating bad rtl.  */
@@ -7285,7 +7407,7 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
       icode = CODE_FOR_altivec_dss;
       arg0 = TREE_VALUE (arglist);
       STRIP_NOPS (arg0);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
 
       /* If we got invalid arguments bail out before generating bad rtl.  */
@@ -7519,7 +7641,7 @@ spe_expand_builtin (tree exp, rtx target, bool *expandedp)
     case SPE_BUILTIN_MTSPEFSCR:
       icode = CODE_FOR_spe_mtspefscr;
       arg0 = TREE_VALUE (arglist);
-      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op0 = expand_normal (arg0);
       mode0 = insn_data[icode].operand[0].mode;
 
       if (arg0 == error_mark_node)
@@ -7547,8 +7669,8 @@ spe_expand_predicate_builtin (enum insn_code icode, tree arglist, rtx target)
   tree form = TREE_VALUE (arglist);
   tree arg0 = TREE_VALUE (TREE_CHAIN (arglist));
   tree arg1 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
   int form_int;
@@ -7656,10 +7778,10 @@ spe_expand_evsel_builtin (enum insn_code icode, tree arglist, rtx target)
   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))));
-  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
-  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
-  rtx op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
-  rtx op3 = expand_expr (arg3, NULL_RTX, VOIDmode, 0);
+  rtx op0 = expand_normal (arg0);
+  rtx op1 = expand_normal (arg1);
+  rtx op2 = expand_normal (arg2);
+  rtx op3 = expand_normal (arg3);
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
   enum machine_mode mode1 = insn_data[icode].operand[2].mode;
 
@@ -7904,6 +8026,12 @@ rs6000_init_builtins (void)
     altivec_init_builtins ();
   if (TARGET_ALTIVEC || TARGET_SPE)
     rs6000_common_init_builtins ();
+
+#if TARGET_XCOFF
+  /* AIX libm provides clog as __clog.  */
+  if (built_in_decls [BUILT_IN_CLOG])
+    set_user_assembler_name (built_in_decls [BUILT_IN_CLOG], "__clog");
+#endif
 }
 
 /* Search through a set of builtins and enable the mask bits.
@@ -9024,33 +9152,32 @@ rs6000_init_libfuncs (void)
   if (!TARGET_HARD_FLOAT)
     return;
 
-  if (DEFAULT_ABI != ABI_V4)
+  if (DEFAULT_ABI != ABI_V4 && TARGET_XCOFF
+      && !TARGET_POWER2 && !TARGET_POWERPC)
     {
-      if (TARGET_XCOFF && ! TARGET_POWER2 && ! TARGET_POWERPC)
-       {
-         /* AIX library routines for float->int conversion.  */
-         set_conv_libfunc (sfix_optab, SImode, DFmode, "__itrunc");
-         set_conv_libfunc (ufix_optab, SImode, DFmode, "__uitrunc");
-         set_conv_libfunc (sfix_optab, SImode, TFmode, "_qitrunc");
-         set_conv_libfunc (ufix_optab, SImode, TFmode, "_quitrunc");
-       }
+      /* 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)
-       {
-         set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
-         set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
-         set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
-         set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
-       }
-      else
-       {
-         set_optab_libfunc (add_optab, TFmode, "_xlqadd");
-         set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
-         set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
-         set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
-       }
-    }
+    if (!TARGET_XL_COMPAT)
+      {
+       set_optab_libfunc (add_optab, TFmode, "__gcc_qadd");
+       set_optab_libfunc (sub_optab, TFmode, "__gcc_qsub");
+       set_optab_libfunc (smul_optab, TFmode, "__gcc_qmul");
+       set_optab_libfunc (sdiv_optab, TFmode, "__gcc_qdiv");
+      }
+    else
+      {
+       set_optab_libfunc (add_optab, TFmode, "_xlqadd");
+       set_optab_libfunc (sub_optab, TFmode, "_xlqsub");
+       set_optab_libfunc (smul_optab, TFmode, "_xlqmul");
+       set_optab_libfunc (sdiv_optab, TFmode, "_xlqdiv");
+      }
   else
     {
       /* 32-bit SVR4 quad floating point routines.  */
@@ -10667,7 +10794,8 @@ print_operand (FILE *file, rtx x, int code)
        else
          {
            gcc_assert (GET_CODE (tmp) == PLUS
-                       && GET_CODE (XEXP (tmp, 1)) == REG);
+                       && REG_P (XEXP (tmp, 0))
+                       && REG_P (XEXP (tmp, 1)));
 
            if (REGNO (XEXP (tmp, 0)) == 0)
              fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (tmp, 1)) ],
@@ -10727,6 +10855,7 @@ print_operand_address (FILE *file, rtx x)
     }
   else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == REG)
     {
+      gcc_assert (REG_P (XEXP (x, 0)));
       if (REGNO (XEXP (x, 0)) == 0)
        fprintf (file, "%s,%s", reg_names[ REGNO (XEXP (x, 1)) ],
                 reg_names[ REGNO (XEXP (x, 0)) ]);
@@ -10806,15 +10935,14 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
   /* Special handling for SI values.  */
   if (RELOCATABLE_NEEDS_FIXUP && size == 4 && aligned_p)
     {
-      extern int in_toc_section (void);
       static int recurse = 0;
 
       /* For -mrelocatable, we mark all addresses that need to be fixed up
         in the .fixup section.  */
       if (TARGET_RELOCATABLE
-         && !in_toc_section ()
-         && !in_text_section ()
-         && !in_unlikely_text_section ()
+         && in_section != toc_section
+         && in_section != text_section
+         && !unlikely_text_section_p (in_section)
          && !recurse
          && GET_CODE (x) != CONST_INT
          && GET_CODE (x) != CONST_DOUBLE
@@ -11084,7 +11212,7 @@ rs6000_generate_compare (enum rtx_code code)
         CLOBBERs to match cmptf_internal2 pattern.  */
       if (comp_mode == CCFPmode && TARGET_XL_COMPAT
          && GET_MODE (rs6000_compare_op0) == TFmode
-         && (DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+         && !TARGET_IEEEQUAD
          && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128)
        emit_insn (gen_rtx_PARALLEL (VOIDmode,
          gen_rtvec (9,
@@ -12260,6 +12388,96 @@ rs6000_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
   emit_insn (gen_isync ());
 }
 
+void
+rs6000_expand_compare_and_swapqhi (rtx dst, rtx mem, rtx oldval, rtx newval)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx addrSI, align, wdst, shift, mask;
+  HOST_WIDE_INT shift_mask = mode == QImode ? 0x18 : 0x10;
+  HOST_WIDE_INT imask = GET_MODE_MASK (mode);
+
+  /* Shift amount for subword relative to aligned word.  */
+  addrSI = force_reg (SImode, gen_lowpart_common (SImode, XEXP (mem, 0)));
+  shift = gen_reg_rtx (SImode);
+  emit_insn (gen_rlwinm (shift, addrSI, GEN_INT (3),
+                        GEN_INT (shift_mask)));
+  emit_insn (gen_xorsi3 (shift, shift, GEN_INT (shift_mask)));
+
+  /* Shift and mask old value into position within word.  */
+  oldval = convert_modes (SImode, mode, oldval, 1);
+  oldval = expand_binop (SImode, and_optab,
+                        oldval, GEN_INT (imask), NULL_RTX,
+                        1, OPTAB_LIB_WIDEN);
+  emit_insn (gen_ashlsi3 (oldval, oldval, shift));
+
+  /* Shift and mask new value into position within word.  */
+  newval = convert_modes (SImode, mode, newval, 1);
+  newval = expand_binop (SImode, and_optab,
+                        newval, GEN_INT (imask), NULL_RTX,
+                        1, OPTAB_LIB_WIDEN);
+  emit_insn (gen_ashlsi3 (newval, newval, shift));
+
+  /* Mask for insertion.  */
+  mask = gen_reg_rtx (SImode);
+  emit_move_insn (mask, GEN_INT (imask));
+  emit_insn (gen_ashlsi3 (mask, mask, shift));
+
+  /* Address of aligned word containing subword.  */
+  align = expand_binop (Pmode, and_optab, XEXP (mem, 0), GEN_INT (-4),
+                       NULL_RTX, 1, OPTAB_LIB_WIDEN);
+  mem = change_address (mem, SImode, align);
+  set_mem_align (mem, 32);
+  MEM_VOLATILE_P (mem) = 1;
+
+  wdst = gen_reg_rtx (SImode);
+  emit_insn (gen_sync_compare_and_swapqhi_internal (wdst, mask,
+                                                   oldval, newval, mem));
+
+  emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+rs6000_split_compare_and_swapqhi (rtx dest, rtx mask,
+                                 rtx oldval, rtx newval, rtx mem,
+                                 rtx scratch)
+{
+  rtx label1, label2, x, cond = gen_rtx_REG (CCmode, CR0_REGNO);
+
+  emit_insn (gen_memory_barrier ());
+  label1 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  label2 = gen_rtx_LABEL_REF (VOIDmode, gen_label_rtx ());
+  emit_label (XEXP (label1, 0));
+
+  emit_load_locked (SImode, scratch, mem);
+
+  /* Mask subword within loaded value for comparison with oldval.
+     Use UNSPEC_AND to avoid clobber.*/
+  emit_insn (gen_rtx_SET (SImode, dest,
+                         gen_rtx_UNSPEC (SImode,
+                                         gen_rtvec (2, scratch, mask),
+                                         UNSPEC_AND)));
+
+  x = gen_rtx_COMPARE (CCmode, dest, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label2);
+
+  /* Clear subword within loaded value for insertion of new value.  */
+  emit_insn (gen_rtx_SET (SImode, scratch,
+                         gen_rtx_AND (SImode,
+                                      gen_rtx_NOT (SImode, mask), scratch)));
+  emit_insn (gen_iorsi3 (scratch, scratch, newval));
+  emit_store_conditional (SImode, cond, mem, scratch);
+
+  x = gen_rtx_NE (VOIDmode, cond, const0_rtx);
+  emit_unlikely_jump (x, label1);
+
+  emit_insn (gen_isync ());
+  emit_label (XEXP (label2, 0));
+}
+
+
   /* Emit instructions to move SRC to DST.  Called by splitters for
    multi-register moves.  It will emit at most one instruction for
    each register that is accessed; that is, it won't emit li/lis pairs
@@ -12327,7 +12545,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
                         : gen_adddi3 (breg, breg, delta_rtx));
              src = replace_equiv_address (src, breg);
            }
-         else if (! offsettable_memref_p (src))
+         else if (! rs6000_offsettable_memref_p (src))
            {
              rtx basereg;
              basereg = gen_rtx_REG (Pmode, reg);
@@ -12380,7 +12598,7 @@ rs6000_split_multireg_move (rtx dst, rtx src)
              dst = replace_equiv_address (dst, breg);
            }
          else
-           gcc_assert (offsettable_memref_p (dst));
+           gcc_assert (rs6000_offsettable_memref_p (dst));
        }
 
       for (i = 0; i < nregs; i++)
@@ -13484,6 +13702,8 @@ uses_TOC (void)
 rtx
 create_TOC_reference (rtx symbol)
 {
+  if (no_new_pseudos)
+    regs_ever_live[TOC_REGISTER] = 1;
   return gen_rtx_PLUS (Pmode,
           gen_rtx_REG (Pmode, TOC_REGISTER),
             gen_rtx_CONST (Pmode,
@@ -14999,8 +15219,6 @@ static void
 rs6000_output_function_epilogue (FILE *file,
                                 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  rs6000_stack_t *info = rs6000_stack_info ();
-
   if (! HAVE_epilogue)
     {
       rtx insn = get_last_insn ();
@@ -15071,13 +15289,14 @@ rs6000_output_function_epilogue (FILE *file,
      System V.4 Powerpc's (and the embedded ABI derived from it) use a
      different traceback table.  */
   if (DEFAULT_ABI == ABI_AIX && ! flag_inhibit_size_directive
-      && rs6000_traceback != traceback_none)
+      && rs6000_traceback != traceback_none && !current_function_is_thunk)
     {
       const char *fname = NULL;
       const char *language_string = lang_hooks.name;
       int fixed_parms = 0, float_parms = 0, parm_info = 0;
       int i;
       int optional_tbtab;
+      rs6000_stack_t *info = rs6000_stack_info ();
 
       if (rs6000_traceback == traceback_full)
        optional_tbtab = 1;
@@ -15118,7 +15337,8 @@ rs6000_output_function_epilogue (FILE *file,
         official way to discover the language being compiled, so we
         use language_string.
         C is 0.  Fortran is 1.  Pascal is 2.  Ada is 3.  C++ is 9.
-        Java is 13.  Objective-C is 14.  */
+        Java is 13.  Objective-C is 14.  Objective-C++ isn't assigned
+        a number, so for now use 9.  */
       if (! strcmp (language_string, "GNU C"))
        i = 0;
       else if (! strcmp (language_string, "GNU F77")
@@ -15128,7 +15348,8 @@ rs6000_output_function_epilogue (FILE *file,
        i = 2;
       else if (! strcmp (language_string, "GNU Ada"))
        i = 3;
-      else if (! strcmp (language_string, "GNU C++"))
+      else if (! strcmp (language_string, "GNU C++")
+              || ! strcmp (language_string, "GNU Objective-C++"))
        i = 9;
       else if (! strcmp (language_string, "GNU Java"))
        i = 13;
@@ -15639,13 +15860,17 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
   /* Handle FP constants specially.  Note that if we have a minimal
      TOC, things we put here aren't actually in the TOC, so we can allow
      FP constants.  */
-  if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == TFmode)
+  if (GET_CODE (x) == CONST_DOUBLE &&
+      (GET_MODE (x) == TFmode || GET_MODE (x) == TDmode))
     {
       REAL_VALUE_TYPE rv;
       long k[4];
 
       REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
-      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
+       REAL_VALUE_TO_TARGET_DECIMAL128 (rv, k);
+      else
+       REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
 
       if (TARGET_64BIT)
        {
@@ -15674,13 +15899,18 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
          return;
        }
     }
-  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
+  else if (GET_CODE (x) == CONST_DOUBLE &&
+          (GET_MODE (x) == DFmode || GET_MODE (x) == DDmode))
     {
       REAL_VALUE_TYPE rv;
       long k[2];
 
       REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
-      REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
+
+      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
+       REAL_VALUE_TO_TARGET_DECIMAL64 (rv, k);
+      else
+       REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
 
       if (TARGET_64BIT)
        {
@@ -15705,13 +15935,17 @@ output_toc (FILE *file, rtx x, int labelno, enum machine_mode mode)
          return;
        }
     }
-  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
+  else if (GET_CODE (x) == CONST_DOUBLE &&
+          (GET_MODE (x) == SFmode || GET_MODE (x) == SDmode))
     {
       REAL_VALUE_TYPE rv;
       long l;
 
       REAL_VALUE_FROM_CONST_DOUBLE (rv, x);
-      REAL_VALUE_TO_TARGET_SINGLE (rv, l);
+      if (DECIMAL_FLOAT_MODE_P (GET_MODE (x)))
+       REAL_VALUE_TO_TARGET_DECIMAL32 (rv, l);
+      else
+       REAL_VALUE_TO_TARGET_SINGLE (rv, l);
 
       if (TARGET_64BIT)
        {
@@ -17082,9 +17316,8 @@ rs6000_trampoline_size (void)
 void
 rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
 {
-  enum machine_mode pmode = Pmode;
   int regsize = (TARGET_32BIT) ? 4 : 8;
-  rtx ctx_reg = force_reg (pmode, cxt);
+  rtx ctx_reg = force_reg (Pmode, cxt);
 
   switch (DEFAULT_ABI)
     {
@@ -17092,15 +17325,15 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
       gcc_unreachable ();
 
 /* Macros to shorten the code expansions below.  */
-#define MEM_DEREF(addr) gen_rtx_MEM (pmode, memory_address (pmode, addr))
+#define MEM_DEREF(addr) gen_rtx_MEM (Pmode, memory_address (Pmode, addr))
 #define MEM_PLUS(addr,offset) \
-  gen_rtx_MEM (pmode, memory_address (pmode, plus_constant (addr, offset)))
+  gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (addr, offset)))
 
     /* Under AIX, just build the 3 word function descriptor */
     case ABI_AIX:
       {
-       rtx fn_reg = gen_reg_rtx (pmode);
-       rtx toc_reg = gen_reg_rtx (pmode);
+       rtx fn_reg = gen_reg_rtx (Pmode);
+       rtx toc_reg = gen_reg_rtx (Pmode);
        emit_move_insn (fn_reg, MEM_DEREF (fnaddr));
        emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize));
        emit_move_insn (MEM_DEREF (addr), fn_reg);
@@ -17112,12 +17345,12 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
     /* Under V.4/eabi/darwin, __trampoline_setup does the real work.  */
     case ABI_DARWIN:
     case ABI_V4:
-      emit_library_call (gen_rtx_SYMBOL_REF (SImode, "__trampoline_setup"),
+      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__trampoline_setup"),
                         FALSE, VOIDmode, 4,
-                        addr, pmode,
+                        addr, Pmode,
                         GEN_INT (rs6000_trampoline_size ()), SImode,
-                        fnaddr, pmode,
-                        ctx_reg, pmode);
+                        fnaddr, Pmode,
+                        ctx_reg, Pmode);
       break;
     }
 
@@ -17133,6 +17366,8 @@ const struct attribute_spec rs6000_attribute_table[] =
   { "altivec",   1, 1, false, true,  false, rs6000_handle_altivec_attribute },
   { "longcall",  0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
   { "shortcall", 0, 0, false, true,  true,  rs6000_handle_longcall_attribute },
+  { "ms_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
+  { "gcc_struct", 0, 0, false, false, false, rs6000_handle_struct_attribute },
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
   SUBTARGET_ATTRIBUTE_TABLE,
 #endif
@@ -17192,6 +17427,8 @@ rs6000_handle_altivec_attribute (tree *node,
     error ("use of boolean types in AltiVec types is invalid");
   else if (TREE_CODE (type) == COMPLEX_TYPE)
     error ("use of %<complex%> in AltiVec types is invalid");
+  else if (DECIMAL_FLOAT_MODE_P (mode))
+    error ("use of decimal floating point types in AltiVec types is invalid");
 
   switch (altivec_type)
     {
@@ -17257,6 +17494,14 @@ rs6000_mangle_fundamental_type (tree type)
   if (type == pixel_type_node) return "u7__pixel";
   if (type == bool_int_type_node) return "U6__booli";
 
+  /* Mangle IBM extended float long double as `g' (__float128) on
+     powerpc*-linux where long-double-64 previously was the default.  */
+  if (TYPE_MAIN_VARIANT (type) == long_double_type_node
+      && TARGET_ELF
+      && TARGET_LONG_DOUBLE_128
+      && !TARGET_IEEEQUAD)
+    return "g";
+
   /* For all other types, use normal C++ mangling.  */
   return NULL;
 }
@@ -17293,6 +17538,10 @@ rs6000_set_default_type_attributes (tree type)
     TYPE_ATTRIBUTES (type) = tree_cons (get_identifier ("longcall"),
                                        NULL_TREE,
                                        TYPE_ATTRIBUTES (type));
+
+#if TARGET_MACHO
+  darwin_set_default_type_attributes (type);
+#endif
 }
 
 /* Return a reference suitable for calling a function with the
@@ -17321,33 +17570,124 @@ rs6000_longcall_ref (rtx call_ref)
   return force_reg (Pmode, call_ref);
 }
 \f
+#ifndef TARGET_USE_MS_BITFIELD_LAYOUT
+#define TARGET_USE_MS_BITFIELD_LAYOUT 0
+#endif
+
+/* Handle a "ms_struct" or "gcc_struct" attribute; arguments as in
+   struct attribute_spec.handler.  */
+static tree
+rs6000_handle_struct_attribute (tree *node, tree name,
+                               tree args ATTRIBUTE_UNUSED,
+                               int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  tree *type = NULL;
+  if (DECL_P (*node))
+    {
+      if (TREE_CODE (*node) == TYPE_DECL)
+        type = &TREE_TYPE (*node);
+    }
+  else
+    type = node;
+
+  if (!(type && (TREE_CODE (*type) == RECORD_TYPE
+                 || TREE_CODE (*type) == UNION_TYPE)))
+    {
+      warning (OPT_Wattributes, "%qs attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  else if ((is_attribute_p ("ms_struct", name)
+            && lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (*type)))
+           || ((is_attribute_p ("gcc_struct", name)
+                && lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (*type)))))
+    {
+      warning (OPT_Wattributes, "%qs incompatible attribute ignored",
+               IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+static bool
+rs6000_ms_bitfield_layout_p (tree record_type)
+{
+  return (TARGET_USE_MS_BITFIELD_LAYOUT &&
+          !lookup_attribute ("gcc_struct", TYPE_ATTRIBUTES (record_type)))
+    || lookup_attribute ("ms_struct", TYPE_ATTRIBUTES (record_type));
+}
+\f
 #ifdef USING_ELFOS_H
 
-/* A C statement or statements to switch to the appropriate section
-   for output of RTX in mode MODE.  You can assume that RTX is some
-   kind of constant in RTL.  The argument MODE is redundant except in
-   the case of a `const_int' rtx.  Select the section by calling
-   `text_section' or one of the alternatives for other sections.
+/* A get_unnamed_section callback, used for switching to toc_section.  */
+
+static void
+rs6000_elf_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+{
+  if (DEFAULT_ABI == ABI_AIX
+      && TARGET_MINIMAL_TOC
+      && !TARGET_RELOCATABLE)
+    {
+      if (!toc_initialized)
+       {
+         toc_initialized = 1;
+         fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
+         (*targetm.asm_out.internal_label) (asm_out_file, "LCTOC", 0);
+         fprintf (asm_out_file, "\t.tc ");
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1[TC],");
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
+         fprintf (asm_out_file, "\n");
+
+         fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
+         fprintf (asm_out_file, " = .+32768\n");
+       }
+      else
+       fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
+    }
+  else if (DEFAULT_ABI == ABI_AIX && !TARGET_RELOCATABLE)
+    fprintf (asm_out_file, "%s\n", TOC_SECTION_ASM_OP);
+  else
+    {
+      fprintf (asm_out_file, "%s\n", MINIMAL_TOC_SECTION_ASM_OP);
+      if (!toc_initialized)
+       {
+         ASM_OUTPUT_INTERNAL_LABEL_PREFIX (asm_out_file, "LCTOC1");
+         fprintf (asm_out_file, " = .+32768\n");
+         toc_initialized = 1;
+       }
+    }
+}
 
-   Do not define this macro if you put all constants in the read-only
-   data section.  */
+/* Implement TARGET_ASM_INIT_SECTIONS.  */
 
 static void
+rs6000_elf_asm_init_sections (void)
+{
+  toc_section
+    = get_unnamed_section (0, rs6000_elf_output_toc_section_asm_op, NULL);
+
+  sdata2_section
+    = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+                          SDATA2_SECTION_ASM_OP);
+}
+
+/* Implement TARGET_SELECT_RTX_SECTION.  */
+
+static section *
 rs6000_elf_select_rtx_section (enum machine_mode mode, rtx x,
                               unsigned HOST_WIDE_INT align)
 {
   if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
-    toc_section ();
+    return toc_section;
   else
-    default_elf_select_rtx_section (mode, x, align);
+    return default_elf_select_rtx_section (mode, x, align);
 }
 
-/* A C statement or statements to switch to the appropriate
-   section for output of DECL.  DECL is either a `VAR_DECL' node
-   or a constant of some sort.  RELOC indicates whether forming
-   the initial value of DECL requires link-time relocations.  */
+/* Implement TARGET_ASM_SELECT_SECTION for ELF targets.  */
 
-static void
+static section *
 rs6000_elf_select_section (tree decl, int reloc,
                           unsigned HOST_WIDE_INT align)
 {
@@ -17355,8 +17695,8 @@ rs6000_elf_select_section (tree decl, int reloc,
      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.  */
-  default_elf_select_section_1 (decl, reloc, align,
-                               flag_pic || DEFAULT_ABI == ABI_AIX);
+  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
@@ -17444,7 +17784,14 @@ rs6000_elf_in_small_data_p (tree decl)
 }
 
 #endif /* USING_ELFOS_H */
+\f
+/* Implement TARGET_USE_BLOCKS_FOR_CONSTANT_P.  */
 
+static bool
+rs6000_use_blocks_for_constant_p (enum machine_mode mode, rtx x)
+{
+  return !ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode);
+}
 \f
 /* Return a REG that occurs in ADDR with coefficient 1.
    ADDR can be effectively incremented by incrementing REG.
@@ -17678,9 +18025,9 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
   GEN_LAZY_PTR_NAME_FOR_SYMBOL (lazy_ptr_name, symb, length);
 
   if (flag_pic == 2)
-    machopic_picsymbol_stub1_section ();
+    switch_to_section (darwin_sections[machopic_picsymbol_stub1_section]);
   else
-    machopic_symbol_stub1_section ();
+    switch_to_section (darwin_sections[machopic_symbol_stub1_section]);
 
   if (flag_pic == 2)
     {
@@ -17720,7 +18067,7 @@ machopic_output_stub (FILE *file, const char *symb, const char *stub)
       fprintf (file, "\tbctr\n");
     }
 
-  machopic_lazy_symbol_ptr_section ();
+  switch_to_section (darwin_sections[machopic_lazy_symbol_ptr_section]);
   fprintf (file, "%s:\n", lazy_ptr_name);
   fprintf (file, "\t.indirect_symbol %s\n", symbol_name);
   fprintf (file, "%sdyld_stub_binding_helper\n",
@@ -17781,16 +18128,6 @@ rs6000_machopic_legitimize_pic_address (rtx orig, enum machine_mode mode,
   return machopic_legitimize_pic_address (orig, mode, reg);
 }
 
-/* This is just a placeholder to make linking work without having to
-   add this to the generic Darwin EXTRA_SECTIONS.  If -mcall-aix is
-   ever needed for Darwin (not too likely!) this would have to get a
-   real definition.  */
-
-void
-toc_section (void)
-{
-}
-
 /* Output a .machine directive for the Darwin assembler, and call
    the generic start_file routine.  */
 
@@ -17823,6 +18160,7 @@ rs6000_darwin_file_start (void)
   size_t i;
 
   rs6000_file_start ();
+  darwin_file_start ();
 
   /* Determine the argument to -mcpu=.  Default to G3 if not specified.  */
   for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
@@ -17876,7 +18214,7 @@ rs6000_elf_asm_out_constructor (rtx symbol, int priority)
       section = buf;
     }
 
-  named_section_flags (section, SECTION_WRITE);
+  switch_to_section (get_section (section, SECTION_WRITE, NULL));
   assemble_align (POINTER_SIZE);
 
   if (TARGET_RELOCATABLE)
@@ -17905,7 +18243,7 @@ rs6000_elf_asm_out_destructor (rtx symbol, int priority)
       section = buf;
     }
 
-  named_section_flags (section, SECTION_WRITE);
+  switch_to_section (get_section (section, SECTION_WRITE, NULL));
   assemble_align (POINTER_SIZE);
 
   if (TARGET_RELOCATABLE)
@@ -18004,6 +18342,16 @@ rs6000_elf_end_indicate_exec_stack (void)
 
 #if TARGET_XCOFF
 static void
+rs6000_xcoff_asm_output_anchor (rtx symbol)
+{
+  char buffer[100];
+
+  sprintf (buffer, "$ + " HOST_WIDE_INT_PRINT_DEC,
+          SYMBOL_REF_BLOCK_OFFSET (symbol));
+  ASM_OUTPUT_DEF (asm_out_file, XSTR (symbol, 0), buffer);
+}
+
+static void
 rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
 {
   fputs (GLOBAL_ASM_OP, stream);
@@ -18011,6 +18359,73 @@ rs6000_xcoff_asm_globalize_label (FILE *stream, const char *name)
   putc ('\n', stream);
 }
 
+/* A get_unnamed_decl callback, used for read-only sections.  PTR
+   points to the section string variable.  */
+
+static void
+rs6000_xcoff_output_readonly_section_asm_op (const void *directive)
+{
+  fprintf (asm_out_file, "\t.csect %s[RO],3\n",
+          *(const char *const *) directive);
+}
+
+/* Likewise for read-write sections.  */
+
+static void
+rs6000_xcoff_output_readwrite_section_asm_op (const void *directive)
+{
+  fprintf (asm_out_file, "\t.csect %s[RW],3\n",
+          *(const char *const *) directive);
+}
+
+/* A get_unnamed_section callback, used for switching to toc_section.  */
+
+static void
+rs6000_xcoff_output_toc_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+{
+  if (TARGET_MINIMAL_TOC)
+    {
+      /* toc_section is always selected at least once from
+        rs6000_xcoff_file_start, so this is guaranteed to
+        always be defined once and only once in each file.  */
+      if (!toc_initialized)
+       {
+         fputs ("\t.toc\nLCTOC..1:\n", asm_out_file);
+         fputs ("\t.tc toc_table[TC],toc_table[RW]\n", asm_out_file);
+         toc_initialized = 1;
+       }
+      fprintf (asm_out_file, "\t.csect toc_table[RW]%s\n",
+              (TARGET_32BIT ? "" : ",3"));
+    }
+  else
+    fputs ("\t.toc\n", asm_out_file);
+}
+
+/* Implement TARGET_ASM_INIT_SECTIONS.  */
+
+static void
+rs6000_xcoff_asm_init_sections (void)
+{
+  read_only_data_section
+    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
+                          &xcoff_read_only_section_name);
+
+  private_data_section
+    = get_unnamed_section (SECTION_WRITE,
+                          rs6000_xcoff_output_readwrite_section_asm_op,
+                          &xcoff_private_data_section_name);
+
+  read_only_private_data_section
+    = get_unnamed_section (0, rs6000_xcoff_output_readonly_section_asm_op,
+                          &xcoff_private_data_section_name);
+
+  toc_section
+    = get_unnamed_section (0, rs6000_xcoff_output_toc_section_asm_op, NULL);
+
+  readonly_data_section = read_only_data_section;
+  exception_section = data_section;
+}
+
 static void
 rs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
                                tree decl ATTRIBUTE_UNUSED)
@@ -18030,23 +18445,23 @@ rs6000_xcoff_asm_named_section (const char *name, unsigned int flags,
           name, suffix[smclass], flags & SECTION_ENTSIZE);
 }
 
-static void
+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 (TREE_PUBLIC (decl))
-       read_only_data_section ();
+       return read_only_data_section;
       else
-       read_only_private_data_section ();
+       return read_only_private_data_section;
     }
   else
     {
       if (TREE_PUBLIC (decl))
-       data_section ();
+       return data_section;
       else
-       private_data_section ();
+       return private_data_section;
     }
 }
 
@@ -18075,14 +18490,14 @@ rs6000_xcoff_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
    However, if this is being placed in the TOC it must be output as a
    toc entry.  */
 
-static void
+static section *
 rs6000_xcoff_select_rtx_section (enum machine_mode mode, rtx x,
                                 unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
   if (ASM_OUTPUT_SPECIAL_POOL_ENTRY_P (x, mode))
-    toc_section ();
+    return toc_section;
   else
-    read_only_private_data_section ();
+    return read_only_private_data_section;
 }
 
 /* Remove any trailing [DS] or the like from the symbol name.  */
@@ -18146,8 +18561,8 @@ rs6000_xcoff_file_start (void)
   output_quoted_string (asm_out_file, main_input_filename);
   fputc ('\n', asm_out_file);
   if (write_symbols != NO_DEBUG)
-    private_data_section ();
-  text_section ();
+    switch_to_section (private_data_section);
+  switch_to_section (text_section);
   if (profile_flag)
     fprintf (asm_out_file, "\t.extern %s\n", RS6000_MCOUNT);
   rs6000_file_start ();
@@ -18159,9 +18574,9 @@ rs6000_xcoff_file_start (void)
 static void
 rs6000_xcoff_file_end (void)
 {
-  text_section ();
+  switch_to_section (text_section);
   fputs ("_section_.text:\n", asm_out_file);
-  data_section ();
+  switch_to_section (data_section);
   fputs (TARGET_32BIT
         ? "\t.long _section_.text\n" : "\t.llong _section_.text\n",
         asm_out_file);
@@ -18184,19 +18599,21 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
       if (((outer_code == SET
            || outer_code == PLUS
            || outer_code == MINUS)
-          && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
-              || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')))
+          && (satisfies_constraint_I (x)
+              || satisfies_constraint_L (x)))
          || (outer_code == AND
-             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
-                                            mode == SImode ? 'L' : 'J'))
+             && (satisfies_constraint_K (x)
+                 || (mode == SImode
+                     ? satisfies_constraint_L (x)
+                     : satisfies_constraint_J (x))
                  || mask_operand (x, mode)
                  || (mode == DImode
                      && mask64_operand (x, DImode))))
          || ((outer_code == IOR || outer_code == XOR)
-             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
-                                            mode == SImode ? 'L' : 'J'))))
+             && (satisfies_constraint_K (x)
+                 || (mode == SImode
+                     ? satisfies_constraint_L (x)
+                     : satisfies_constraint_J (x))))
          || outer_code == ASHIFT
          || outer_code == ASHIFTRT
          || outer_code == LSHIFTRT
@@ -18204,22 +18621,23 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
          || outer_code == ROTATERT
          || outer_code == ZERO_EXTRACT
          || (outer_code == MULT
-             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+             && satisfies_constraint_I (x))
          || ((outer_code == DIV || outer_code == UDIV
               || outer_code == MOD || outer_code == UMOD)
              && exact_log2 (INTVAL (x)) >= 0)
          || (outer_code == COMPARE
-             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
-                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')))
+             && (satisfies_constraint_I (x)
+                 || satisfies_constraint_K (x)))
          || (outer_code == EQ
-             && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'I')
-                 || CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                 || (CONST_OK_FOR_LETTER_P (INTVAL (x),
-                                            mode == SImode ? 'L' : 'J'))))
+             && (satisfies_constraint_I (x)
+                 || satisfies_constraint_K (x)
+                 || (mode == SImode
+                     ? satisfies_constraint_L (x)
+                     : satisfies_constraint_J (x))))
          || (outer_code == GTU
-             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'I'))
+             && satisfies_constraint_I (x))
          || (outer_code == LTU
-             && CONST_OK_FOR_LETTER_P (INTVAL (x), 'P')))
+             && satisfies_constraint_P (x)))
        {
          *total = 0;
          return true;
@@ -18240,28 +18658,25 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
       /* FALLTHRU */
 
     case CONST_DOUBLE:
-      if (mode == DImode
-         && ((outer_code == AND
-              && (CONST_OK_FOR_LETTER_P (INTVAL (x), 'K')
-                  || CONST_OK_FOR_LETTER_P (INTVAL (x), 'L')
-                  || mask_operand (x, DImode)
-                  || mask64_operand (x, DImode)))
-             || ((outer_code == IOR || outer_code == XOR)
-                 && CONST_DOUBLE_HIGH (x) == 0
-                 && (CONST_DOUBLE_LOW (x)
-                     & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)))
+      if (mode == DImode && code == CONST_DOUBLE)
        {
-         *total = 0;
-         return true;
-       }
-      else if (mode == DImode
-              && (outer_code == SET
-                  || outer_code == IOR
-                  || outer_code == XOR)
-              && CONST_DOUBLE_HIGH (x) == 0)
-       {
-         *total = COSTS_N_INSNS (1);
-         return true;
+         if ((outer_code == IOR || outer_code == XOR)
+             && CONST_DOUBLE_HIGH (x) == 0
+             && (CONST_DOUBLE_LOW (x)
+                 & ~ (unsigned HOST_WIDE_INT) 0xffff) == 0)
+           {
+             *total = 0;
+             return true;
+           }
+         else if ((outer_code == AND && and64_2_operand (x, DImode))
+                  || ((outer_code == SET
+                       || outer_code == IOR
+                       || outer_code == XOR)
+                      && CONST_DOUBLE_HIGH (x) == 0))
+           {
+             *total = COSTS_N_INSNS (1);
+             return true;
+           }
        }
       /* FALLTHRU */
 
@@ -18333,7 +18748,7 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total)
 
     case MULT:
       if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (x, 1)), 'I'))
+         && satisfies_constraint_I (XEXP (x, 1)))
        {
          if (INTVAL (XEXP (x, 1)) >= -256
              && INTVAL (XEXP (x, 1)) <= 255)
@@ -18796,6 +19211,7 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
                                                   GP_ARG_RETURN + 3),
                                      GEN_INT (12))));
     }
+
   if ((INTEGRAL_TYPE_P (valtype)
        && TYPE_PRECISION (valtype) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
@@ -18803,7 +19219,9 @@ rs6000_function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
   else
     mode = TYPE_MODE (valtype);
 
-  if (SCALAR_FLOAT_TYPE_P (valtype) && TARGET_HARD_FLOAT && TARGET_FPRS)
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    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
           && targetm.calls.split_complex_arg)
@@ -18842,7 +19260,9 @@ rs6000_libcall_value (enum machine_mode mode)
                                      GEN_INT (4))));
     }
 
-  if (SCALAR_FLOAT_MODE_P (mode)
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    regno = GP_ARG_RETURN;
+  else if (SCALAR_FLOAT_MODE_P (mode)
           && TARGET_HARD_FLOAT && TARGET_FPRS)
     regno = FP_ARG_RETURN;
   else if (ALTIVEC_VECTOR_MODE (mode)
@@ -18970,6 +19390,16 @@ rs6000_eh_return_filter_mode (void)
   return TARGET_32BIT ? SImode : word_mode;
 }
 
+/* Target hook for scalar_mode_supported_p.  */
+static bool
+rs6000_scalar_mode_supported_p (enum machine_mode mode)
+{
+  if (DECIMAL_FLOAT_MODE_P (mode))
+    return true;
+  else
+    return default_scalar_mode_supported_p (mode);
+}
+
 /* Target hook for vector_mode_supported_p.  */
 static bool
 rs6000_vector_mode_supported_p (enum machine_mode mode)