OSDN Git Service

* hooks.h (hook_tree_tree_tree_bool_null): Rename to...
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 6715437..9f9e20b 100644 (file)
@@ -1,6 +1,7 @@
 /* Subroutines for insn-output.c for SPARC.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
    at Cygnus Support.
@@ -9,7 +10,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -18,9 +19,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -48,8 +48,11 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 #include "cfglayout.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "langhooks.h"
+#include "params.h"
+#include "df.h"
+#include "dwarf2out.h"
 
 /* Processor costs */
 static const
@@ -196,6 +199,54 @@ struct processor_costs ultrasparc3_costs = {
   0, /* shift penalty */
 };
 
+static const
+struct processor_costs niagara_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (9), /* float load */
+  COSTS_N_INSNS (8), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (8), /* fadd, fsub */
+  COSTS_N_INSNS (26), /* fcmp */
+  COSTS_N_INSNS (8), /* fmov, fmovr */
+  COSTS_N_INSNS (29), /* fmul */
+  COSTS_N_INSNS (54), /* fdivs */
+  COSTS_N_INSNS (83), /* fdivd */
+  COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */
+  COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */
+  COSTS_N_INSNS (11), /* imul */
+  COSTS_N_INSNS (11), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (72), /* idiv */
+  COSTS_N_INSNS (72), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs niagara2_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (3), /* float load */
+  COSTS_N_INSNS (6), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (6), /* fadd, fsub */
+  COSTS_N_INSNS (6), /* fcmp */
+  COSTS_N_INSNS (6), /* fmov, fmovr */
+  COSTS_N_INSNS (6), /* fmul */
+  COSTS_N_INSNS (19), /* fdivs */
+  COSTS_N_INSNS (33), /* fdivd */
+  COSTS_N_INSNS (19), /* fsqrts */
+  COSTS_N_INSNS (33), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (31), /* idiv, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (31), /* idivX, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
 const struct processor_costs *sparc_costs = &cypress_costs;
 
 #ifdef HAVE_AS_RELAX_OPTION
@@ -225,14 +276,10 @@ static HOST_WIDE_INT actual_fsize;
 static int num_gfregs;
 
 /* The alias set for prologue/epilogue register save/restore.  */
-static GTY(()) int sparc_sr_alias_set;
+static GTY(()) alias_set_type sparc_sr_alias_set;
 
 /* The alias set for the structure return value.  */
-static GTY(()) int struct_value_alias_set;
-
-/* Save the operands last given to a compare for use when we
-   generate a scc or bcc insn.  */
-rtx sparc_compare_op0, sparc_compare_op1;
+static GTY(()) alias_set_type struct_value_alias_set;
 
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
@@ -271,7 +318,7 @@ char sparc_leaf_regs[] =
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1};
 
-struct machine_function GTY(())
+struct GTY(()) machine_function
 {
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
@@ -311,21 +358,18 @@ static int hypersparc_adjust_cost (rtx, rtx, rtx, int);
 static void sparc_output_addr_vec (rtx);
 static void sparc_output_addr_diff_vec (rtx);
 static void sparc_output_deferred_case_vectors (void);
+static bool sparc_legitimate_address_p (enum machine_mode, rtx, bool);
 static rtx sparc_builtin_saveregs (void);
 static int epilogue_renumber (rtx *, int);
 static bool sparc_assemble_integer (rtx, unsigned int, int);
 static int set_extends (rtx);
-static void emit_pic_helper (void);
-static void load_pic_register (bool);
+static void load_pic_register (void);
 static int save_or_restore_regs (int, int, rtx, int, int);
-static void emit_save_regs (void);
-static void emit_restore_regs (void);
+static void emit_save_or_restore_regs (int);
 static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
 static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
-#ifdef OBJECT_FORMAT_ELF
-static void sparc_elf_asm_named_section (const char *, unsigned int, tree);
-#endif
-
+static void sparc_solaris_elf_asm_named_section (const char *, unsigned int,
+                                                tree) ATTRIBUTE_UNUSED;
 static int sparc_adjust_cost (rtx, rtx, rtx, int);
 static int sparc_issue_rate (void);
 static void sparc_sched_init (FILE *, int, int);
@@ -342,38 +386,59 @@ static void sparc_init_libfuncs (void);
 static void sparc_init_builtins (void);
 static void sparc_vis_init_builtins (void);
 static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static tree sparc_fold_builtin (tree, int, tree *, bool);
+static int sparc_vis_mul8x16 (int, int);
+static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree);
 static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                   HOST_WIDE_INT, tree);
-static bool sparc_can_output_mi_thunk (tree, HOST_WIDE_INT,
-                                      HOST_WIDE_INT, tree);
+static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
+                                      HOST_WIDE_INT, const_tree);
 static struct machine_function * sparc_init_machine_status (void);
 static bool sparc_cannot_force_const_mem (rtx);
 static rtx sparc_tls_get_addr (void);
 static rtx sparc_tls_got (void);
 static const char *get_some_local_dynamic_name (void);
 static int get_some_local_dynamic_name_1 (rtx *, void *);
-static bool sparc_rtx_costs (rtx, int, int, int *);
-static bool sparc_promote_prototypes (tree);
+static bool sparc_rtx_costs (rtx, int, int, int *, bool);
+static bool sparc_promote_prototypes (const_tree);
 static rtx sparc_struct_value_rtx (tree, int);
-static bool sparc_return_in_memory (tree, tree);
+static enum machine_mode sparc_promote_function_mode (const_tree, enum machine_mode,
+                                                     int *, const_tree, int);
+static bool sparc_return_in_memory (const_tree, const_tree);
 static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
-static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static void sparc_va_start (tree, rtx);
+static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
 static bool sparc_vector_mode_supported_p (enum machine_mode);
+static bool sparc_tls_referenced_p (rtx);
+static rtx legitimize_tls_address (rtx);
+static rtx legitimize_pic_address (rtx, rtx);
+static rtx sparc_legitimize_address (rtx, rtx, enum machine_mode);
 static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
-                                    enum machine_mode, tree, bool);
+                                    enum machine_mode, const_tree, bool);
 static int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
                                    enum machine_mode, tree, bool);
 static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 static void sparc_file_end (void);
+static bool sparc_frame_pointer_required (void);
+static bool sparc_can_eliminate (const int, const int);
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+static const char *sparc_mangle_type (const_tree);
+#endif
+static void sparc_trampoline_init (rtx, tree, rtx);
+\f
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
-const struct attribute_spec sparc_attribute_table[];
+/* Table of valid machine attributes.  */
+static const struct attribute_spec sparc_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  SUBTARGET_ATTRIBUTE_TABLE,
+  { NULL,        0, 0, false, false, false, NULL }
+};
 #endif
 \f
 /* Option handling.  */
 
-/* Code model option as passed by user.  */
-const char *sparc_cmodel_string;
-
 /* Parsed value.  */
 enum cmodel sparc_cmodel;
 
@@ -396,14 +461,9 @@ static bool fpu_option_set = false;
 
 /* Initialize the GCC target structure.  */
 
-/* The sparc default is to use .half rather than .short for aligned
-   HI objects.  Use .word instead of .long on non-ELF systems.  */
+/* The default is to use .half rather than .short for aligned HI objects.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
-#ifndef OBJECT_FORMAT_ELF
-#undef TARGET_ASM_ALIGNED_SI_OP
-#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
-#endif
 
 #undef TARGET_ASM_UNALIGNED_HI_OP
 #define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t"
@@ -438,13 +498,19 @@ static bool fpu_option_set = false;
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS sparc_init_builtins
 
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS sparc_legitimize_address
+
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN sparc_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN sparc_fold_builtin
 
-#ifdef HAVE_AS_TLS
+#if TARGET_TLS
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS true
 #endif
+
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
 
@@ -456,19 +522,10 @@ static bool fpu_option_set = false;
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS sparc_rtx_costs
 #undef TARGET_ADDRESS_COST
-#define TARGET_ADDRESS_COST hook_int_rtx_0
-
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
-   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
-   test for this value.  */
-#undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
 
-/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
-   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
-   test for this value.  */
-#undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE sparc_promote_function_mode
 
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
@@ -489,6 +546,8 @@ static bool fpu_option_set = false;
 #undef TARGET_STRICT_ARGUMENT_NAMING
 #define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
 
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
 
@@ -516,9 +575,31 @@ static bool fpu_option_set = false;
 #undef TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION sparc_handle_option
 
+#if TARGET_GNU_TLS && defined(HAVE_AS_SPARC_UA_PCREL)
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
+#endif
+
 #undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END sparc_file_end
 
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE sparc_can_eliminate
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE sparc_mangle_type
+#endif
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P sparc_legitimate_address_p
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT sparc_trampoline_init
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Implement TARGET_HANDLE_OPTION.  */
@@ -541,10 +622,6 @@ sparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
     case OPT_mtune_:
       sparc_select[2].string = arg;
       break;
-
-    case OPT_mcmodel_:
-      sparc_cmodel_string = arg;
-      break;
     }
 
   return true;
@@ -558,14 +635,14 @@ sparc_override_options (void)
 {
   static struct code_model {
     const char *const name;
-    const int value;
+    const enum cmodel value;
   } const cmodels[] = {
     { "32", CM_32 },
     { "medlow", CM_MEDLOW },
     { "medmid", CM_MEDMID },
     { "medany", CM_MEDANY },
     { "embmedany", CM_EMBMEDANY },
-    { 0, 0 }
+    { NULL, (enum cmodel) 0 }
   };
   const struct code_model *cmodel;
   /* Map TARGET_CPU_DEFAULT to value for -m{arch,tune}=.  */
@@ -584,6 +661,8 @@ sparc_override_options (void)
     { TARGET_CPU_v9, "v9" },
     { TARGET_CPU_ultrasparc, "ultrasparc" },
     { TARGET_CPU_ultrasparc3, "ultrasparc3" },
+    { TARGET_CPU_niagara, "niagara" },
+    { TARGET_CPU_niagara2, "niagara2" },
     { 0, 0 }
   };
   const struct cpu_default *def;
@@ -619,12 +698,15 @@ sparc_override_options (void)
     /* TI ultrasparc III */
     /* ??? Check if %y issue still holds true in ultra3.  */
     { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
-    { 0, 0, 0, 0 }
+    /* UltraSPARC T1 */
+    { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+    { "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9},
+    { 0, (enum processor_type) 0, 0, 0 }
   };
   const struct cpu_table *cpu;
   const struct sparc_cpu_select *sel;
   int fpu;
-  
+
 #ifndef SPARC_BI_ARCH
   /* Check for unsupported architecture size.  */
   if (! TARGET_64BIT != DEFAULT_ARCH32_P)
@@ -641,7 +723,7 @@ sparc_override_options (void)
 
   /* Code model selection.  */
   sparc_cmodel = SPARC_DEFAULT_CMODEL;
-  
+
 #ifdef SPARC_BI_ARCH
   if (TARGET_ARCH32)
     sparc_cmodel = CM_32;
@@ -663,7 +745,7 @@ sparc_override_options (void)
        error ("-mcmodel= is not supported on 32 bit systems");
     }
 
-  fpu = TARGET_FPU; /* save current -mfpu status */
+  fpu = target_flags & MASK_FPU; /* save current -mfpu status */
 
   /* Set the default CPU.  */
   for (def = &cpu_default[0]; def->name; ++def)
@@ -724,11 +806,13 @@ sparc_override_options (void)
   /* Don't use stack biasing in 32 bit mode.  */
   if (TARGET_ARCH32)
     target_flags &= ~MASK_STACK_BIAS;
-    
+
   /* Supply a default value for align_functions.  */
   if (align_functions == 0
       && (sparc_cpu == PROCESSOR_ULTRASPARC
-         || sparc_cpu == PROCESSOR_ULTRASPARC3))
+         || sparc_cpu == PROCESSOR_ULTRASPARC3
+         || sparc_cpu == PROCESSOR_NIAGARA
+         || sparc_cpu == PROCESSOR_NIAGARA2))
     align_functions = 32;
 
   /* Validate PCC_STRUCT_RETURN.  */
@@ -777,18 +861,35 @@ sparc_override_options (void)
     case PROCESSOR_ULTRASPARC3:
       sparc_costs = &ultrasparc3_costs;
       break;
+    case PROCESSOR_NIAGARA:
+      sparc_costs = &niagara_costs;
+      break;
+    case PROCESSOR_NIAGARA2:
+      sparc_costs = &niagara2_costs;
+      break;
     };
-}
-\f
-#ifdef SUBTARGET_ATTRIBUTE_TABLE
-/* Table of valid machine attributes.  */
-const struct attribute_spec sparc_attribute_table[] =
-{
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  SUBTARGET_ATTRIBUTE_TABLE,
-  { NULL,        0, 0, false, false, false, NULL }
-};
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+    target_flags |= MASK_LONG_DOUBLE_128;
 #endif
+
+  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
+    set_param_value ("simultaneous-prefetches",
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 2
+                     : (sparc_cpu == PROCESSOR_ULTRASPARC3
+                        ? 8 : 3)));
+  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
+    set_param_value ("l1-cache-line-size",
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_ULTRASPARC3
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 64 : 32));
+}
 \f
 /* Miscellaneous utilities.  */
 
@@ -802,9 +903,6 @@ v9_regcmp_p (enum rtx_code code)
          || code == LE || code == GT);
 }
 
-\f
-/* Operand constraints.  */
-
 /* Nonzero if OP is a floating point constant which can
    be loaded into an integer register using a single
    sethi instruction.  */
@@ -868,19 +966,139 @@ fp_high_losum_p (rtx op)
   return 0;
 }
 
-/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
-   otherwise return 0.  */
+/* Expand a move instruction.  Return true if all work is done.  */
 
-int
-tls_symbolic_operand (rtx op)
+bool
+sparc_expand_move (enum machine_mode mode, rtx *operands)
 {
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
-  return SYMBOL_REF_TLS_MODEL (op);
+  /* Handle sets of MEM first.  */
+  if (GET_CODE (operands[0]) == MEM)
+    {
+      /* 0 is a register (or a pair of registers) on SPARC.  */
+      if (register_or_zero_operand (operands[1], mode))
+       return false;
+
+      if (!reload_in_progress)
+       {
+         operands[0] = validize_mem (operands[0]);
+         operands[1] = force_reg (mode, operands[1]);
+       }
+    }
+
+  /* Fixup TLS cases.  */
+  if (TARGET_HAVE_TLS
+      && CONSTANT_P (operands[1])
+      && sparc_tls_referenced_p (operands [1]))
+    {
+      operands[1] = legitimize_tls_address (operands[1]);
+      return false;
+    }
+
+  /* Fixup PIC cases.  */
+  if (flag_pic && CONSTANT_P (operands[1]))
+    {
+      if (pic_address_needs_scratch (operands[1]))
+       operands[1] = legitimize_pic_address (operands[1], NULL_RTX);
+
+      /* VxWorks does not impose a fixed gap between segments; the run-time
+        gap can be different from the object-file gap.  We therefore can't
+        assume X - _GLOBAL_OFFSET_TABLE_ is a link-time constant unless we
+        are absolutely sure that X is in the same segment as the GOT.
+        Unfortunately, the flexibility of linker scripts means that we
+        can't be sure of that in general, so assume that _G_O_T_-relative
+        accesses are never valid on VxWorks.  */
+      if (GET_CODE (operands[1]) == LABEL_REF && !TARGET_VXWORKS_RTP)
+       {
+         if (mode == SImode)
+           {
+             emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
+
+         if (mode == DImode)
+           {
+             gcc_assert (TARGET_ARCH64);
+             emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
+       }
+
+      if (symbolic_operand (operands[1], mode))
+       {
+         operands[1] = legitimize_pic_address (operands[1],
+                                               reload_in_progress
+                                               ? operands[0] : NULL_RTX);
+         return false;
+       }
+    }
+
+  /* If we are trying to toss an integer constant into FP registers,
+     or loading a FP or vector constant, force it into memory.  */
+  if (CONSTANT_P (operands[1])
+      && REG_P (operands[0])
+      && (SPARC_FP_REG_P (REGNO (operands[0]))
+         || SCALAR_FLOAT_MODE_P (mode)
+         || VECTOR_MODE_P (mode)))
+    {
+      /* emit_group_store will send such bogosity to us when it is
+         not storing directly into memory.  So fix this up to avoid
+         crashes in output_constant_pool.  */
+      if (operands [1] == const0_rtx)
+       operands[1] = CONST0_RTX (mode);
+
+      /* We can clear FP registers if TARGET_VIS, and always other regs.  */
+      if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG)
+         && const_zero_operand (operands[1], mode))
+       return false;
+
+      if (REGNO (operands[0]) < SPARC_FIRST_FP_REG
+         /* We are able to build any SF constant in integer registers
+            with at most 2 instructions.  */
+         && (mode == SFmode
+             /* And any DF constant in integer registers.  */
+             || (mode == DFmode
+                 && (reload_completed || reload_in_progress))))
+       return false;
+
+      operands[1] = force_const_mem (mode, operands[1]);
+      if (!reload_in_progress)
+       operands[1] = validize_mem (operands[1]);
+      return false;
+    }
+
+  /* Accept non-constants and valid constants unmodified.  */
+  if (!CONSTANT_P (operands[1])
+      || GET_CODE (operands[1]) == HIGH
+      || input_operand (operands[1], mode))
+    return false;
+
+  switch (mode)
+    {
+    case QImode:
+      /* All QImode constants require only one insn, so proceed.  */
+      break;
+
+    case HImode:
+    case SImode:
+      sparc_emit_set_const32 (operands[0], operands[1]);
+      return true;
+
+    case DImode:
+      /* input_operand should have filtered out 32-bit mode.  */
+      sparc_emit_set_const64 (operands[0], operands[1]);
+      return true;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return false;
 }
-\f
-/* We know it can't be done in one insn when we get here,
-   the movsi expander guarantees this.  */
+
+/* Load OP1, a 32-bit constant, into OP0, a register.
+   We know it can't be done in one insn when we get
+   here, the move expander guarantees this.  */
+
 void
 sparc_emit_set_const32 (rtx op0, rtx op1)
 {
@@ -919,13 +1137,13 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
     }
 }
 
-\f
 /* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
    If TEMP is nonzero, we are forbidden to use any other scratch
    registers.  Otherwise, we are allowed to generate them as needed.
 
    Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
    or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns).  */
+
 void
 sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
@@ -1489,14 +1707,9 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
   rtx temp = 0;
 
   /* Sanity check that we know what we are working with.  */
-  gcc_assert (TARGET_ARCH64);
-
-  if (GET_CODE (op0) != SUBREG)
-    {
-      gcc_assert (GET_CODE (op0) == REG
-                 && (REGNO (op0) < SPARC_FIRST_FP_REG
-                     || REGNO (op0) > SPARC_LAST_V9_FP_REG));
-    }
+  gcc_assert (TARGET_ARCH64
+             && (GET_CODE (op0) == SUBREG
+                 || (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0)))));
 
   if (reload_in_progress || reload_completed)
     temp = op0;
@@ -1771,15 +1984,20 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
     }
 }
 
-/* X and Y are two things to compare using CODE.  Emit the compare insn and
-   return the rtx for the cc reg in the proper mode.  */
+/* Emit the compare insn and return the CC reg for a CODE comparison
+   with operands X and Y.  */
 
-rtx
-gen_compare_reg (enum rtx_code code, rtx x, rtx y)
+static rtx
+gen_compare_reg_1 (enum rtx_code code, rtx x, rtx y)
 {
-  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
+  enum machine_mode mode;
   rtx cc_reg;
 
+  if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
+    return x;
+
+  mode = SELECT_CC_MODE (code, x, y);
+
   /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
      fcc regs (cse can't tell they're really call clobbered regs and will
      remove a duplicate comparison even if there is an intervening function
@@ -1826,17 +2044,26 @@ gen_compare_reg (enum rtx_code code, rtx x, rtx y)
   else
     cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
 
-  emit_insn (gen_rtx_SET (VOIDmode, cc_reg,
-                         gen_rtx_COMPARE (mode, x, y)));
+  /* We shouldn't get there for TFmode if !TARGET_HARD_QUAD.  If we do, this
+     will only result in an unrecognizable insn so no point in asserting.  */
+  emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y)));
 
   return cc_reg;
 }
 
+
+/* Emit the compare insn and return the CC reg for the comparison in CMP.  */
+
+rtx
+gen_compare_reg (rtx cmp)
+{
+  return gen_compare_reg_1 (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1));
+}
+
 /* This function is used for v9 only.
+   DEST is the target of the Scc insn.
    CODE is the code for an Scc's comparison.
-   OPERANDS[0] is the target of the Scc insn.
-   OPERANDS[1] is the value we compare against const0_rtx (which hasn't
-   been generated yet).
+   X and Y are the values we compare.
 
    This function is needed to turn
 
@@ -1850,55 +2077,50 @@ gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 
    IE: The instruction recognizer needs to see the mode of the comparison to
    find the right instruction. We could use "gt:DI" right in the
-   define_expand, but leaving it out allows us to handle DI, SI, etc.
-
-   We refer to the global sparc compare operands sparc_compare_op0 and
-   sparc_compare_op1.  */
+   define_expand, but leaving it out allows us to handle DI, SI, etc.  */
 
-int
-gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
+static int
+gen_v9_scc (rtx dest, enum rtx_code compare_code, rtx x, rtx y)
 {
-  rtx temp, op0, op1;
-
   if (! TARGET_ARCH64
-      && (GET_MODE (sparc_compare_op0) == DImode
-         || GET_MODE (operands[0]) == DImode))
+      && (GET_MODE (x) == DImode
+         || GET_MODE (dest) == DImode))
     return 0;
 
-  op0 = sparc_compare_op0;
-  op1 = sparc_compare_op1;
-
   /* Try to use the movrCC insns.  */
   if (TARGET_ARCH64
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-      && op1 == const0_rtx
+      && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+      && y == const0_rtx
       && v9_regcmp_p (compare_code))
     {
+      rtx op0 = x;
+      rtx temp;
+
       /* Special case for op0 != 0.  This can be done with one instruction if
-        operands[0] == sparc_compare_op0.  */
+        dest == x.  */
 
       if (compare_code == NE
-         && GET_MODE (operands[0]) == DImode
-         && rtx_equal_p (op0, operands[0]))
+         && GET_MODE (dest) == DImode
+         && rtx_equal_p (op0, dest))
        {
-         emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+         emit_insn (gen_rtx_SET (VOIDmode, dest,
                              gen_rtx_IF_THEN_ELSE (DImode,
                                       gen_rtx_fmt_ee (compare_code, DImode,
                                                       op0, const0_rtx),
                                       const1_rtx,
-                                      operands[0])));
+                                      dest)));
          return 1;
        }
 
-      if (reg_overlap_mentioned_p (operands[0], op0))
+      if (reg_overlap_mentioned_p (dest, op0))
        {
-         /* Handle the case where operands[0] == sparc_compare_op0.
+         /* Handle the case where dest == x.
             We "early clobber" the result.  */
-         op0 = gen_reg_rtx (GET_MODE (sparc_compare_op0));
-         emit_move_insn (op0, sparc_compare_op0);
+         op0 = gen_reg_rtx (GET_MODE (x));
+         emit_move_insn (op0, x);
        }
 
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
+      emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx));
       if (GET_MODE (op0) != DImode)
        {
          temp = gen_reg_rtx (DImode);
@@ -1906,44 +2128,135 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
        }
       else
        temp = op0;
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                         gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+      emit_insn (gen_rtx_SET (VOIDmode, dest,
+                         gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
                                   gen_rtx_fmt_ee (compare_code, DImode,
                                                   temp, const0_rtx),
                                   const1_rtx,
-                                  operands[0])));
+                                  dest)));
       return 1;
     }
   else
     {
-      operands[1] = gen_compare_reg (compare_code, op0, op1);
+      x = gen_compare_reg_1 (compare_code, x, y);
+      y = const0_rtx;
 
-      switch (GET_MODE (operands[1]))
-       {
-         case CCmode :
-         case CCXmode :
-         case CCFPEmode :
-         case CCFPmode :
-           break;
-         default :
-           gcc_unreachable ();
-       }
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
-      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                         gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
+      gcc_assert (GET_MODE (x) != CC_NOOVmode
+                 && GET_MODE (x) != CCX_NOOVmode);
+
+      emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx));
+      emit_insn (gen_rtx_SET (VOIDmode, dest,
+                         gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
                                   gen_rtx_fmt_ee (compare_code,
-                                                  GET_MODE (operands[1]),
-                                                  operands[1], const0_rtx),
-                                   const1_rtx, operands[0])));
+                                                  GET_MODE (x), x, y),
+                                   const1_rtx, dest)));
       return 1;
     }
 }
 
+
+/* Emit an scc insn.  For seq, sne, sgeu, and sltu, we can do this
+   without jumps using the addx/subx instructions.  */
+
+bool
+emit_scc_insn (rtx operands[])
+{
+  rtx tem;
+  rtx x;
+  rtx y;
+  enum rtx_code code;
+
+  /* The quad-word fp compare library routines all return nonzero to indicate
+     true, which is different from the equivalent libgcc routines, so we must
+     handle them specially here.  */
+  if (GET_MODE (operands[2]) == TFmode && ! TARGET_HARD_QUAD)
+    {
+      operands[1] = sparc_emit_float_lib_cmp (operands[2], operands[3],
+                                             GET_CODE (operands[1]));
+      operands[2] = XEXP (operands[1], 0);
+      operands[3] = XEXP (operands[1], 1);
+    }
+
+  code = GET_CODE (operands[1]);
+  x = operands[2];
+  y = operands[3];
+
+  /* For seq/sne on v9 we use the same code as v8 (the addx/subx method has
+     more applications).  The exception to this is "reg != 0" which can
+     be done in one instruction on v9 (so we do it).  */
+  if (code == EQ)
+    {
+      if (GET_MODE (x) == SImode)
+        {
+          rtx pat = gen_seqsi_special (operands[0], x, y);
+          emit_insn (pat);
+          return true;
+        }
+      else if (GET_MODE (x) == DImode)
+        {
+          rtx pat = gen_seqdi_special (operands[0], x, y);
+          emit_insn (pat);
+          return true;
+        }
+    }
+
+  if (code == NE)
+    {
+      if (GET_MODE (x) == SImode)
+        {
+          rtx pat = gen_snesi_special (operands[0], x, y);
+          emit_insn (pat);
+          return true;
+        }
+      else if (GET_MODE (x) == DImode)
+        {
+          rtx pat = gen_snedi_special (operands[0], x, y);
+          emit_insn (pat);
+          return true;
+        }
+    }
+
+  /* For the rest, on v9 we can use conditional moves.  */
+
+  if (TARGET_V9)
+    {
+      if (gen_v9_scc (operands[0], code, x, y))
+        return true;
+    }
+
+  /* We can do LTU and GEU using the addx/subx instructions too.  And
+     for GTU/LEU, if both operands are registers swap them and fall
+     back to the easy case.  */
+  if (code == GTU || code == LEU)
+    {
+      if ((GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
+          && (GET_CODE (y) == REG || GET_CODE (y) == SUBREG))
+        {
+          tem = x;
+          x = y;
+          y = tem;
+          code = swap_condition (code);
+        }
+    }
+
+  if (code == LTU || code == GEU)
+    {
+      emit_insn (gen_rtx_SET (VOIDmode, operands[0],
+                             gen_rtx_fmt_ee (code, SImode,
+                                             gen_compare_reg_1 (code, x, y),
+                                             const0_rtx)));
+      return true;
+    }
+
+  /* Nope, do branches.  */
+  return false;
+}
+
 /* Emit a conditional jump insn for the v9 architecture using comparison code
    CODE and jump target LABEL.
    This function exists to take advantage of the v9 brxx insns.  */
 
-void
+static void
 emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
 {
   emit_jump_insn (gen_rtx_SET (VOIDmode,
@@ -1955,6 +2268,37 @@ emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
                                    pc_rtx)));
 }
 
+void
+emit_conditional_branch_insn (rtx operands[])
+{
+  /* The quad-word fp compare library routines all return nonzero to indicate
+     true, which is different from the equivalent libgcc routines, so we must
+     handle them specially here.  */
+  if (GET_MODE (operands[1]) == TFmode && ! TARGET_HARD_QUAD)
+    {
+      operands[0] = sparc_emit_float_lib_cmp (operands[1], operands[2],
+                                             GET_CODE (operands[0]));
+      operands[1] = XEXP (operands[0], 0);
+      operands[2] = XEXP (operands[0], 1);
+    }
+
+  if (TARGET_ARCH64 && operands[2] == const0_rtx
+      && GET_CODE (operands[1]) == REG
+      && GET_MODE (operands[1]) == DImode)
+    {
+      emit_v9_brxx_insn (GET_CODE (operands[0]), operands[1], operands[3]);
+      return;
+    }
+
+  operands[1] = gen_compare_reg (operands[0]);
+  operands[2] = const0_rtx;
+  operands[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]), VOIDmode,
+                               operands[1], operands[2]);
+  emit_jump_insn (gen_cbranchcc4 (operands[0], operands[1], operands[2],
+                                 operands[3]));
+}
+
+
 /* Generate a DFmode part of a hard TFmode register.
    REG is the TFmode hard register, LOW is 1 for the
    low 64bit of the register and 0 otherwise.
@@ -2133,6 +2477,8 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
        {
        case SImode:
          func = "_Qp_itoq";
+         if (TARGET_ARCH64)
+           operands[1] = gen_rtx_SIGN_EXTEND (DImode, operands[1]);
          break;
        case DImode:
          func = "_Qp_xtoq";
@@ -2147,6 +2493,8 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
        {
        case SImode:
          func = "_Qp_uitoq";
+         if (TARGET_ARCH64)
+           operands[1] = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
          break;
        case DImode:
          func = "_Qp_uxtoq";
@@ -2274,26 +2622,34 @@ empty_delay_slot (rtx insn)
 int
 tls_call_delay (rtx trial)
 {
-  rtx pat, unspec;
+  rtx pat;
 
   /* Binutils allows
-     call __tls_get_addr, %tgd_call (foo)
-      add %l7, %o0, %o0, %tgd_add (foo)
+       call __tls_get_addr, %tgd_call (foo)
+        add %l7, %o0, %o0, %tgd_add (foo)
      while Sun as/ld does not.  */
   if (TARGET_GNU_TLS || !TARGET_TLS)
     return 1;
 
   pat = PATTERN (trial);
-  if (GET_CODE (pat) != SET || GET_CODE (SET_DEST (pat)) != PLUS)
-    return 1;
 
-  unspec = XEXP (SET_DEST (pat), 1);
-  if (GET_CODE (unspec) != UNSPEC
-      || (XINT (unspec, 1) != UNSPEC_TLSGD
-         && XINT (unspec, 1) != UNSPEC_TLSLDM))
-    return 1;
+  /* We must reject tgd_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
+     and tldm_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
+     for Sun as/ld.  */
+  if (GET_CODE (pat) == SET
+      && GET_CODE (SET_SRC (pat)) == PLUS)
+    {
+      rtx unspec = XEXP (SET_SRC (pat), 1);
 
-  return 0;
+      if (GET_CODE (unspec) == UNSPEC
+         && (XINT (unspec, 1) == UNSPEC_TLSGD
+             || XINT (unspec, 1) == UNSPEC_TLSLDM))
+       return 0;
+    }
+
+  return 1;
 }
 
 /* Return nonzero if TRIAL, an insn, can be combined with a 'restore'
@@ -2393,7 +2749,7 @@ eligible_for_return_delay (rtx trial)
 
   /* If the function uses __builtin_eh_return, the eh_return machinery
      occupies the delay slot.  */
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     return 0;
 
   /* In the case of a true leaf function, anything can go into the slot.  */
@@ -2552,9 +2908,8 @@ sparc_cannot_force_const_mem (rtx x)
 }
 \f
 /* PIC support.  */
-static GTY(()) char pic_helper_symbol_name[256];
+static GTY(()) bool pic_helper_needed = false;
 static GTY(()) rtx pic_helper_symbol;
-static GTY(()) bool pic_helper_emitted_p = false;
 static GTY(()) rtx global_offset_table;
 
 /* Ensure that we are not using patterns that are not OK with PIC.  */
@@ -2578,7 +2933,7 @@ check_pic (int i)
     }
 }
 
-/* Return true if X is an address which needs a temporary register when 
+/* Return true if X is an address which needs a temporary register when
    reloaded while generating PIC code.  */
 
 int
@@ -2600,23 +2955,11 @@ pic_address_needs_scratch (rtx x)
 bool
 legitimate_constant_p (rtx x)
 {
-  rtx inner;
-
   switch (GET_CODE (x))
     {
-    case SYMBOL_REF:
-      /* TLS symbols are not constant.  */
-      if (SYMBOL_REF_TLS_MODEL (x))
-       return false;
-      break;
-
     case CONST:
-      inner = XEXP (x, 0);
-
-      /* Offsets of TLS symbols are never valid.
-        Discourage CSE from creating them.  */
-      if (GET_CODE (inner) == PLUS
-         && tls_symbolic_operand (XEXP (inner, 0)))
+    case SYMBOL_REF:
+      if (sparc_tls_referenced_p (x))
        return false;
       break;
 
@@ -2627,9 +2970,16 @@ legitimate_constant_p (rtx x)
       /* Floating point constants are generally not ok.
         The only exception is 0.0 in VIS.  */
       if (TARGET_VIS
-         && (GET_MODE (x) == SFmode
-             || GET_MODE (x) == DFmode
-             || GET_MODE (x) == TFmode)
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
+         && const_zero_operand (x, GET_MODE (x)))
+       return true;
+
+      return false;
+
+    case CONST_VECTOR:
+      /* Vector constants are generally not ok.
+        The only exception is 0 in VIS.  */
+      if (TARGET_VIS
          && const_zero_operand (x, GET_MODE (x)))
        return true;
 
@@ -2676,19 +3026,16 @@ legitimate_pic_operand_p (rtx x)
 {
   if (pic_address_needs_scratch (x))
     return false;
-  if (tls_symbolic_operand (x)
-      || (GET_CODE (x) == CONST
-         && GET_CODE (XEXP (x, 0)) == PLUS
-         && tls_symbolic_operand (XEXP (XEXP (x, 0), 0))))
+  if (sparc_tls_referenced_p (x))
     return false;
   return true;
 }
 
 /* Return nonzero if ADDR is a valid memory address.
    STRICT specifies whether strict register checking applies.  */
-   
-int
-legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
+
+static bool
+sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
 {
   rtx rs1 = NULL, rs2 = NULL, imm1 = NULL;
 
@@ -2717,7 +3064,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
           && GET_CODE (rs2) != SUBREG
           && GET_CODE (rs2) != LO_SUM
           && GET_CODE (rs2) != MEM
-          && !tls_symbolic_operand (rs2)
+          && !(GET_CODE (rs2) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs2))
           && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
           && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
          || ((REG_P (rs1)
@@ -2757,7 +3104,8 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
          rs2 = NULL;
          imm1 = XEXP (rs1, 1);
          rs1 = XEXP (rs1, 0);
-         if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+         if (!CONSTANT_P (imm1)
+             || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
            return 0;
        }
     }
@@ -2766,7 +3114,8 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
       rs1 = XEXP (addr, 0);
       imm1 = XEXP (addr, 1);
 
-      if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+      if (!CONSTANT_P (imm1)
+         || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
        return 0;
 
       /* We can't allow TFmode in 32-bit mode, because an offset greater
@@ -2815,6 +3164,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
 /* Construct the SYMBOL_REF for the tls_get_offset function.  */
 
 static GTY(()) rtx sparc_tls_symbol;
+
 static rtx
 sparc_tls_get_addr (void)
 {
@@ -2830,7 +3180,7 @@ sparc_tls_got (void)
   rtx temp;
   if (flag_pic)
     {
-      current_function_uses_pic_offset_table = 1;
+      crtl->uses_pic_offset_table = 1;
       return pic_offset_table_rtx;
     }
 
@@ -2841,16 +3191,33 @@ sparc_tls_got (void)
   return temp;
 }
 
+/* Return true if X contains a thread-local symbol.  */
+
+static bool
+sparc_tls_referenced_p (rtx x)
+{
+  if (!TARGET_HAVE_TLS)
+    return false;
+
+  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
+    x = XEXP (XEXP (x, 0), 0);
+
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
+    return true;
+
+  /* That's all we handle in legitimize_tls_address for now.  */
+  return false;
+}
 
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
 
-rtx
+static rtx
 legitimize_tls_address (rtx addr)
 {
   rtx temp1, temp2, temp3, ret, o0, got, insn;
 
-  gcc_assert (! no_new_pseudos);
+  gcc_assert (can_create_pseudo_p ());
 
   if (GET_CODE (addr) == SYMBOL_REF)
     switch (SYMBOL_REF_TLS_MODEL (addr))
@@ -2969,23 +3336,40 @@ legitimize_tls_address (rtx addr)
        gcc_unreachable ();
       }
 
+  else if (GET_CODE (addr) == CONST)
+    {
+      rtx base, offset;
+
+      gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
+
+      base = legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
+      offset = XEXP (XEXP (addr, 0), 1);
+
+      base = force_operand (base, NULL_RTX);
+      if (!(GET_CODE (offset) == CONST_INT && SMALL_INT (offset)))
+       offset = force_reg (Pmode, offset);
+      ret = gen_rtx_PLUS (Pmode, base, offset);
+    }
+
   else
     gcc_unreachable ();  /* for now ... */
 
   return ret;
 }
 
-
 /* Legitimize PIC addresses.  If the address is already position-independent,
    we return ORIG.  Newly generated position-independent addresses go into a
    reg.  This is REG if nonzero, otherwise we allocate register(s) as
    necessary.  */
 
-rtx
-legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
-                       rtx reg)
+static rtx
+legitimize_pic_address (rtx orig, rtx reg)
 {
-  if (GET_CODE (orig) == SYMBOL_REF)
+  bool gotdata_op = false;
+
+  if (GET_CODE (orig) == SYMBOL_REF
+      /* See the comment in sparc_expand_move.  */
+      || (TARGET_VXWORKS_RTP && GET_CODE (orig) == LABEL_REF))
     {
       rtx pic_ref, address;
       rtx insn;
@@ -3008,30 +3392,42 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
             won't get confused into thinking that these two instructions
             are loading in the true address of the symbol.  If in the
             future a PIC rtx exists, that should be used instead.  */
-         if (Pmode == SImode)
+         if (TARGET_ARCH64)
            {
-             emit_insn (gen_movsi_high_pic (temp_reg, orig));
-             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movdi_high_pic (temp_reg, orig));
+             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          else
            {
-             emit_insn (gen_movdi_high_pic (temp_reg, orig));
-             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movsi_high_pic (temp_reg, orig));
+             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          address = temp_reg;
+         gotdata_op = true;
        }
       else
        address = orig;
 
-      pic_ref = gen_const_mem (Pmode,
-                              gen_rtx_PLUS (Pmode,
-                                            pic_offset_table_rtx, address));
-      current_function_uses_pic_offset_table = 1;
-      insn = emit_move_insn (reg, pic_ref);
+      crtl->uses_pic_offset_table = 1;
+      if (gotdata_op)
+       {
+         if (TARGET_ARCH64)
+           insn = emit_insn (gen_movdi_pic_gotdata_op (reg, pic_offset_table_rtx,
+                                                       address, orig));
+         else
+           insn = emit_insn (gen_movsi_pic_gotdata_op (reg, pic_offset_table_rtx,
+                                                       address, orig));
+       }
+      else
+       {
+         pic_ref = gen_const_mem (Pmode,
+                                  gen_rtx_PLUS (Pmode,
+                                                pic_offset_table_rtx, address));
+         insn = emit_move_insn (reg, pic_ref);
+       }
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
-                                 REG_NOTES (insn));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
       return reg;
     }
   else if (GET_CODE (orig) == CONST)
@@ -3049,9 +3445,9 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
        }
 
       gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
-      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
-      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
-                                      base == reg ? 0 : reg);
+      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
+      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+                                      base == reg ? NULL_RTX : reg);
 
       if (GET_CODE (offset) == CONST_INT)
        {
@@ -3069,7 +3465,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
     /* ??? Why do we do this?  */
     /* Now movsi_pic_label_ref uses it, but we ought to be checking that
        the register is live instead, in case it is eliminated.  */
-    current_function_uses_pic_offset_table = 1;
+    crtl->uses_pic_offset_table = 1;
 
   return orig;
 }
@@ -3080,10 +3476,13 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
    OLDX is the address as it was before break_out_memory_refs was called.
    In some cases it is useful to look at this to decide what needs to be done.
 
-   MODE is the mode of the operand pointed to by X.  */
+   MODE is the mode of the operand pointed to by X.
 
-rtx
-legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
+   On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG.  */
+
+static rtx
+sparc_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+                         enum machine_mode mode)
 {
   rtx orig_x = x;
 
@@ -3100,13 +3499,13 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
     x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
                      force_operand (XEXP (x, 1), NULL_RTX));
 
-  if (x != orig_x && legitimate_address_p (mode, x, FALSE))
+  if (x != orig_x && sparc_legitimate_address_p (mode, x, FALSE))
     return x;
 
-  if (tls_symbolic_operand (x))
+  if (sparc_tls_referenced_p (x))
     x = legitimize_tls_address (x);
   else if (flag_pic)
-    x = legitimize_pic_address (x, mode, 0);
+    x = legitimize_pic_address (x, NULL_RTX);
   else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
     x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
                      copy_to_mode_reg (Pmode, XEXP (x, 1)));
@@ -3115,55 +3514,60 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
                      copy_to_mode_reg (Pmode, XEXP (x, 0)));
   else if (GET_CODE (x) == SYMBOL_REF
           || GET_CODE (x) == CONST
-           || GET_CODE (x) == LABEL_REF)
+          || GET_CODE (x) == LABEL_REF)
     x = copy_to_suggested_reg (x, NULL_RTX, Pmode);
+
   return x;
 }
 
-/* Emit the special PIC helper function.  */
+#ifdef HAVE_GAS_HIDDEN
+# define USE_HIDDEN_LINKONCE 1
+#else
+# define USE_HIDDEN_LINKONCE 0
+#endif
 
 static void
-emit_pic_helper (void)
+get_pc_thunk_name (char name[32], unsigned int regno)
 {
-  const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
-  int align;
+  const char *pic_name = reg_names[regno];
 
-  text_section ();
+  /* Skip the leading '%' as that cannot be used in a
+     symbol name.  */
+  pic_name += 1;
 
-  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-  if (align > 0)
-    ASM_OUTPUT_ALIGN (asm_out_file, align);
-  ASM_OUTPUT_LABEL (asm_out_file, pic_helper_symbol_name);
-  if (flag_delayed_branch)
-    fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
-           pic_name, pic_name);
+  if (USE_HIDDEN_LINKONCE)
+    sprintf (name, "__sparc_get_pc_thunk.%s", pic_name);
   else
-    fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
-           pic_name, pic_name);
-
-  pic_helper_emitted_p = true;
+    ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno);
 }
 
 /* Emit code to load the PIC register.  */
 
 static void
-load_pic_register (bool delay_pic_helper)
+load_pic_register (void)
 {
   int orig_flag_pic = flag_pic;
 
+  if (TARGET_VXWORKS_RTP)
+    {
+      emit_insn (gen_vxworks_load_got ());
+      emit_use (pic_offset_table_rtx);
+      return;
+    }
+
   /* If we haven't initialized the special PIC symbols, do so now.  */
-  if (!pic_helper_symbol_name[0])
+  if (!pic_helper_needed)
     {
-      ASM_GENERATE_INTERNAL_LABEL (pic_helper_symbol_name, "LADDPC", 0);
-      pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, pic_helper_symbol_name);
+      char name[32];
+
+      pic_helper_needed = true;
+
+      get_pc_thunk_name (name, REGNO (pic_offset_table_rtx));
+      pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
+
       global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
     }
 
-  /* If we haven't emitted the special PIC helper function, do so now unless
-     we are requested to delay it.  */
-  if (!delay_pic_helper && !pic_helper_emitted_p)
-    emit_pic_helper ();
-
   flag_pic = 0;
   if (TARGET_ARCH64)
     emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table,
@@ -3177,7 +3581,30 @@ load_pic_register (bool delay_pic_helper)
      since setjmp/longjmp can cause life info to screw up.
      ??? In the case where we don't obey regdecls, this is not sufficient
      since we may not fall out the bottom.  */
-  emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+  emit_use (pic_offset_table_rtx);
+}
+
+/* Emit a call instruction with the pattern given by PAT.  ADDR is the
+   address of the call target.  */
+
+void
+sparc_emit_call_insn (rtx pat, rtx addr)
+{
+  rtx insn;
+
+  insn = emit_call_insn (pat);
+
+  /* The PIC register is live on entry to VxWorks PIC PLT entries.  */
+  if (TARGET_VXWORKS_RTP
+      && flag_pic
+      && GET_CODE (addr) == SYMBOL_REF
+      && (SYMBOL_REF_DECL (addr)
+         ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
+         : !SYMBOL_REF_LOCAL_P (addr)))
+    {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+      crtl->uses_pic_offset_table = 1;
+    }
 }
 \f
 /* Return 1 if RTX is a MEM which is known to be aligned to at
@@ -3193,7 +3620,8 @@ mem_min_alignment (rtx mem, int desired)
     return 0;
 
   /* Obviously...  */
-  if (MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
+  if (!TARGET_UNALIGNED_DOUBLES
+      && MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
     return 1;
 
   /* ??? The rest of the function predates MEM_ALIGN so
@@ -3254,7 +3682,7 @@ mem_min_alignment (rtx mem, int desired)
         it is to a constant address, or the address involves a LO_SUM.  */
       return 1;
     }
-  
+
   /* An obviously unaligned address.  */
   return 0;
 }
@@ -3266,7 +3694,7 @@ mem_min_alignment (rtx mem, int desired)
    hard register number, and one indexed by mode.  */
 
 /* The purpose of sparc_mode_class is to shrink the range of modes so that
-   they all fit (as bit numbers) in a 32 bit word (again).  Each real mode is
+   they all fit (as bit numbers) in a 32-bit word (again).  Each real mode is
    mapped into one sparc_mode_class mode.  */
 
 enum sparc_mode_class {
@@ -3293,27 +3721,22 @@ enum sparc_mode_class {
 #define SF_MODES (S_MODES)
 
 /* Modes for double-float and smaller quantities.  */
-#define DF_MODES (S_MODES | D_MODES)
-
-/* Modes for double-float only quantities.  */
-#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
-
-/* Modes for quad-float only quantities.  */
-#define TF_ONLY_MODES (1 << (int) TF_MODE)
+#define DF_MODES (D_MODES)
 
 /* Modes for quad-float and smaller quantities.  */
-#define TF_MODES (DF_MODES | TF_ONLY_MODES)
+#define TF_MODES (DF_MODES | (1 << (int) TF_MODE))
 
-/* Modes for quad-float and double-float quantities.  */
-#define TF_MODES_NO_S (DF_MODES_NO_S | TF_ONLY_MODES)
+/* Modes for quad-float pairs and smaller quantities.  */
+#define OF_MODES (TF_MODES | (1 << (int) OF_MODE))
 
-/* Modes for quad-float pair only quantities.  */
-#define OF_ONLY_MODES (1 << (int) OF_MODE)
+/* Modes for double-float only quantities.  */
+#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
 
-/* Modes for quad-float pairs and smaller quantities.  */
-#define OF_MODES (TF_MODES | OF_ONLY_MODES)
+/* Modes for quad-float and double-float only quantities.  */
+#define TF_MODES_NO_S (DF_MODES_NO_S | (1 << (int) TF_MODE))
 
-#define OF_MODES_NO_S (TF_MODES_NO_S | OF_ONLY_MODES)
+/* Modes for quad-float pairs and double-float only quantities.  */
+#define OF_MODES_NO_S (TF_MODES_NO_S | (1 << (int) OF_MODE))
 
 /* Modes for condition codes.  */
 #define CC_MODES (1 << (int) CC_MODE)
@@ -3402,7 +3825,7 @@ sparc_init_modes (void)
            sparc_mode_class[i] = 1 << (int) T_MODE;
          else if (GET_MODE_SIZE (i) == 32)
            sparc_mode_class[i] = 1 << (int) O_MODE;
-         else 
+         else
            sparc_mode_class[i] = 0;
          break;
        case MODE_VECTOR_INT:
@@ -3421,7 +3844,7 @@ sparc_init_modes (void)
            sparc_mode_class[i] = 1 << (int) TF_MODE;
          else if (GET_MODE_SIZE (i) == 32)
            sparc_mode_class[i] = 1 << (int) OF_MODE;
-         else 
+         else
            sparc_mode_class[i] = 0;
          break;
        case MODE_CC:
@@ -3465,7 +3888,7 @@ sparc_init_modes (void)
 HOST_WIDE_INT
 sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 {
-  int outgoing_args_size = (current_function_outgoing_args_size
+  int outgoing_args_size = (crtl->outgoing_args_size
                            + REG_PARM_STACK_SPACE (current_function_decl));
   int n_regs = 0;  /* N_REGS is the number of 4-byte regs saved thus far.  */
   int i;
@@ -3473,20 +3896,20 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
   if (TARGET_ARCH64)
     {
       for (i = 0; i < 8; i++)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          n_regs += 2;
     }
   else
     {
       for (i = 0; i < 8; i += 2)
-       if ((regs_ever_live[i] && ! call_used_regs[i])
-           || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+       if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+           || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
          n_regs += 2;
     }
 
   for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
-    if ((regs_ever_live[i] && ! call_used_regs[i])
-       || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+    if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+       || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
       n_regs += 2;
 
   /* Set up values for use in prologue and epilogue.  */
@@ -3495,7 +3918,7 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
   if (leaf_function_p
       && n_regs == 0
       && size == 0
-      && current_function_outgoing_args_size == 0)
+      && crtl->outgoing_args_size == 0)
     actual_fsize = apparent_fsize = 0;
   else
     {
@@ -3507,10 +3930,9 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 
   /* Make sure nothing can clobber our register windows.
      If a SAVE must be done, or there is a stack-local variable,
-     the register window area must be allocated.
-     ??? For v8 we apparently need an additional 8 bytes of reserved space.  */
+     the register window area must be allocated.  */
   if (! leaf_function_p || size > 0)
-    actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
+    actual_fsize += FIRST_PARM_OFFSET (current_function_decl);
 
   return SPARC_STACK_ALIGN (actual_fsize);
 }
@@ -3530,11 +3952,14 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
      .register being printed for them already.  */
   for (i = 2; i < 8; i++)
     {
-      if (regs_ever_live [i]
+      if (df_regs_ever_live_p (i)
          && ! sparc_hard_reg_printed [i])
        {
          sparc_hard_reg_printed [i] = 1;
-         fprintf (file, "\t.register\t%%g%d, #scratch\n", i);
+         /* %g7 is used as TLS base register, use #ignore
+            for it instead of #scratch.  */
+         fprintf (file, "\t.register\t%%g%d, #%s\n", i,
+                  i == 7 ? "ignore" : "scratch");
        }
       if (i == 3) i = 5;
     }
@@ -3558,7 +3983,7 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
     {
       for (i = low; i < high; i++)
        {
-         if (regs_ever_live[i] && ! call_used_regs[i])
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
            {
              mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
              set_mem_alias_set (mem, sparc_sr_alias_set);
@@ -3577,8 +4002,8 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
     {
       for (i = low; i < high; i += 2)
        {
-         bool reg0 = regs_ever_live[i] && ! call_used_regs[i];
-         bool reg1 = regs_ever_live[i+1] && ! call_used_regs[i+1];
+         bool reg0 = df_regs_ever_live_p (i) && ! call_used_regs[i];
+         bool reg1 = df_regs_ever_live_p (i+1) && ! call_used_regs[i+1];
          enum machine_mode mode;
          int regno;
 
@@ -3622,14 +4047,14 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
 /* Emit code to save call-saved registers.  */
 
 static void
-emit_save_regs (void)
+emit_save_or_restore_regs (int action)
 {
   HOST_WIDE_INT offset;
   rtx base;
 
   offset = frame_base_offset - apparent_fsize;
 
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+  if (offset < -4096 || offset + num_gfregs * 4 > 4095)
     {
       /* ??? This might be optimized a little as %g1 might already have a
         value close enough that a single add insn will do.  */
@@ -3647,34 +4072,8 @@ emit_save_regs (void)
   else
     base = frame_base_reg;
 
-  offset = save_or_restore_regs (0, 8, base, offset, SORR_SAVE);
-  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_SAVE);
-}
-
-/* Emit code to restore call-saved registers.  */
-
-static void
-emit_restore_regs (void)
-{
-  HOST_WIDE_INT offset;
-  rtx base;
-
-  offset = frame_base_offset - apparent_fsize;
-
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
-    {
-      base = gen_rtx_REG (Pmode, 1);
-      emit_move_insn (base, GEN_INT (offset));
-      emit_insn (gen_rtx_SET (VOIDmode,
-                             base,
-                             gen_rtx_PLUS (Pmode, frame_base_reg, base)));
-      offset = 0;
-    }
-  else
-    base = frame_base_reg;
-
-  offset = save_or_restore_regs (0, 8, base, offset, SORR_RESTORE);
-  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_RESTORE);
+  offset = save_or_restore_regs (0, 8, base, offset, action);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action);
 }
 
 /* Generate a save_register_window insn.  */
@@ -3693,10 +4092,11 @@ gen_save_register_window (rtx increment)
 static rtx
 gen_stack_pointer_inc (rtx increment)
 {
-  if (TARGET_ARCH64)
-    return gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment);
-  else
-    return gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment);
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_PLUS (Pmode,
+                                   stack_pointer_rtx,
+                                   increment));
 }
 
 /* Generate a decrement for the stack pointer.  */
@@ -3704,10 +4104,11 @@ gen_stack_pointer_inc (rtx increment)
 static rtx
 gen_stack_pointer_dec (rtx decrement)
 {
-  if (TARGET_ARCH64)
-    return gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement);
-  else
-    return gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement);
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_MINUS (Pmode,
+                                    stack_pointer_rtx,
+                                    decrement));
 }
 
 /* Expand the function prologue.  The prologue is responsible for reserving
@@ -3783,10 +4184,8 @@ sparc_expand_prologue (void)
          rtx reg = gen_rtx_REG (Pmode, 1);
          emit_move_insn (reg, GEN_INT (-actual_fsize));
          insn = emit_insn (gen_stack_pointer_inc (reg));
-         REG_NOTES (insn) =
-           gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                              PATTERN (gen_stack_pointer_inc (GEN_INT (-actual_fsize))),
-                              REG_NOTES (insn));
+         add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+                       gen_stack_pointer_inc (GEN_INT (-actual_fsize)));
        }
 
       RTX_FRAME_RELATED_P (insn) = 1;
@@ -3813,22 +4212,16 @@ sparc_expand_prologue (void)
         RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
     }
 
-  /* Call-saved registers are saved just above the outgoing argument area.  */
   if (num_gfregs)
-    emit_save_regs ();
+    emit_save_or_restore_regs (SORR_SAVE);
 
   /* Load the PIC register if needed.  */
-  if (flag_pic && current_function_uses_pic_offset_table)
-    load_pic_register (false);
+  if (flag_pic && crtl->uses_pic_offset_table)
+    load_pic_register ();
 }
-/* This function generates the assembly code for function entry, which boils
-   down to emitting the necessary .register directives.
 
-   ??? Historical cruft: "On SPARC, move-double insns between fpu and cpu need
-   an 8-byte block of memory.  If any fpu reg is used in the function, we
-   allocate such a block here, at the bottom of the frame, just in case it's
-   needed."  Could this explain the -8 in emit_restore_regs?  */
+/* This function generates the assembly code for function entry, which boils
+   down to emitting the necessary .register directives.  */
 
 static void
 sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
@@ -3846,7 +4239,7 @@ void
 sparc_expand_epilogue (void)
 {
   if (num_gfregs)
-    emit_restore_regs ();
+    emit_save_or_restore_regs (SORR_RESTORE);
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
@@ -3877,9 +4270,9 @@ sparc_can_use_return_insn_p (void)
   return sparc_prologue_data_valid_p
         && (actual_fsize == 0 || !sparc_leaf_function_p);
 }
-  
+
 /* This function generates the assembly code for function exit.  */
-  
+
 static void
 sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
@@ -3904,9 +4297,9 @@ sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
   sparc_output_deferred_case_vectors ();
 }
-  
+
 /* Output a 'restore' instruction.  */
+
 static void
 output_restore (rtx pat)
 {
@@ -3946,7 +4339,7 @@ output_restore (rtx pat)
        break;
     }
 }
-  
+
 /* Output a return.  */
 
 const char *
@@ -3959,7 +4352,7 @@ output_return (rtx insn)
         semantics of restore/return.  We simply output the jump to the
         return address and the insn in the delay slot (if any).  */
 
-      gcc_assert (! current_function_calls_eh_return);
+      gcc_assert (! crtl->calls_eh_return);
 
       return "jmp\t%%o7+%)%#";
     }
@@ -3970,7 +4363,7 @@ output_return (rtx insn)
         combined with the 'restore' instruction or put in the delay slot of
         the 'return' instruction.  */
 
-      if (current_function_calls_eh_return)
+      if (crtl->calls_eh_return)
        {
          /* If the function uses __builtin_eh_return, the eh_return
             machinery occupies the delay slot.  */
@@ -4129,7 +4522,7 @@ output_sibcall (rtx insn, rtx call_operand)
      the appropriate fp reg and in memory.
 
 
-   Summary of the calling conventions implemented by GCC on SPARC:
+   Summary of the calling conventions implemented by GCC on the SPARC:
 
    32-bit ABI:
                                 size      argument     return value
@@ -4198,7 +4591,7 @@ implemented by the Sun compiler.
 Note #2: integral vector types follow the scalar floating-point types
 conventions to match what is implemented by the Sun VIS SDK.
 
-Note #3: floating-point vector types follow the aggregate types 
+Note #3: floating-point vector types follow the aggregate types
 conventions.  */
 
 
@@ -4228,11 +4621,38 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
    When a prototype says `char' or `short', really pass an `int'.  */
 
 static bool
-sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+sparc_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
 {
   return TARGET_ARCH32 ? true : false;
 }
 
+/* Handle promotion of pointer and integer arguments.  */
+
+static enum machine_mode
+sparc_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
+                             enum machine_mode mode,
+                             int *punsignedp ATTRIBUTE_UNUSED,
+                             const_tree fntype ATTRIBUTE_UNUSED,
+                             int for_return ATTRIBUTE_UNUSED)
+{
+  if (POINTER_TYPE_P (type))
+    {
+      *punsignedp = POINTERS_EXTEND_UNSIGNED;
+      return Pmode;
+    }
+
+  /* For TARGET_ARCH64 we need this, as we don't have instructions
+     for arithmetic operations which do zero/sign extension at the same time,
+     so without this we end up with a srl/sra after every assignment to an
+     user variable,  which means very very bad code.  */
+  if (TARGET_ARCH64
+      && GET_MODE_CLASS (mode) == MODE_INT
+      && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+    return word_mode;
+
+  return mode;
+}
+
 /* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook.  */
 
 static bool
@@ -4314,7 +4734,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
 
   /* For SPARC64, objects requiring 16-byte alignment get it.  */
   if (TARGET_ARCH64
-      && GET_MODE_ALIGNMENT (mode) >= 2 * BITS_PER_WORD
+      && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
       && (slotno & 1) != 0)
     slotno++, *ppadding = 1;
 
@@ -4347,6 +4767,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
     {
     case MODE_FLOAT:
     case MODE_COMPLEX_FLOAT:
+    case MODE_VECTOR_INT:
       if (TARGET_ARCH64 && TARGET_FPU && named)
        {
          if (slotno >= SPARC_FP_ARG_MAX)
@@ -4374,14 +4795,10 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
 
       gcc_assert (mode == BLKmode);
 
-      /* For SPARC64, objects requiring 16-byte alignment get it.  */
-      if (TARGET_ARCH64
-         && type
-         && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
-         && (slotno & 1) != 0)
-       slotno++, *ppadding = 1;
-
-      if (TARGET_ARCH32 || !type || (TREE_CODE (type) == UNION_TYPE))
+      if (TARGET_ARCH32
+         || !type
+         || (TREE_CODE (type) != VECTOR_TYPE
+             && TREE_CODE (type) != RECORD_TYPE))
        {
          if (slotno >= SPARC_INT_ARG_MAX)
            return -1;
@@ -4444,17 +4861,17 @@ struct function_arg_record_value_parms
 static void function_arg_record_value_3
  (HOST_WIDE_INT, struct function_arg_record_value_parms *);
 static void function_arg_record_value_2
- (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
+ (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static void function_arg_record_value_1
- (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
+ (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
+static rtx function_arg_record_value (const_tree, enum machine_mode, int, int, int);
 static rtx function_arg_union_value (int, enum machine_mode, int, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
    recursively and determine how many registers will be required.  */
 
 static void
-function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
+function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
                             struct function_arg_record_value_parms *parms,
                             bool packed_p)
 {
@@ -4551,7 +4968,7 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
 /* A subroutine of function_arg_record_value.  Assign the bits of the
    structure between parms->intoffset and bitpos to integer registers.  */
 
-static void 
+static void
 function_arg_record_value_3 (HOST_WIDE_INT bitpos,
                             struct function_arg_record_value_parms *parms)
 {
@@ -4610,7 +5027,7 @@ function_arg_record_value_3 (HOST_WIDE_INT bitpos,
    to make that happen.  */
 
 static void
-function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
+function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
                             struct function_arg_record_value_parms *parms,
                             bool packed_p)
 {
@@ -4715,9 +5132,9 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
    NAMED is nonzero if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).
    REGBASE is the regno of the base register for the parameter array.  */
-   
+
 static rtx
-function_arg_record_value (tree type, enum machine_mode mode,
+function_arg_record_value (const_tree type, enum machine_mode mode,
                           int slotno, int named, int regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
@@ -4846,15 +5263,13 @@ function_arg_union_value (int size, enum machine_mode mode, int slotno,
    Return an expression valid as a return value for the two macros
    FUNCTION_ARG and FUNCTION_VALUE.
 
-   SIZE is the size in bytes of the vector.
-   BASE_MODE is the argument's base machine mode.
+   SIZE is the size in bytes of the vector (at least 8 bytes).
    REGNO is the FP hard register the vector will be passed in.  */
 
 static rtx
-function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
+function_arg_vector_value (int size, int regno)
 {
-  unsigned short base_mode_size = GET_MODE_SIZE (base_mode);
-  int nregs = size / base_mode_size, i;
+  int i, nregs = size / 8;
   rtx regs;
 
   regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
@@ -4863,9 +5278,8 @@ function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
     {
       XVECEXP (regs, 0, i)
        = gen_rtx_EXPR_LIST (VOIDmode,
-                            gen_rtx_REG (base_mode, regno),
-                            GEN_INT (base_mode_size * i));
-      regno += base_mode_size / 4;
+                            gen_rtx_REG (DImode, regno + 2*i),
+                            GEN_INT (i*8));
     }
 
   return regs;
@@ -4895,62 +5309,57 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno, regno, padding;
   enum mode_class mclass = GET_MODE_CLASS (mode);
-  rtx reg;
 
   slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
                                &regno, &padding);
-
   if (slotno == -1)
     return 0;
 
-  if (TARGET_ARCH32)
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
     {
-      reg = gen_rtx_REG (mode, regno);
-      return reg;
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert ((TARGET_ARCH32 && size <= 8)
+                 || (TARGET_ARCH64 && size <= 16));
+
+      if (mode == BLKmode)
+       return function_arg_vector_value (size,
+                                         SPARC_FP_ARG_FIRST + 2*slotno);
+      else
+       mclass = MODE_FLOAT;
     }
-    
-  if (type && TREE_CODE (type) == RECORD_TYPE)
-    {
-      /* Structures up to 16 bytes in size are passed in arg slots on the
-        stack and are promoted to registers where possible.  */
 
-      gcc_assert (int_size_in_bytes (type) <= 16);
+  if (TARGET_ARCH32)
+    return gen_rtx_REG (mode, regno);
 
-      return function_arg_record_value (type, mode, slotno, named, regbase);
-    }
-  else if (type && TREE_CODE (type) == UNION_TYPE)
+  /* Structures up to 16 bytes in size are passed in arg slots on the stack
+     and are promoted to registers if possible.  */
+  if (type && TREE_CODE (type) == RECORD_TYPE)
     {
       HOST_WIDE_INT size = int_size_in_bytes (type);
-
       gcc_assert (size <= 16);
 
-      return function_arg_union_value (size, mode, slotno, regno);
+      return function_arg_record_value (type, mode, slotno, named, regbase);
     }
-  else if (type && TREE_CODE (type) == VECTOR_TYPE)
+
+  /* Unions up to 16 bytes in size are passed in integer registers.  */
+  else if (type && TREE_CODE (type) == UNION_TYPE)
     {
-      /* Vector types deserve special treatment because they are
-        polymorphic wrt their mode, depending upon whether VIS
-        instructions are enabled.  */
       HOST_WIDE_INT size = int_size_in_bytes (type);
-
       gcc_assert (size <= 16);
 
-      if (mode == BLKmode)
-       return function_arg_vector_value (size,
-                                         TYPE_MODE (TREE_TYPE (type)),
-                                         SPARC_FP_ARG_FIRST + 2*slotno);
-      else
-       mclass = MODE_FLOAT;
+      return function_arg_union_value (size, mode, slotno, regno);
     }
 
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
      in two places, either fp regs and int regs or fp regs and memory.  */
-  if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
-      && SPARC_FP_REG_P (regno))
+  else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+          && SPARC_FP_REG_P (regno))
     {
-      reg = gen_rtx_REG (mode, regno);
+      rtx reg = gen_rtx_REG (mode, regno);
       if (cum->prototype_p || cum->libcall_p)
        {
          /* "* 2" because fp reg numbers are recorded in 4 byte
@@ -5011,13 +5420,18 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
            }
        }
     }
-  else
+
+  /* All other aggregate types are passed in an integer register in a mode
+     corresponding to the size of the type.  */
+  else if (type && AGGREGATE_TYPE_P (type))
     {
-      /* Scalar or complex int.  */
-      reg = gen_rtx_REG (mode, regno);
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
+
+      mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
     }
 
-  return reg;
+  return gen_rtx_REG (mode, regno);
 }
 
 /* For an arg passed partly in registers and partly in memory,
@@ -5089,11 +5503,10 @@ sparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 
 static bool
 sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
-                        enum machine_mode mode, tree type,
+                        enum machine_mode mode, const_tree type,
                         bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
-    {
     /* Original SPARC 32-bit ABI says that structures and unions,
        and quad-precision floats are passed by reference.  For Pascal,
        also pass arrays by reference.  All other base types are passed
@@ -5108,20 +5521,18 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
        integers are passed like floats of the same size, that is in
        registers up to 8 bytes.  Pass all vector floats by reference
        like structure and unions.  */
-      return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
-             || mode == SCmode
-             /* Catch CDImode, TFmode, DCmode and TCmode.  */
-             || GET_MODE_SIZE (mode) > 8
-             || (type
-                 && TREE_CODE (type) == VECTOR_TYPE
-                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
-    }
+    return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
+           || mode == SCmode
+           /* Catch CDImode, TFmode, DCmode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 8
+           || (type
+               && TREE_CODE (type) == VECTOR_TYPE
+               && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
   else
-    {
     /* Original SPARC 64-bit ABI says that structures and unions
        smaller than 16 bytes are passed in registers, as well as
-       all other base types.  For Pascal, pass arrays by reference.
-       
+       all other base types.
+
        Extended ABI (as implemented by the Sun compiler) says that
        complex floats are passed in registers up to 16 bytes.  Pass
        all complex integers in registers up to 16 bytes.  More generally,
@@ -5131,13 +5542,11 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
        integers are passed like floats of the same size, that is in
        registers (up to 16 bytes).  Pass all vector floats like structure
        and unions.  */
-      return ((type && TREE_CODE (type) == ARRAY_TYPE)
-             || (type
-                 && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
-                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
-             /* Catch CTImode and TCmode.  */
-             || GET_MODE_SIZE (mode) > 16);
-    }
+    return ((type
+            && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
+           /* Catch CTImode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 16);
 }
 
 /* Handle the FUNCTION_ARG_ADVANCE macro.
@@ -5191,7 +5600,7 @@ function_arg_advance (struct sparc_args *cum, enum machine_mode mode,
    argument slot.  */
 
 enum direction
-function_arg_padding (enum machine_mode mode, tree type)
+function_arg_padding (enum machine_mode mode, const_tree type)
 {
   if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
     return upward;
@@ -5204,7 +5613,7 @@ function_arg_padding (enum machine_mode mode, tree type)
    Specify whether to return the return value in memory.  */
 
 static bool
-sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+sparc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
     /* Original SPARC 32-bit ABI says that structures and unions,
@@ -5229,7 +5638,7 @@ sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
     /* Original SPARC 64-bit ABI says that structures and unions
        smaller than 32 bytes are returned in registers, as well as
        all other base types.
-       
+
        Extended ABI (as implemented by the Sun compiler) says that all
        complex floats are returned in registers (8 FP registers at most
        for '_Complex long double').  Return all complex integers in
@@ -5247,7 +5656,7 @@ sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
    Return where to find the structure return value address.  */
 
 static rtx
-sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
+sparc_struct_value_rtx (tree fndecl, int incoming)
 {
   if (TARGET_ARCH64)
     return 0;
@@ -5262,6 +5671,46 @@ sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
        mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
                                                 STRUCT_VALUE_OFFSET));
 
+      /* Only follow the SPARC ABI for fixed-size structure returns.
+         Variable size structure returns are handled per the normal
+         procedures in GCC. This is enabled by -mstd-struct-return */
+      if (incoming == 2
+         && sparc_std_struct_return
+         && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
+         && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
+       {
+         /* We must check and adjust the return address, as it is
+            optional as to whether the return object is really
+            provided.  */
+         rtx ret_rtx = gen_rtx_REG (Pmode, 31);
+         rtx scratch = gen_reg_rtx (SImode);
+         rtx endlab = gen_label_rtx ();
+
+         /* Calculate the return object size */
+         tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
+         rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
+         /* Construct a temporary return value */
+         rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+         /* Implement SPARC 32-bit psABI callee returns struck checking
+            requirements:
+
+             Fetch the instruction where we will return to and see if
+            it's an unimp instruction (the most significant 10 bits
+            will be zero).  */
+         emit_move_insn (scratch, gen_rtx_MEM (SImode,
+                                               plus_constant (ret_rtx, 8)));
+         /* Assume the size is valid and pre-adjust */
+         emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
+         emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         /* Assign stack temp:
+            Write the address of the memory pointed to by temp_val into
+            the memory pointed to by mem */
+         emit_move_insn (mem, XEXP (temp_val, 0));
+         emit_label (endlab);
+       }
+
       set_mem_alias_set (mem, struct_value_alias_set);
       return mem;
     }
@@ -5272,7 +5721,7 @@ sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
    except that up to 32 bytes may be returned in registers.  */
 
 rtx
-function_value (tree type, enum machine_mode mode, int incoming_p)
+function_value (const_tree type, enum machine_mode mode, int incoming_p)
 {
   /* Beware that the two values are swapped here wrt function_arg.  */
   int regbase = (incoming_p
@@ -5281,51 +5730,55 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
   enum mode_class mclass = GET_MODE_CLASS (mode);
   int regno;
 
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
   if (type && TREE_CODE (type) == VECTOR_TYPE)
     {
-      /* Vector types deserve special treatment because they are
-        polymorphic wrt their mode, depending upon whether VIS
-        instructions are enabled.  */
       HOST_WIDE_INT size = int_size_in_bytes (type);
-
       gcc_assert ((TARGET_ARCH32 && size <= 8)
                  || (TARGET_ARCH64 && size <= 32));
 
       if (mode == BLKmode)
        return function_arg_vector_value (size,
-                                         TYPE_MODE (TREE_TYPE (type)),
                                          SPARC_FP_ARG_FIRST);
       else
        mclass = MODE_FLOAT;
     }
-  else if (type && TARGET_ARCH64)
+
+  if (TARGET_ARCH64 && type)
     {
+      /* Structures up to 32 bytes in size are returned in registers.  */
       if (TREE_CODE (type) == RECORD_TYPE)
        {
-         /* Structures up to 32 bytes in size are passed in registers,
-            promoted to fp registers where possible.  */
-
-         gcc_assert (int_size_in_bytes (type) <= 32);
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+
+      /* Unions up to 32 bytes in size are returned in integer registers.  */
       else if (TREE_CODE (type) == UNION_TYPE)
        {
          HOST_WIDE_INT size = int_size_in_bytes (type);
-
          gcc_assert (size <= 32);
 
          return function_arg_union_value (size, mode, 0, regbase);
        }
+
+      /* Objects that require it are returned in FP registers.  */
+      else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+       ;
+
+      /* All other aggregate types are returned in an integer register in a
+        mode corresponding to the size of the type.  */
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
             in a mode corresponding to the size of the type.  */
-         HOST_WIDE_INT bytes = int_size_in_bytes (type);
-
-         gcc_assert (bytes <= 32);
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
-         mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
 
          /* ??? We probably should have made the same ABI change in
             3.4.0 as the one we made for unions.   The latter was
@@ -5337,17 +5790,18 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
             try to be unduly clever, and simply follow the ABI
             for unions in that case.  */
          if (mode == BLKmode)
-           return function_arg_union_value (bytes, mode, 0, regbase);
+           return function_arg_union_value (size, mode, 0, regbase);
          else
            mclass = MODE_INT;
        }
-      else if (mclass == MODE_INT
-              && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+
+      /* This must match sparc_promote_function_mode.
+        ??? Maybe 32-bit pointers should actually remain in Pmode?  */
+      else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        mode = word_mode;
     }
 
-  if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
-      && TARGET_FPU)
+  if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
     regno = SPARC_FP_ARG_FIRST;
   else
     regno = regbase;
@@ -5362,7 +5816,7 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
 static rtx
 sparc_builtin_saveregs (void)
 {
-  int first_reg = current_function_args_info.words;
+  int first_reg = crtl->args.info.words;
   rtx address;
   int regno;
 
@@ -5386,7 +5840,7 @@ sparc_builtin_saveregs (void)
 
 /* Implement `va_start' for stdarg.  */
 
-void
+static void
 sparc_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
@@ -5396,7 +5850,8 @@ sparc_va_start (tree valist, rtx nextarg)
 /* Implement `va_arg' for stdarg.  */
 
 static tree
-sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
+                      gimple_seq *post_p)
 {
   HOST_WIDE_INT size, rsize, align;
   tree addr, incr;
@@ -5415,7 +5870,7 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       size = int_size_in_bytes (type);
       rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
       align = 0;
-    
+
       if (TARGET_ARCH64)
        {
          /* For SPARC64, objects requiring 16-byte alignment get it.  */
@@ -5437,50 +5892,46 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   incr = valist;
   if (align)
     {
-      incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
-                          ssize_int (align - 1)));
-      incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
-                          ssize_int (-align)));
+      incr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                         size_int (align - 1));
+      incr = fold_convert (sizetype, incr);
+      incr = fold_build2 (BIT_AND_EXPR, sizetype, incr,
+                         size_int (-align));
+      incr = fold_convert (ptr_type_node, incr);
     }
 
   gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
   addr = incr;
 
   if (BYTES_BIG_ENDIAN && size < rsize)
-    addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
-                        ssize_int (rsize - size)));
+    addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                       size_int (rsize - size));
 
   if (indirect)
     {
       addr = fold_convert (build_pointer_type (ptrtype), addr);
       addr = build_va_arg_indirect_ref (addr);
     }
-  /* If the address isn't aligned properly for the type,
-     we may need to copy to a temporary.  
-     FIXME: This is inefficient.  Usually we can do this
-     in registers.  */
-  else if (align == 0
-          && TYPE_ALIGN (type) > BITS_PER_WORD)
+
+  /* If the address isn't aligned properly for the type, we need a temporary.
+     FIXME: This is inefficient, usually we can do this in registers.  */
+  else if (align == 0 && TYPE_ALIGN (type) > BITS_PER_WORD)
     {
       tree tmp = create_tmp_var (type, "va_arg_tmp");
       tree dest_addr = build_fold_addr_expr (tmp);
-
-      tree copy = build_function_call_expr
-       (implicit_built_in_decls[BUILT_IN_MEMCPY],
-        tree_cons (NULL_TREE, dest_addr,
-                   tree_cons (NULL_TREE, addr,
-                              tree_cons (NULL_TREE, size_int (rsize),
-                                         NULL_TREE))));
-
+      tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY],
+                                  3, dest_addr, addr, size_int (rsize));
+      TREE_ADDRESSABLE (tmp) = 1;
       gimplify_and_add (copy, pre_p);
       addr = dest_addr;
     }
+
   else
     addr = fold_convert (ptrtype, addr);
 
-  incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
-  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
-  gimplify_and_add (incr, post_p);
+  incr
+    = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
+  gimplify_assign (valist, incr, post_p);
 
   return build_va_arg_indirect_ref (addr);
 }
@@ -5781,41 +6232,45 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
 }
 
 /* Emit a library call comparison between floating point X and Y.
-   COMPARISON is the rtl operator to compare with (EQ, NE, GT, etc.).
+   COMPARISON is the operator to compare with (EQ, NE, GT, etc).
+   Return the new operator to be used in the comparison sequence.
+
    TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
    values as arguments instead of the TFmode registers themselves,
    that's why we cannot call emit_float_lib_cmp.  */
-void
+
+rtx
 sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
 {
   const char *qpfunc;
-  rtx slot0, slot1, result, tem, tem2;
+  rtx slot0, slot1, result, tem, tem2, libfunc;
   enum machine_mode mode;
+  enum rtx_code new_comparison;
 
   switch (comparison)
     {
     case EQ:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_feq" : "_Q_feq";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq");
       break;
 
     case NE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fne" : "_Q_fne";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne");
       break;
 
     case GT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fgt" : "_Q_fgt";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt");
       break;
 
     case GE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fge" : "_Q_fge";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge");
       break;
 
     case LT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_flt" : "_Q_flt";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt");
       break;
 
     case LE:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_fle" : "_Q_fle";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle");
       break;
 
     case ORDERED:
@@ -5826,7 +6281,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
     case UNGE:
     case UNLE:
     case LTGT:
-      qpfunc = (TARGET_ARCH64) ? "_Qp_cmp" : "_Q_cmp";
+      qpfunc = (TARGET_ARCH64 ? "_Qp_cmp" : "_Q_cmp");
       break;
 
     default:
@@ -5835,35 +6290,35 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
 
   if (TARGET_ARCH64)
     {
-      if (GET_CODE (x) != MEM)
+      if (MEM_P (x))
+       slot0 = x;
+      else
        {
          slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+         emit_move_insn (slot0, x);
        }
-      else
-       slot0 = x;
 
-      if (GET_CODE (y) != MEM)
+      if (MEM_P (y))
+       slot1 = y;
+      else
        {
          slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+         emit_move_insn (slot1, y);
        }
-      else
-       slot1 = y;
 
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
+      libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
+      emit_library_call (libfunc, LCT_NORMAL,
                         DImode, 2,
                         XEXP (slot0, 0), Pmode,
                         XEXP (slot1, 0), Pmode);
-
       mode = DImode;
     }
   else
     {
-      emit_library_call (gen_rtx_SYMBOL_REF (Pmode, qpfunc), LCT_NORMAL,
+      libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
+      emit_library_call (libfunc, LCT_NORMAL,
                         SImode, 2,
                         x, TFmode, y, TFmode);
-
       mode = SImode;
     }
 
@@ -5872,34 +6327,29 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
      register so reload doesn't clobber the value if it needs
      the return register for a spill reg.  */
   result = gen_reg_rtx (mode);
-  emit_move_insn (result, hard_libcall_value (mode));
+  emit_move_insn (result, hard_libcall_value (mode, libfunc));
 
   switch (comparison)
     {
     default:
-      emit_cmp_insn (result, const0_rtx, NE, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_NE (VOIDmode, result, const0_rtx);
     case ORDERED:
     case UNORDERED:
-      emit_cmp_insn (result, GEN_INT(3), comparison == UNORDERED ? EQ : NE,
-                    NULL_RTX, mode, 0);
-      break;
+      new_comparison = (comparison == UNORDERED ? EQ : NE);
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, GEN_INT(3));
     case UNGT:
     case UNGE:
-      emit_cmp_insn (result, const1_rtx,
-                    comparison == UNGT ? GT : NE, NULL_RTX, mode, 0);
-      break;
+      new_comparison = (comparison == UNGT ? GT : NE);
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, const1_rtx);
     case UNLE:
-      emit_cmp_insn (result, const2_rtx, NE, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_NE (VOIDmode, result, const2_rtx);
     case UNLT:
       tem = gen_reg_rtx (mode);
       if (TARGET_ARCH32)
        emit_insn (gen_andsi3 (tem, result, const1_rtx));
       else
        emit_insn (gen_anddi3 (tem, result, const1_rtx));
-      emit_cmp_insn (tem, const0_rtx, NE, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_NE (VOIDmode, tem, const0_rtx);
     case UNEQ:
     case LTGT:
       tem = gen_reg_rtx (mode);
@@ -5912,10 +6362,11 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
        emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
       else
        emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
-      emit_cmp_insn (tem2, const0_rtx, comparison == UNEQ ? EQ : NE,
-                    NULL_RTX, mode, 0);
-      break;
+      new_comparison = (comparison == UNEQ ? EQ : NE);
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, tem2, const0_rtx);
     }
+
+  gcc_unreachable ();
 }
 
 /* Generate an unsigned DImode to FP conversion.  This is the same code
@@ -6016,21 +6467,21 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
 
   /* branch on register are limited to +-128KB.  If it is too far away,
      change
-     
+
      brnz,pt %g1, .LC30
-     
+
      to
-     
+
      brz,pn %g1, .+12
       nop
      ba,pt %xcc, .LC30
-     
+
      and
-     
+
      brgez,a,pn %o1, .LC29
-     
+
      to
-     
+
      brlz,pt %o1, .+16
       nop
      ba,pt %xcc, .LC29  */
@@ -6233,7 +6684,7 @@ order_regs_for_local_alloc (void)
 {
   static int last_order_nonleaf = 1;
 
-  if (regs_ever_live[15] != last_order_nonleaf)
+  if (df_regs_ever_live_p (15) != last_order_nonleaf)
     {
       last_order_nonleaf = !last_order_nonleaf;
       memcpy ((char *) reg_alloc_order,
@@ -6282,7 +6733,7 @@ sparc_absnegfloat_split_legitimate (rtx x, rtx y)
 }
 
 /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
-   This makes them candidates for using ldd and std insns. 
+   This makes them candidates for using ldd and std insns.
 
    Note reg1 and reg2 *must* be hard registers.  */
 
@@ -6290,22 +6741,22 @@ int
 registers_ok_for_ldd_peep (rtx reg1, rtx reg2)
 {
   /* We might have been passed a SUBREG.  */
-  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 
+  if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
     return 0;
 
   if (REGNO (reg1) % 2 != 0)
     return 0;
 
-  /* Integer ldd is deprecated in SPARC V9 */ 
-  if (TARGET_V9 && REGNO (reg1) < 32)                  
-    return 0;                             
+  /* Integer ldd is deprecated in SPARC V9 */
+  if (TARGET_V9 && REGNO (reg1) < 32)
+    return 0;
 
   return (REGNO (reg1) == REGNO (reg2) - 1);
 }
 
 /* Return 1 if the addresses in mem1 and mem2 are suitable for use in
    an ldd or std insn.
-   
+
    This can only happen when addr1 and addr2, the addresses in mem1
    and mem2, are consecutive memory locations (addr1 + 4 == addr2).
    addr1 must also be aligned on a 64-bit boundary.
@@ -6348,10 +6799,10 @@ mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
   /* MEM1 should be aligned on a 64-bit boundary.  */
   if (MEM_ALIGN (mem1) < 64)
     return 0;
-  
+
   addr1 = XEXP (mem1, 0);
   addr2 = XEXP (mem2, 0);
-  
+
   /* Extract a register number and offset (if used) from the first addr.  */
   if (GET_CODE (addr1) == PLUS)
     {
@@ -6389,8 +6840,8 @@ mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
 
   if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx))
     return 0;
-  
-  /* The first offset must be evenly divisible by 8 to ensure the 
+
+  /* The first offset must be evenly divisible by 8 to ensure the
      address is 64 bit aligned.  */
   if (offset1 % 8 != 0)
     return 0;
@@ -6404,21 +6855,49 @@ mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
   return 1;
 }
 
-/* Return 1 if reg is a pseudo, or is the first register in 
-   a hard register pair.  This makes it a candidate for use in
+/* Return 1 if reg is a pseudo, or is the first register in
+   a hard register pair.  This makes it suitable for use in
    ldd and std insns.  */
 
 int
 register_ok_for_ldd (rtx reg)
 {
   /* We might have been passed a SUBREG.  */
-  if (GET_CODE (reg) != REG) 
+  if (!REG_P (reg))
     return 0;
 
   if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
     return (REGNO (reg) % 2 == 0);
-  else 
-    return 1;
+
+  return 1;
+}
+
+/* Return 1 if OP is a memory whose address is known to be
+   aligned to 8-byte boundary, or a pseudo during reload.
+   This makes it suitable for use in ldd and std insns.  */
+
+int
+memory_ok_for_ldd (rtx op)
+{
+  if (MEM_P (op))
+    {
+      /* In 64-bit mode, we assume that the address is word-aligned.  */
+      if (TARGET_ARCH32 && !mem_min_alignment (op, 8))
+       return 0;
+
+      if ((reload_in_progress || reload_completed)
+         && !strict_memory_address_p (Pmode, XEXP (op, 0)))
+       return 0;
+    }
+  else if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+    {
+      if (!(reload_in_progress && reg_renumber [REGNO (op)] < 0))
+       return 0;
+    }
+  else
+    return 0;
+
+  return 1;
 }
 \f
 /* Print operand X (an rtx) in assembler syntax to file FILE.
@@ -6459,14 +6938,19 @@ print_operand (FILE *file, rtx x, int code)
       /* Output the right displacement from the saved PC on function return.
         The caller may have placed an "unimp" insn immediately after the call
         so we have to account for it.  This insn is used in the 32-bit ABI
-        when calling a function that returns a non zero-sized structure. The
+        when calling a function that returns a non zero-sized structure.  The
         64-bit ABI doesn't have it.  Be careful to have this test be the same
-        as that used on the call.  */
-     if (! TARGET_ARCH64
-        && current_function_returns_struct
-        && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
-            == INTEGER_CST)
-        && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+        as that for the call.  The exception is when sparc_std_struct_return
+        is enabled, the psABI is followed exactly and the adjustment is made
+        by the code in sparc_struct_value_rtx.  The call emitted is the same
+        when sparc_std_struct_return is enabled. */
+     if (!TARGET_ARCH64
+        && cfun->returns_struct
+        && !sparc_std_struct_return
+        && DECL_SIZE (DECL_RESULT (current_function_decl))
+        && TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+            == INTEGER_CST
+        && !integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
        fputs ("12", file);
       else
         fputc ('8', file);
@@ -6799,7 +7283,7 @@ sparc_type_code (register tree type)
        {
        case ERROR_MARK:
          return qualifiers;
-  
+
        case ARRAY_TYPE:
          qualifiers |= (3 << shift);
          break;
@@ -6847,16 +7331,16 @@ sparc_type_code (register tree type)
 
          if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
            return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2));
-  
+
          else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
            return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3));
-  
+
          else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
            return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4));
-  
+
          else
            return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5));
-  
+
        case REAL_TYPE:
          /* If this is a range type, consider it to be the underlying
             type.  */
@@ -6869,9 +7353,9 @@ sparc_type_code (register tree type)
          if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
            return (qualifiers | 6);
 
-         else 
+         else
            return (qualifiers | 7);
-  
+
        case COMPLEX_TYPE:      /* GNU Fortran COMPLEX type.  */
          /* ??? We need to distinguish between double and float complex types,
             but I don't know how yet because I can't reach this code from
@@ -6879,11 +7363,10 @@ sparc_type_code (register tree type)
          return (qualifiers | 7);      /* Who knows? */
 
        case VECTOR_TYPE:
-       case CHAR_TYPE:         /* GNU Pascal CHAR type.  Not used in C.  */
-       case BOOLEAN_TYPE:      /* GNU Fortran BOOLEAN type.  */
+       case BOOLEAN_TYPE:      /* Boolean truth value type.  */
        case LANG_TYPE:         /* ? */
          return qualifiers;
-  
+
        default:
          gcc_unreachable ();           /* Not a type! */
         }
@@ -6905,8 +7388,8 @@ sparc_type_code (register tree type)
 
    Emit enough FLUSH insns to synchronize the data and instruction caches.  */
 
-void
-sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
+static void
+sparc32_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
 {
   /* SPARC 32-bit trampoline:
 
@@ -6920,7 +7403,7 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
    */
 
   emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
+    (adjust_address (m_tramp, SImode, 0),
      expand_binop (SImode, ior_optab,
                   expand_shift (RSHIFT_EXPR, SImode, fnaddr,
                                 size_int (10), 0, 1),
@@ -6928,7 +7411,7 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
                   NULL_RTX, 1, OPTAB_DIRECT));
 
   emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+    (adjust_address (m_tramp, SImode, 4),
      expand_binop (SImode, ior_optab,
                   expand_shift (RSHIFT_EXPR, SImode, cxt,
                                 size_int (10), 0, 1),
@@ -6936,14 +7419,14 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
                   NULL_RTX, 1, OPTAB_DIRECT));
 
   emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+    (adjust_address (m_tramp, SImode, 8),
      expand_binop (SImode, ior_optab,
                   expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
                   GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
                   NULL_RTX, 1, OPTAB_DIRECT));
 
   emit_move_insn
-    (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+    (adjust_address (m_tramp, SImode, 12),
      expand_binop (SImode, ior_optab,
                   expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
                   GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
@@ -6951,17 +7434,18 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 
   /* On UltraSPARC a flush flushes an entire cache line.  The trampoline is
      aligned on a 16 byte boundary so one flush clears it all.  */
-  emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
+  emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 0))));
   if (sparc_cpu != PROCESSOR_ULTRASPARC
-      && sparc_cpu != PROCESSOR_ULTRASPARC3)
-    emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
-                                                    plus_constant (tramp, 8)))));
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
+    emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 8))));
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
 #ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+                     LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
 #endif
 
 }
@@ -6970,8 +7454,8 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
    values as "immediate" data out of the trampoline.  It's also easier since
    we can read the PC without clobbering a register.  */
 
-void
-sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
+static void
+sparc64_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
 {
   /* SPARC 64-bit trampoline:
 
@@ -6982,29 +7466,44 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
        +16 bytes data
    */
 
-  emit_move_insn (gen_rtx_MEM (SImode, tramp),
+  emit_move_insn (adjust_address (m_tramp, SImode, 0),
                  GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 4)),
+  emit_move_insn (adjust_address (m_tramp, SImode, 4),
                  GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 8)),
+  emit_move_insn (adjust_address (m_tramp, SImode, 8),
                  GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
-  emit_move_insn (gen_rtx_MEM (SImode, plus_constant (tramp, 12)),
+  emit_move_insn (adjust_address (m_tramp, SImode, 12),
                  GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
-  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 16)), cxt);
-  emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
-  emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
+  emit_move_insn (adjust_address (m_tramp, DImode, 16), cxt);
+  emit_move_insn (adjust_address (m_tramp, DImode, 24), fnaddr);
+  emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 0))));
 
   if (sparc_cpu != PROCESSOR_ULTRASPARC
-      && sparc_cpu != PROCESSOR_ULTRASPARC3)
-    emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
+    emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 8))));
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
      the stack address is accessible.  */
 #ifdef ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+                     LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
 #endif
 }
+
+/* Worker for TARGET_TRAMPOLINE_INIT.  */
+
+static void
+sparc_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
+{
+  rtx fnaddr = force_reg (Pmode, XEXP (DECL_RTL (fndecl), 0));
+  cxt = force_reg (Pmode, cxt);
+  if (TARGET_ARCH64)
+    sparc64_initialize_trampoline (m_tramp, fnaddr, cxt);
+  else
+    sparc32_initialize_trampoline (m_tramp, fnaddr, cxt);
+}
 \f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
@@ -7109,13 +7608,13 @@ hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
          if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
            {
              if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
-                 || GET_CODE (SET_DEST (dep_pat)) != MEM        
+                 || GET_CODE (SET_DEST (dep_pat)) != MEM
                  || GET_CODE (SET_SRC (pat)) != MEM
                  || ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
                                    XEXP (SET_SRC (pat), 0)))
                return cost + 2;
 
-             return cost + 8;        
+             return cost + 8;
            }
          break;
 
@@ -7142,7 +7641,7 @@ hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
     default:
       break;
-    }    
+    }
 
   return cost;
 }
@@ -7169,12 +7668,14 @@ static void
 sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
                  int sched_verbose ATTRIBUTE_UNUSED,
                  int max_ready ATTRIBUTE_UNUSED)
-{
-}
-  
+{}
+
 static int
 sparc_use_sched_lookahead (void)
 {
+  if (sparc_cpu == PROCESSOR_NIAGARA
+      || sparc_cpu == PROCESSOR_NIAGARA2)
+    return 0;
   if (sparc_cpu == PROCESSOR_ULTRASPARC
       || sparc_cpu == PROCESSOR_ULTRASPARC3)
     return 4;
@@ -7190,6 +7691,8 @@ sparc_issue_rate (void)
 {
   switch (sparc_cpu)
     {
+    case PROCESSOR_NIAGARA:
+    case PROCESSOR_NIAGARA2:
     default:
       return 1;
     case PROCESSOR_V9:
@@ -7284,13 +7787,13 @@ sparc_defer_case_vector (rtx lab, rtx vec, int diff)
     sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
 }
 
-static void 
+static void
 sparc_output_addr_vec (rtx vec)
 {
   rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
   int idx, vlen = XVECLEN (body, 0);
 
-#ifdef ASM_OUTPUT_ADDR_VEC_START  
+#ifdef ASM_OUTPUT_ADDR_VEC_START
   ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
 #endif
 
@@ -7306,20 +7809,20 @@ sparc_output_addr_vec (rtx vec)
       ASM_OUTPUT_ADDR_VEC_ELT
        (asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
     }
-    
+
 #ifdef ASM_OUTPUT_ADDR_VEC_END
   ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
 #endif
 }
 
-static void 
+static void
 sparc_output_addr_diff_vec (rtx vec)
 {
   rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
   rtx base = XEXP (XEXP (body, 0), 0);
   int idx, vlen = XVECLEN (body, 1);
 
-#ifdef ASM_OUTPUT_ADDR_VEC_START  
+#ifdef ASM_OUTPUT_ADDR_VEC_START
   ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
 #endif
 
@@ -7338,7 +7841,7 @@ sparc_output_addr_diff_vec (rtx vec)
          CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
          CODE_LABEL_NUMBER (base));
     }
-    
+
 #ifdef ASM_OUTPUT_ADDR_VEC_END
   ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
 #endif
@@ -7355,12 +7858,12 @@ sparc_output_deferred_case_vectors (void)
     return;
 
   /* Align to cache line in the function's code section.  */
-  current_function_section (current_function_decl);
+  switch_to_section (current_function_section ());
 
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
   if (align > 0)
     ASM_OUTPUT_ALIGN (asm_out_file, align);
-  
+
   for (t = sparc_addr_list; t ; t = XEXP (t, 1))
     sparc_output_addr_vec (XEXP (t, 0));
   for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
@@ -7388,7 +7891,7 @@ sparc_check_64 (rtx x, rtx insn)
     y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
   if (flag_expensive_optimizations
-      && REG_N_SETS (REGNO (y)) == 1)
+      && df && DF_REG_DEF_COUNT (REGNO (y)) == 1)
     set_once = 1;
 
   if (insn == 0)
@@ -7474,26 +7977,25 @@ sparc_profile_hook (int labelno)
   char buf[32];
   rtx lab, fun;
 
-  ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
-  lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
   fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
-
-  emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+  if (NO_PROFILE_COUNTERS)
+    {
+      emit_library_call (fun, LCT_NORMAL, VOIDmode, 0);
+    }
+  else
+    {
+      ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
+      lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
+      emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+    }
 }
 \f
-#ifdef OBJECT_FORMAT_ELF
+/* Solaris implementation of TARGET_ASM_NAMED_SECTION.  */
+
 static void
-sparc_elf_asm_named_section (const char *name, unsigned int flags,
-                            tree decl)
+sparc_solaris_elf_asm_named_section (const char *name, unsigned int flags,
+                                    tree decl ATTRIBUTE_UNUSED)
 {
-  if (flags & SECTION_MERGE)
-    {
-      /* entsize cannot be expressed in this section attributes
-        encoding style.  */
-      default_elf_asm_named_section (name, flags, decl);
-      return;
-    }
-
   fprintf (asm_out_file, "\t.section\t\"%s\"", name);
 
   if (!(flags & SECTION_DEBUG))
@@ -7509,7 +8011,6 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags,
 
   fputc ('\n', asm_out_file);
 }
-#endif /* OBJECT_FORMAT_ELF */
 
 /* We do not allow indirect calls to be optimized into sibling calls.
 
@@ -7528,13 +8029,19 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags,
    the sibling call right?  Well, in the C++ case we can end up passing
    the pointer to the struct return area to a constructor (which returns
    void) and then nothing else happens.  Such a sibling call would look
-   valid without the added check here.  */
+   valid without the added check here.
+
+   VxWorks PIC PLT entries require the global pointer to be initialized
+   on entry.  We therefore can't emit sibling calls to them.  */
 static bool
 sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   return (decl
          && flag_delayed_branch
-         && (TARGET_ARCH64 || ! current_function_returns_struct));
+         && (TARGET_ARCH64 || ! cfun->returns_struct)
+         && !(TARGET_VXWORKS_RTP
+              && flag_pic
+              && !targetm.binds_local_p (decl)));
 }
 \f
 /* libfunc renaming.  */
@@ -7585,12 +8092,14 @@ sparc_init_libfuncs (void)
       set_conv_libfunc (sfix_optab,   SImode, TFmode, "_Q_qtoi");
       set_conv_libfunc (ufix_optab,   SImode, TFmode, "_Q_qtou");
       set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq");
+      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq");
 
       if (DITF_CONVERSION_LIBFUNCS)
        {
          set_conv_libfunc (sfix_optab,   DImode, TFmode, "_Q_qtoll");
          set_conv_libfunc (ufix_optab,   DImode, TFmode, "_Q_qtoull");
          set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
+         set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq");
        }
 
       if (SUN_CONVERSION_LIBFUNCS)
@@ -7635,8 +8144,8 @@ sparc_init_libfuncs (void)
 }
 \f
 #define def_builtin(NAME, CODE, TYPE) \
-  lang_hooks.builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \
-                              NULL_TREE)
+  add_builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \
+                       NULL_TREE)
 
 /* Implement the TARGET_INIT_BUILTINS target hook.
    Create builtin functions for special SPARC instructions.  */
@@ -7732,36 +8241,35 @@ sparc_vis_init_builtins (void)
 }
 
 /* Handle TARGET_EXPAND_BUILTIN target hook.
-   Expand builtin functions for sparc instrinsics.  */
+   Expand builtin functions for sparc intrinsics.  */
 
 static rtx
-sparc_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
-                     enum machine_mode tmode, int ignore ATTRIBUTE_UNUSED)
-{
-  tree arglist;
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+sparc_expand_builtin (tree exp, rtx target,
+                     rtx subtarget ATTRIBUTE_UNUSED,
+                     enum machine_mode tmode ATTRIBUTE_UNUSED,
+                     int ignore ATTRIBUTE_UNUSED)
+{
+  tree arg;
+  call_expr_arg_iterator iter;
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int icode = DECL_FUNCTION_CODE (fndecl);
   rtx pat, op[4];
   enum machine_mode mode[4];
   int arg_count = 0;
 
-  mode[arg_count] = tmode;
-
-  if (target == 0
-      || GET_MODE (target) != tmode
-      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
-    op[arg_count] = gen_reg_rtx (tmode);
+  mode[0] = insn_data[icode].operand[0].mode;
+  if (!target
+      || GET_MODE (target) != mode[0]
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode[0]))
+    op[0] = gen_reg_rtx (mode[0]);
   else
-    op[arg_count] = target;
+    op[0] = target;
 
-  for (arglist = TREE_OPERAND (exp, 1); arglist;
-       arglist = TREE_CHAIN (arglist))
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
-      tree arg = TREE_VALUE (arglist);
-
       arg_count++;
       mode[arg_count] = insn_data[icode].operand[arg_count].mode;
-      op[arg_count] = expand_expr (arg, NULL_RTX, VOIDmode, 0);
+      op[arg_count] = expand_normal (arg);
 
       if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count],
                                                              mode[arg_count]))
@@ -7790,75 +8298,215 @@ sparc_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
   return op[0];
 }
-\f
-int
-sparc_extra_constraint_check (rtx op, int c, int strict)
+
+static int
+sparc_vis_mul8x16 (int e8, int e16)
 {
-  int reload_ok_mem;
+  return (e8 * e16 + 128) / 256;
+}
 
-  if (TARGET_ARCH64
-      && (c == 'T' || c == 'U'))
-    return 0;
+/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified
+   by FNCODE.  All of the elements in ELTS0 and ELTS1 lists must be integer
+   constants.  A tree list with the results of the multiplications is returned,
+   and each element in the list is of INNER_TYPE.  */
 
-  switch (c)
-    {
-    case 'Q':
-      return fp_sethi_p (op);
+static tree
+sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
+{
+  tree n_elts = NULL_TREE;
+  int scale;
 
-    case 'R':
-      return fp_mov_p (op);
+  switch (fncode)
+    {
+    case CODE_FOR_fmul8x16_vis:
+      for (; elts0 && elts1;
+          elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                TREE_INT_CST_LOW (TREE_VALUE (elts1)));
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
 
-    case 'S':
-      return fp_high_losum_p (op);
+    case CODE_FOR_fmul8x16au_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (elts1));
 
-    case 'U':
-      if (! strict
-         || (GET_CODE (op) == REG
-             && (REGNO (op) < FIRST_PSEUDO_REGISTER
-                 || reg_renumber[REGNO (op)] >= 0)))
-       return register_ok_for_ldd (op);
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
 
-      return 0;
+    case CODE_FOR_fmul8x16al_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1)));
 
-    case 'W':
-    case 'T':
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
       break;
 
-    case 'Y':
-      return const_zero_operand (op, GET_MODE (op));
-
     default:
-      return 0;
+      gcc_unreachable ();
     }
 
-  /* Our memory extra constraints have to emulate the
-     behavior of 'm' and 'o' in order for reload to work
-     correctly.  */
-  if (GET_CODE (op) == MEM)
-    {
-      reload_ok_mem = 0;
-      if ((TARGET_ARCH64 || mem_min_alignment (op, 8))
-         && (! strict
-             || strict_memory_address_p (Pmode, XEXP (op, 0))))
-       reload_ok_mem = 1;
-    }
-  else
+  return nreverse (n_elts);
+
+}
+/* Handle TARGET_FOLD_BUILTIN target hook.
+   Fold builtin functions for SPARC intrinsics.  If IGNORE is true the
+   result of the function call is ignored.  NULL_TREE is returned if the
+   function could not be folded.  */
+
+static tree
+sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
+                   tree *args, bool ignore)
+{
+  tree arg0, arg1, arg2;
+  tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
+  enum insn_code icode = (enum insn_code) DECL_FUNCTION_CODE (fndecl);
+
+  if (ignore
+      && icode != CODE_FOR_alignaddrsi_vis
+      && icode != CODE_FOR_alignaddrdi_vis)
+    return fold_convert (rtype, integer_zero_node);
+
+  switch (icode)
     {
-      reload_ok_mem = (reload_in_progress
-                      && GET_CODE (op) == REG
-                      && REGNO (op) >= FIRST_PSEUDO_REGISTER
-                      && reg_renumber [REGNO (op)] < 0);
+    case CODE_FOR_fexpand_vis:
+      arg0 = args[0];
+      STRIP_NOPS (arg0);
+
+      if (TREE_CODE (arg0) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts = TREE_VECTOR_CST_ELTS (arg0);
+         tree n_elts = NULL_TREE;
+
+         for (; elts; elts = TREE_CHAIN (elts))
+           {
+             unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4;
+             n_elts = tree_cons (NULL_TREE,
+                                 build_int_cst (inner_type, val),
+                                 n_elts);
+           }
+         return build_vector (rtype, nreverse (n_elts));
+       }
+      break;
+
+    case CODE_FOR_fmul8x16_vis:
+    case CODE_FOR_fmul8x16au_vis:
+    case CODE_FOR_fmul8x16al_vis:
+      arg0 = args[0];
+      arg1 = args[1];
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = sparc_handle_vis_mul8x16 (icode, inner_type, elts0,
+                                                 elts1);
+
+         return build_vector (rtype, n_elts);
+       }
+      break;
+
+    case CODE_FOR_fpmerge_vis:
+      arg0 = args[0];
+      arg1 = args[1];
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = NULL_TREE;
+
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts);
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts);
+           }
+
+         return build_vector (rtype, nreverse (n_elts));
+       }
+      break;
+
+    case CODE_FOR_pdist_vis:
+      arg0 = args[0];
+      arg1 = args[1];
+      arg2 = args[2];
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+      STRIP_NOPS (arg2);
+
+      if (TREE_CODE (arg0) == VECTOR_CST
+         && TREE_CODE (arg1) == VECTOR_CST
+         && TREE_CODE (arg2) == INTEGER_CST)
+       {
+         int overflow = 0;
+         unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2);
+         HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             unsigned HOST_WIDE_INT
+               low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+               low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+             HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0));
+             HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1));
+
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             overflow |= neg_double (low1, high1, &l, &h);
+             overflow |= add_double (low0, high0, l, h, &l, &h);
+             if (h < 0)
+               overflow |= neg_double (l, h, &l, &h);
+
+             overflow |= add_double (low, high, l, h, &low, &high);
+           }
+
+         gcc_assert (overflow == 0);
+
+         return build_int_cst_wide (rtype, low, high);
+       }
+
+    default:
+      break;
     }
 
-  return reload_ok_mem;
+  return NULL_TREE;
 }
-
+\f
 /* ??? This duplicates information provided to the compiler by the
    ??? scheduler description.  Some day, teach genautomata to output
    ??? the latencies and then CSE will just use that.  */
 
 static bool
-sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
+sparc_rtx_costs (rtx x, int code, int outer_code, int *total,
+                bool speed ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = GET_MODE (x);
   bool float_mode_p = FLOAT_MODE_P (mode);
@@ -8056,19 +8704,36 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
     }
 }
 
-/* Emit the sequence of insns SEQ while preserving the register REG.  */
+/* Emit the sequence of insns SEQ while preserving the registers REG and REG2.
+   This is achieved by means of a manual dynamic stack space allocation in
+   the current frame.  We make the assumption that SEQ doesn't contain any
+   function calls, with the possible exception of calls to the PIC helper.  */
 
 static void
-emit_and_preserve (rtx seq, rtx reg)
+emit_and_preserve (rtx seq, rtx reg, rtx reg2)
 {
-  rtx slot = gen_rtx_MEM (word_mode,
-                         plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS));
+  /* We must preserve the lowest 16 words for the register save area.  */
+  HOST_WIDE_INT offset = 16*UNITS_PER_WORD;
+  /* We really need only 2 words of fresh stack space.  */
+  HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD);
+
+  rtx slot
+    = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx,
+                                            SPARC_STACK_BIAS + offset));
 
-  emit_insn (gen_stack_pointer_dec (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)));
+  emit_insn (gen_stack_pointer_dec (GEN_INT (size)));
   emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD),
+                           reg2));
   emit_insn (seq);
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           reg2,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD)));
   emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
-  emit_insn (gen_stack_pointer_inc (GEN_INT (STACK_BOUNDARY/BITS_PER_UNIT)));
+  emit_insn (gen_stack_pointer_inc (GEN_INT (size)));
 }
 
 /* Output the assembler code for a thunk function.  THUNK_DECL is the
@@ -8082,13 +8747,11 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                       HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
                       tree function)
 {
-  rtx this, insn, funexp;
+  rtx this_rtx, insn, funexp;
   unsigned int int_arg_first;
 
   reload_completed = 1;
   epilogue_completed = 1;
-  no_new_pseudos = 1;
-  reset_block_changes ();
 
   emit_note (NOTE_INSN_PROLOGUE_END);
 
@@ -8114,10 +8777,11 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   /* Find the "this" pointer.  Normally in %o0, but in ARCH64 if the function
      returns a structure, the structure return pointer is there instead.  */
-  if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
-    this = gen_rtx_REG (Pmode, int_arg_first + 1);
+  if (TARGET_ARCH64
+      && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
   else
-    this = gen_rtx_REG (Pmode, int_arg_first);
+    this_rtx = gen_rtx_REG (Pmode, int_arg_first);
 
   /* Add DELTA.  When possible use a plain add, otherwise load it into
      a register first.  */
@@ -8132,11 +8796,11 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          delta_rtx = scratch;
        }
 
-      /* THIS += DELTA.  */
-      emit_insn (gen_add2_insn (this, delta_rtx));
+      /* THIS_RTX += DELTA.  */
+      emit_insn (gen_add2_insn (this_rtx, delta_rtx));
     }
 
-  /* Add the word at address (*THIS + VCALL_OFFSET).  */
+  /* Add the word at address (*THIS_RTX + VCALL_OFFSET).  */
   if (vcall_offset)
     {
       rtx vcall_offset_rtx = GEN_INT (vcall_offset);
@@ -8144,8 +8808,8 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
       gcc_assert (vcall_offset < 0);
 
-      /* SCRATCH = *THIS.  */
-      emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
+      /* SCRATCH = *THIS_RTX.  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode, this_rtx));
 
       /* Prepare for adding VCALL_OFFSET.  The difficulty is that we
         may not have any available scratch register at this point.  */
@@ -8178,14 +8842,14 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
        }
 
-      /* SCRATCH = *(*THIS + VCALL_OFFSET).  */
+      /* SCRATCH = *(*THIS_RTX + VCALL_OFFSET).  */
       emit_move_insn (scratch, gen_rtx_MEM (Pmode,
                                            gen_rtx_PLUS (Pmode,
                                                          scratch,
                                                          vcall_offset_rtx)));
 
-      /* THIS += *(*THIS + VCALL_OFFSET).  */
-      emit_insn (gen_add2_insn (this, scratch));
+      /* THIS_RTX += *(*THIS_RTX + VCALL_OFFSET).  */
+      emit_insn (gen_add2_insn (this_rtx, scratch));
     }
 
   /* Generate a tail call to the target function.  */
@@ -8206,19 +8870,20 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* The hoops we have to jump through in order to generate a sibcall
         without using delay slots...  */
-      rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1);
+      rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1);
 
       if (flag_pic)
         {
          spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
+         spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
          start_sequence ();
          /* Delay emitting the PIC helper function because it needs to
             change the section and we are emitting assembly code.  */
-         load_pic_register (true);  /* clobbers %o7 */
-         scratch = legitimize_pic_address (funexp, Pmode, scratch);
+         load_pic_register ();  /* clobbers %o7 */
+         scratch = legitimize_pic_address (funexp, scratch);
          seq = get_insns ();
          end_sequence ();
-         emit_and_preserve (seq, spill_reg);
+         emit_and_preserve (seq, spill_reg, spill_reg2);
        }
       else if (TARGET_ARCH32)
        {
@@ -8247,7 +8912,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
              sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
              seq = get_insns ();
              end_sequence ();
-             emit_and_preserve (seq, spill_reg);
+             emit_and_preserve (seq, spill_reg, 0);
              break;
 
            default:
@@ -8265,7 +8930,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1);
@@ -8273,17 +8938,16 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   reload_completed = 0;
   epilogue_completed = 0;
-  no_new_pseudos = 0;
 }
 
 /* Return true if sparc_output_mi_thunk would be able to output the
    assembler code for the thunk function specified by the arguments
    it is passed, and false otherwise.  */
 static bool
-sparc_can_output_mi_thunk (tree thunk_fndecl ATTRIBUTE_UNUSED,
+sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
                           HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
                           HOST_WIDE_INT vcall_offset,
-                          tree function ATTRIBUTE_UNUSED)
+                          const_tree function ATTRIBUTE_UNUSED)
 {
   /* Bound the loop used in the default method above.  */
   return (vcall_offset >= -32768 || ! fixed_regs[5]);
@@ -8294,7 +8958,7 @@ sparc_can_output_mi_thunk (tree thunk_fndecl ATTRIBUTE_UNUSED,
 static struct machine_function *
 sparc_init_machine_status (void)
 {
-  return ggc_alloc_cleared (sizeof (struct machine_function));
+  return GGC_CNEW (struct machine_function);
 }
 
 /* Locate some local-dynamic symbol still in use by this function
@@ -8344,10 +9008,10 @@ sparc_dwarf_handle_frame_unspec (const char *label,
   dwarf2out_window_save (label);
 }
 
-/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
-void
+static void
 sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
   switch (size)
@@ -8365,15 +9029,204 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
   fputs (")", file);
 }
 
-static
-void sparc_file_end (void)
+/* Do whatever processing is required at the end of a file.  */
+
+static void
+sparc_file_end (void)
 {
-  /* If we haven't emitted the special PIC helper function, do so now.  */
-  if (pic_helper_symbol_name[0] && !pic_helper_emitted_p)
-    emit_pic_helper ();
+  /* If need to emit the special PIC helper function, do so now.  */
+  if (pic_helper_needed)
+    {
+      unsigned int regno = REGNO (pic_offset_table_rtx);
+      const char *pic_name = reg_names[regno];
+      char name[32];
+#ifdef DWARF2_UNWIND_INFO
+      bool do_cfi;
+#endif
+
+      get_pc_thunk_name (name, regno);
+      if (USE_HIDDEN_LINKONCE)
+       {
+         tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+                                 get_identifier (name),
+                                 build_function_type (void_type_node,
+                                                      void_list_node));
+         DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
+                                          NULL_TREE, void_type_node);
+         TREE_STATIC (decl) = 1;
+         make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
+         DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+         DECL_VISIBILITY_SPECIFIED (decl) = 1;
+         allocate_struct_function (decl, true);
+         current_function_decl = decl;
+         init_varasm_status ();
+         assemble_start_function (decl, name);
+       }
+      else
+       {
+         const int align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+          switch_to_section (text_section);
+         if (align > 0)
+           ASM_OUTPUT_ALIGN (asm_out_file, align);
+         ASM_OUTPUT_LABEL (asm_out_file, name);
+       }
+
+#ifdef DWARF2_UNWIND_INFO
+      do_cfi = dwarf2out_do_cfi_asm ();
+      if (do_cfi)
+       fprintf (asm_out_file, "\t.cfi_startproc\n");
+#endif
+      if (flag_delayed_branch)
+       fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
+                pic_name, pic_name);
+      else
+       fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
+                pic_name, pic_name);
+#ifdef DWARF2_UNWIND_INFO
+      if (do_cfi)
+       fprintf (asm_out_file, "\t.cfi_endproc\n");
+#endif
+    }
 
   if (NEED_INDICATE_EXEC_STACK)
     file_end_indicate_exec_stack ();
 }
 
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_TYPE.  */
+
+static const char *
+sparc_mangle_type (const_tree type)
+{
+  if (!TARGET_64BIT
+      && TYPE_MAIN_VARIANT (type) == long_double_type_node
+      && TARGET_LONG_DOUBLE_128)
+    return "g";
+
+  /* For all other types, use normal C++ mangling.  */
+  return NULL;
+}
+#endif
+
+/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
+   compare and swap on the word containing the byte or half-word.  */
+
+void
+sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+{
+  rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
+  rtx addr = gen_reg_rtx (Pmode);
+  rtx off = gen_reg_rtx (SImode);
+  rtx oldv = gen_reg_rtx (SImode);
+  rtx newv = gen_reg_rtx (SImode);
+  rtx oldvalue = gen_reg_rtx (SImode);
+  rtx newvalue = gen_reg_rtx (SImode);
+  rtx res = gen_reg_rtx (SImode);
+  rtx resv = gen_reg_rtx (SImode);
+  rtx memsi, val, mask, end_label, loop_label, cc;
+
+  emit_insn (gen_rtx_SET (VOIDmode, addr,
+                         gen_rtx_AND (Pmode, addr1, GEN_INT (-4))));
+
+  if (Pmode != SImode)
+    addr1 = gen_lowpart (SImode, addr1);
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_AND (SImode, addr1, GEN_INT (3))));
+
+  memsi = gen_rtx_MEM (SImode, addr);
+  set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
+
+  val = force_reg (SImode, memsi);
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_XOR (SImode, off,
+                                      GEN_INT (GET_MODE (mem) == QImode
+                                               ? 3 : 2))));
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_ASHIFT (SImode, off, GEN_INT (3))));
+
+  if (GET_MODE (mem) == QImode)
+    mask = force_reg (SImode, GEN_INT (0xff));
+  else
+    mask = force_reg (SImode, GEN_INT (0xffff));
+
+  emit_insn (gen_rtx_SET (VOIDmode, mask,
+                         gen_rtx_ASHIFT (SImode, mask, off)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, val,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      val)));
+
+  oldval = gen_lowpart (SImode, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_ASHIFT (SImode, oldval, off)));
+
+  newval = gen_lowpart_common (SImode, newval);
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_ASHIFT (SImode, newval, off)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_AND (SImode, oldv, mask)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_AND (SImode, newv, mask)));
+
+  end_label = gen_label_rtx ();
+  loop_label = gen_label_rtx ();
+  emit_label (loop_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, oldvalue,
+                         gen_rtx_IOR (SImode, oldv, val)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, newvalue,
+                         gen_rtx_IOR (SImode, newv, val)));
+
+  emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
+
+  emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, resv,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      res)));
+
+  cc = gen_compare_reg_1 (NE, resv, val);
+  emit_insn (gen_rtx_SET (VOIDmode, val, resv));
+
+  /* Use cbranchcc4 to separate the compare and branch!  */
+  emit_jump_insn (gen_cbranchcc4 (gen_rtx_NE (VOIDmode, cc, const0_rtx),
+                                 cc, const0_rtx, loop_label));
+
+  emit_label (end_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_AND (SImode, res, mask)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_LSHIFTRT (SImode, res, off)));
+
+  emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
+}
+
+/* Implement TARGET_FRAME_POINTER_REQUIRED.  */
+
+bool
+sparc_frame_pointer_required (void)
+{
+  return !(leaf_function_p () && only_leaf_regs_used ());
+}
+
+/* The way this is structured, we can't eliminate SFP in favor of SP
+   if the frame pointer is required: we want to use the SFP->HFP elimination
+   in that case.  But the test in update_eliminables doesn't know we are
+   assuming below that we only do the former elimination.  */
+
+bool
+sparc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+  return (to == HARD_FRAME_POINTER_REGNUM
+          || !targetm.frame_pointer_required ());
+}
+
 #include "gt-sparc.h"