OSDN Git Service

* doc/tm.texi.in (US_SOFTWARE_GOFAST): Don't document.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index d3d1af0..b37b851 100644 (file)
@@ -1,6 +1,6 @@
 /* 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, 2006, 2007
+   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,
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
-#include "real.h"
 #include "insn-config.h"
 #include "insn-codes.h"
 #include "conditions.h"
@@ -38,10 +37,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "insn-attr.h"
 #include "flags.h"
 #include "function.h"
+#include "except.h"
 #include "expr.h"
 #include "optabs.h"
 #include "recog.h"
-#include "toplev.h"
+#include "diagnostic-core.h"
 #include "ggc.h"
 #include "tm_p.h"
 #include "debug.h"
@@ -50,8 +50,10 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfglayout.h"
 #include "gimple.h"
 #include "langhooks.h"
+#include "reload.h"
 #include "params.h"
 #include "df.h"
+#include "dwarf2out.h"
 
 /* Processor costs */
 static const
@@ -280,10 +282,6 @@ static GTY(()) alias_set_type sparc_sr_alias_set;
 /* The alias set for the structure return value.  */
 static GTY(()) alias_set_type 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, sparc_compare_emitted;
-
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
    eliminate it.  You must use -fomit-frame-pointer to get that.  */
@@ -321,7 +319,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;
@@ -350,31 +348,32 @@ static HOST_WIDE_INT frame_base_offset;
 int sparc_indent_opcode = 0;
 
 static bool sparc_handle_option (size_t, const char *, int);
+static void sparc_option_override (void);
 static void sparc_init_modes (void);
-static void scan_record_type (tree, int *, int *, int *);
+static void scan_record_type (const_tree, int *, int *, int *);
 static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
-                               tree, int, int, int *, int *);
+                               const_tree, bool, bool, int *, int *);
 
 static int supersparc_adjust_cost (rtx, rtx, rtx, int);
 static int hypersparc_adjust_cost (rtx, rtx, rtx, int);
 
+static void sparc_emit_set_const32 (rtx, rtx);
+static void sparc_emit_set_const64 (rtx, rtx);
 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_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);
@@ -391,7 +390,7 @@ 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, tree, bool);
+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,
@@ -405,25 +404,57 @@ 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 *, bool);
-static bool sparc_promote_prototypes (const_tree);
+static rtx sparc_function_value (const_tree, const_tree, bool);
+static rtx sparc_libcall_value (enum machine_mode, const_rtx);
+static bool sparc_function_value_regno_p (const unsigned int);
 static rtx sparc_struct_value_rtx (tree, int);
+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 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 sparc_legitimize_tls_address (rtx);
+static rtx sparc_legitimize_pic_address (rtx, rtx);
+static rtx sparc_legitimize_address (rtx, rtx, enum machine_mode);
+static rtx sparc_delegitimize_address (rtx);
+static bool sparc_mode_dependent_address_p (const_rtx);
 static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
                                     enum machine_mode, const_tree, bool);
+static void sparc_function_arg_advance (CUMULATIVE_ARGS *,
+                                       enum machine_mode, const_tree, bool);
+static rtx sparc_function_arg_1 (const CUMULATIVE_ARGS *,
+                                enum machine_mode, const_tree, bool, bool);
+static rtx sparc_function_arg (CUMULATIVE_ARGS *,
+                              enum machine_mode, const_tree, bool);
+static rtx sparc_function_incoming_arg (CUMULATIVE_ARGS *,
+                                       enum machine_mode, const_tree, bool);
+static unsigned int sparc_function_arg_boundary (enum machine_mode,
+                                                const_tree);
 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);
+static void sparc_conditional_register_usage (void);
 #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
 static const char *sparc_mangle_type (const_tree);
 #endif
+static void sparc_trampoline_init (rtx, tree, rtx);
+static enum machine_mode sparc_preferred_simd_mode (enum machine_mode);
+\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.  */
@@ -448,16 +479,18 @@ enum processor_type sparc_cpu;
 /* Whether\fan FPU option was specified.  */
 static bool fpu_option_set = false;
 
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE.  */
+static const struct default_options sparc_option_optimization_table[] =
+  {
+    { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+    { OPT_LEVELS_NONE, 0, NULL, 0 }
+  };
+
 /* 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"
@@ -492,6 +525,13 @@ 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_DELEGITIMIZE_ADDRESS
+#define TARGET_DELEGITIMIZE_ADDRESS sparc_delegitimize_address
+#undef TARGET_MODE_DEPENDENT_ADDRESS_P
+#define TARGET_MODE_DEPENDENT_ADDRESS_P sparc_mode_dependent_address_p
+
 #undef TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN sparc_expand_builtin
 #undef TARGET_FOLD_BUILTIN
@@ -515,20 +555,15 @@ static bool fpu_option_set = false;
 #undef TARGET_ADDRESS_COST
 #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_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
-
-/* 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_const_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
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE sparc_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE sparc_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P sparc_function_value_regno_p
 
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
@@ -540,6 +575,14 @@ static bool fpu_option_set = false;
 #define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE sparc_function_arg_advance
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG sparc_function_arg
+#undef TARGET_FUNCTION_INCOMING_ARG
+#define TARGET_FUNCTION_INCOMING_ARG sparc_function_incoming_arg
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY sparc_function_arg_boundary
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
@@ -554,6 +597,9 @@ static bool fpu_option_set = false;
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p
 
+#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
+#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE sparc_preferred_simd_mode
+
 #undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
 #define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec
 
@@ -574,8 +620,12 @@ static bool fpu_option_set = false;
 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
 #undef TARGET_HANDLE_OPTION
 #define TARGET_HANDLE_OPTION sparc_handle_option
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE sparc_option_override
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE sparc_option_optimization_table
 
-#if TARGET_GNU_TLS
+#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
@@ -583,11 +633,26 @@ static bool fpu_option_set = false;
 #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
+
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE sparc_conditional_register_usage
+
 #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.  */
@@ -618,19 +683,19 @@ sparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
 /* Validate and override various options, and do some machine dependent
    initialization.  */
 
-void
-sparc_override_options (void)
+static void
+sparc_option_override (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}=.  */
@@ -689,12 +754,16 @@ sparc_override_options (void)
     /* UltraSPARC T1 */
     { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
     { "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9},
-    { 0, 0, 0, 0 }
+    { 0, (enum processor_type) 0, 0, 0 }
   };
   const struct cpu_table *cpu;
   const struct sparc_cpu_select *sel;
   int fpu;
-  
+
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
 #ifndef SPARC_BI_ARCH
   /* Check for unsupported architecture size.  */
   if (! TARGET_64BIT != DEFAULT_ARCH32_P)
@@ -711,7 +780,7 @@ sparc_override_options (void)
 
   /* Code model selection.  */
   sparc_cmodel = SPARC_DEFAULT_CMODEL;
-  
+
 #ifdef SPARC_BI_ARCH
   if (TARGET_ARCH32)
     sparc_cmodel = CM_32;
@@ -794,7 +863,7 @@ 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
@@ -862,33 +931,25 @@ sparc_override_options (void)
     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));
+  maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
+                        ((sparc_cpu == PROCESSOR_ULTRASPARC
+                          || sparc_cpu == PROCESSOR_NIAGARA
+                          || sparc_cpu == PROCESSOR_NIAGARA2)
+                         ? 2
+                         : (sparc_cpu == PROCESSOR_ULTRASPARC3
+                            ? 8 : 3)),
+                        global_options.x_param_values,
+                        global_options_set.x_param_values);
+  maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
+                        ((sparc_cpu == PROCESSOR_ULTRASPARC
+                          || sparc_cpu == PROCESSOR_ULTRASPARC3
+                          || sparc_cpu == PROCESSOR_NIAGARA
+                          || sparc_cpu == PROCESSOR_NIAGARA2)
+                         ? 64 : 32),
+                        global_options.x_param_values,
+                        global_options_set.x_param_values);
 }
 \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 }
-};
-#endif
-\f
 /* Miscellaneous utilities.  */
 
 /* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
@@ -964,6 +1025,36 @@ fp_high_losum_p (rtx op)
   return 0;
 }
 
+/* Return true if the address of LABEL can be loaded by means of the
+   mov{si,di}_pic_label_ref patterns in PIC mode.  */
+
+static bool
+can_use_mov_pic_label_ref (rtx label)
+{
+  /* 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 GOT-relative
+     accesses are never valid on VxWorks.  */
+  if (TARGET_VXWORKS_RTP)
+    return false;
+
+  /* Similarly, if the label is non-local, it might end up being placed
+     in a different section than the current one; now mov_pic_label_ref
+     requires the label and the code to be in the same section.  */
+  if (LABEL_REF_NONLOCAL_P (label))
+    return false;
+
+  /* Finally, if we are reordering basic blocks and partition into hot
+     and cold sections, this might happen for any label.  */
+  if (flag_reorder_blocks_and_partition)
+    return false;
+
+  return true;
+}
+
 /* Expand a move instruction.  Return true if all work is done.  */
 
 bool
@@ -986,43 +1077,21 @@ sparc_expand_move (enum machine_mode mode, rtx *operands)
   /* Fixup TLS cases.  */
   if (TARGET_HAVE_TLS
       && CONSTANT_P (operands[1])
-      && GET_CODE (operands[1]) != HIGH
       && sparc_tls_referenced_p (operands [1]))
     {
-      rtx sym = operands[1];
-      rtx addend = NULL;
-
-      if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS)
-       {
-         addend = XEXP (XEXP (sym, 0), 1);
-         sym = XEXP (XEXP (sym, 0), 0);
-       }
-
-      gcc_assert (SPARC_SYMBOL_REF_TLS_P (sym));
-
-      sym = legitimize_tls_address (sym);
-      if (addend)
-       {
-         sym = gen_rtx_PLUS (mode, sym, addend);
-         sym = force_operand (sym, operands[0]);
-       }
-      operands[1] = sym;
+      operands[1] = sparc_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], mode, 0);
+       operands[1] = sparc_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)
+      /* We cannot use the mov{si,di}_pic_label_ref patterns in all cases.  */
+      if (GET_CODE (operands[1]) == LABEL_REF
+         && can_use_mov_pic_label_ref (operands[1]))
        {
          if (mode == SImode)
            {
@@ -1040,11 +1109,10 @@ sparc_expand_move (enum machine_mode mode, rtx *operands)
 
       if (symbolic_operand (operands[1], mode))
        {
-         operands[1] = legitimize_pic_address (operands[1],
-                                               mode,
-                                               (reload_in_progress ?
-                                                operands[0] :
-                                                NULL_RTX));
+         operands[1]
+           = sparc_legitimize_pic_address (operands[1],
+                                           reload_in_progress
+                                           ? operands[0] : NULL_RTX);
          return false;
        }
     }
@@ -1104,7 +1172,7 @@ sparc_expand_move (enum machine_mode mode, rtx *operands)
       /* input_operand should have filtered out 32-bit mode.  */
       sparc_emit_set_const64 (operands[0], operands[1]);
       return true;
-    
+
     default:
       gcc_unreachable ();
     }
@@ -1116,7 +1184,7 @@ sparc_expand_move (enum machine_mode mode, rtx *operands)
    We know it can't be done in one insn when we get
    here, the move expander guarantees this.  */
 
-void
+static void
 sparc_emit_set_const32 (rtx op0, rtx op1)
 {
   enum machine_mode mode = GET_MODE (op0);
@@ -1358,7 +1426,7 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 }
 
 #if HOST_BITS_PER_WIDE_INT == 32
-void
+static void
 sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
 {
   gcc_unreachable ();
@@ -1715,7 +1783,7 @@ create_simple_focus_bits (unsigned HOST_WIDE_INT high_bits,
    being loaded into a register.  Emit the most efficient
    insn sequence possible.  Detection of all the 1-insn cases
    has been done already.  */
-void
+static void
 sparc_emit_set_const64 (rtx op0, rtx op1)
 {
   unsigned HOST_WIDE_INT high_bits, low_bits;
@@ -1941,10 +2009,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
     }
 
   /* The easiest way when all else fails, is full decomposition.  */
-#if 0
-  printf ("sparc_emit_set_const64: Hard constant [%08lx%08lx] neg[%08lx%08lx]\n",
-         high_bits, low_bits, ~high_bits, ~low_bits);
-#endif
   sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
 }
 #endif /* HOST_BITS_PER_WIDE_INT == 32 */
@@ -2001,22 +2065,19 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
     }
 }
 
-/* Emit the compare insn and return the CC reg for a CODE comparison.  */
+/* 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)
+static rtx
+gen_compare_reg_1 (enum rtx_code code, rtx x, rtx y)
 {
-  rtx x = sparc_compare_op0;
-  rtx y = sparc_compare_op1;
-  enum machine_mode mode = SELECT_CC_MODE (code, x, y);
+  enum machine_mode mode;
   rtx cc_reg;
 
-  if (sparc_compare_emitted != NULL_RTX)
-    {
-      cc_reg = sparc_compare_emitted;
-      sparc_compare_emitted = NULL_RTX;
-      return 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
@@ -2071,26 +2132,19 @@ gen_compare_reg (enum rtx_code code)
   return cc_reg;
 }
 
-/* Same as above but return the whole compare operator.  */
+
+/* Emit the compare insn and return the CC reg for the comparison in CMP.  */
 
 rtx
-gen_compare_operator (enum rtx_code code)
+gen_compare_reg (rtx cmp)
 {
-  rtx cc_reg;
-
-  if (GET_MODE (sparc_compare_op0) == TFmode && !TARGET_HARD_QUAD)
-    code
-      = sparc_emit_float_lib_cmp (sparc_compare_op0, sparc_compare_op1, code);
-
-  cc_reg = gen_compare_reg (code);
-  return gen_rtx_fmt_ee (code, GET_MODE (cc_reg), cc_reg, const0_rtx);
+  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
 
@@ -2104,53 +2158,50 @@ gen_compare_operator (enum rtx_code code)
 
    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)
 {
   if (! TARGET_ARCH64
-      && (GET_MODE (sparc_compare_op0) == DImode
-         || GET_MODE (operands[0]) == DImode))
+      && (GET_MODE (x) == DImode
+         || GET_MODE (dest) == DImode))
     return 0;
 
   /* Try to use the movrCC insns.  */
   if (TARGET_ARCH64
-      && GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_INT
-      && sparc_compare_op1 == const0_rtx
+      && GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
+      && y == const0_rtx
       && v9_regcmp_p (compare_code))
     {
-      rtx op0 = sparc_compare_op0;
+      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);
@@ -2158,47 +2209,137 @@ 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);
+      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)
 {
-  gcc_assert (sparc_compare_emitted == NULL_RTX);
   emit_jump_insn (gen_rtx_SET (VOIDmode,
                           pc_rtx,
                           gen_rtx_IF_THEN_ELSE (VOIDmode,
@@ -2208,6 +2349,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.
@@ -2817,9 +2989,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.  */
@@ -2843,7 +3014,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
@@ -2865,23 +3036,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
-         && SPARC_SYMBOL_REF_TLS_P (XEXP (inner, 0)))
+    case SYMBOL_REF:
+      if (sparc_tls_referenced_p (x))
        return false;
       break;
 
@@ -2948,19 +3107,16 @@ legitimate_pic_operand_p (rtx x)
 {
   if (pic_address_needs_scratch (x))
     return false;
-  if (SPARC_SYMBOL_REF_TLS_P (x)
-      || (GET_CODE (x) == CONST
-         && GET_CODE (XEXP (x, 0)) == PLUS
-         && SPARC_SYMBOL_REF_TLS_P (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;
 
@@ -2989,7 +3145,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
-          && ! SPARC_SYMBOL_REF_TLS_P (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)
@@ -3029,7 +3185,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) || SPARC_SYMBOL_REF_TLS_P (rs1))
+         if (!CONSTANT_P (imm1)
+             || (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
            return 0;
        }
     }
@@ -3038,7 +3195,8 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
       rs1 = XEXP (addr, 0);
       imm1 = XEXP (addr, 1);
 
-      if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (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
@@ -3114,30 +3272,29 @@ sparc_tls_got (void)
   return temp;
 }
 
-/* Return 1 if *X is a thread-local symbol.  */
+/* Return true if X contains a thread-local symbol.  */
 
-static int
-sparc_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
-{
-  return SPARC_SYMBOL_REF_TLS_P (*x);
-}
-
-/* Return 1 if X contains a thread-local symbol.  */
-
-bool
+static bool
 sparc_tls_referenced_p (rtx x)
 {
   if (!TARGET_HAVE_TLS)
     return false;
 
-  return for_each_rtx (&x, &sparc_tls_symbol_ref_1, 0);
+  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 sparc_legitimize_tls_address for now.  */
+  return false;
 }
 
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
 
-rtx
-legitimize_tls_address (rtx addr)
+static rtx
+sparc_legitimize_tls_address (rtx addr)
 {
   rtx temp1, temp2, temp3, ret, o0, got, insn;
 
@@ -3260,25 +3417,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 = sparc_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
+sparc_legitimize_pic_address (rtx orig, rtx reg)
 {
+  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))
+      || (GET_CODE (orig) == LABEL_REF && !can_use_mov_pic_label_ref (orig)))
     {
       rtx pic_ref, address;
       rtx insn;
@@ -3312,15 +3484,32 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
              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));
       crtl->uses_pic_offset_table = 1;
-      insn = emit_move_insn (reg, pic_ref);
+      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.  */
       set_unique_reg_note (insn, REG_EQUAL, orig);
@@ -3341,9 +3530,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 = sparc_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
+      offset = sparc_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
+                                            base == reg ? NULL_RTX : reg);
 
       if (GET_CODE (offset) == CONST_INT)
        {
@@ -3358,9 +3547,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       return gen_rtx_PLUS (Pmode, base, offset);
     }
   else if (GET_CODE (orig) == LABEL_REF)
-    /* ??? 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.  */
+    /* ??? We ought to be checking that the register is live instead, in case
+       it is eliminated.  */
     crtl->uses_pic_offset_table = 1;
 
   return orig;
@@ -3372,10 +3560,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;
 
@@ -3392,13 +3583,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 (SPARC_SYMBOL_REF_TLS_P (x))
-    x = legitimize_tls_address (x);
+  if (sparc_tls_referenced_p (x))
+    x = sparc_legitimize_tls_address (x);
   else if (flag_pic)
-    x = legitimize_pic_address (x, mode, 0);
+    x = sparc_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)));
@@ -3407,39 +3598,133 @@ 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.  */
+/* Delegitimize an address that was legitimized by the above function.  */
+
+static rtx
+sparc_delegitimize_address (rtx x)
+{
+  x = delegitimize_mem_from_attrs (x);
+
+  if (GET_CODE (x) == LO_SUM
+      && GET_CODE (XEXP (x, 1)) == UNSPEC
+      && XINT (XEXP (x, 1), 1) == UNSPEC_TLSLE)
+    {
+      x = XVECEXP (XEXP (x, 1), 0, 0);
+      gcc_assert (GET_CODE (x) == SYMBOL_REF);
+    }
+
+  return x;
+}
+
+/* SPARC implementation of LEGITIMIZE_RELOAD_ADDRESS.  Returns a value to
+   replace the input X, or the original X if no replacement is called for.
+   The output parameter *WIN is 1 if the calling macro should goto WIN,
+   0 if it should not.
+
+   For SPARC, we wish to handle addresses by splitting them into
+   HIGH+LO_SUM pairs, retaining the LO_SUM in the memory reference.
+   This cuts the number of extra insns by one.
+
+   Do nothing when generating PIC code and the address is a symbolic
+   operand or requires a scratch register.  */
+
+rtx
+sparc_legitimize_reload_address (rtx x, enum machine_mode mode,
+                                int opnum, int type,
+                                int ind_levels ATTRIBUTE_UNUSED, int *win)
+{
+  /* Decompose SImode constants into HIGH+LO_SUM.  */
+  if (CONSTANT_P (x)
+      && (mode != TFmode || TARGET_ARCH64)
+      && GET_MODE (x) == SImode
+      && GET_CODE (x) != LO_SUM
+      && GET_CODE (x) != HIGH
+      && sparc_cmodel <= CM_MEDLOW
+      && !(flag_pic
+          && (symbolic_operand (x, Pmode) || pic_address_needs_scratch (x))))
+    {
+      x = gen_rtx_LO_SUM (GET_MODE (x), gen_rtx_HIGH (GET_MODE (x), x), x);
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
+      *win = 1;
+      return x;
+    }
+
+  /* We have to recognize what we have already generated above.  */
+  if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == HIGH)
+    {
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, (enum reload_type)type);
+      *win = 1;
+      return x;
+    }
+
+  *win = 0;
+  return x;
+}
+
+/* Return true if ADDR (a legitimate address expression)
+   has an effect that depends on the machine mode it is used for.
+
+   In PIC mode,
+
+      (mem:HI [%l7+a])
+
+   is not equivalent to
+
+      (mem:QI [%l7+a]) (mem:QI [%l7+a+1])
+
+   because [%l7+a+1] is interpreted as the address of (a+1).  */
+
+
+static bool
+sparc_mode_dependent_address_p (const_rtx addr)
+{
+  if (flag_pic && GET_CODE (addr) == PLUS)
+    {
+      rtx op0 = XEXP (addr, 0);
+      rtx op1 = XEXP (addr, 1);
+      if (op0 == pic_offset_table_rtx
+         && SYMBOLIC_CONST (op1))
+       return true;
+    }
+
+  return false;
+}
+
+#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];
 
-  switch_to_section (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;
 
@@ -3451,18 +3736,18 @@ load_pic_register (bool delay_pic_helper)
     }
 
   /* 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,
@@ -3577,7 +3862,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;
 }
@@ -3616,27 +3901,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)
@@ -3725,7 +4005,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:
@@ -3744,7 +4024,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:
@@ -3866,6 +4146,160 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
 #endif
 }
 
+#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
+
+#if PROBE_INTERVAL > 4096
+#error Cannot use indexed addressing mode for stack probing
+#endif
+
+/* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
+   inclusive.  These are offsets from the current stack pointer.
+
+   Note that we don't use the REG+REG addressing mode for the probes because
+   of the stack bias in 64-bit mode.  And it doesn't really buy us anything
+   so the advantages of having a single code win here.  */
+
+static void
+sparc_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
+{
+  rtx g1 = gen_rtx_REG (Pmode, 1);
+
+  /* See if we have a constant small number of probes to generate.  If so,
+     that's the easy case.  */
+  if (size <= PROBE_INTERVAL)
+    {
+      emit_move_insn (g1, GEN_INT (first));
+      emit_insn (gen_rtx_SET (VOIDmode, g1,
+                             gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
+      emit_stack_probe (plus_constant (g1, -size));
+    }
+
+  /* The run-time loop is made up of 10 insns in the generic case while the
+     compile-time loop is made up of 4+2*(n-2) insns for n # of intervals.  */
+  else if (size <= 5 * PROBE_INTERVAL)
+    {
+      HOST_WIDE_INT i;
+
+      emit_move_insn (g1, GEN_INT (first + PROBE_INTERVAL));
+      emit_insn (gen_rtx_SET (VOIDmode, g1,
+                             gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
+      emit_stack_probe (g1);
+
+      /* Probe at FIRST + N * PROBE_INTERVAL for values of N from 2 until
+        it exceeds SIZE.  If only two probes are needed, this will not
+        generate any code.  Then probe at FIRST + SIZE.  */
+      for (i = 2 * PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode, g1,
+                                 plus_constant (g1, -PROBE_INTERVAL)));
+         emit_stack_probe (g1);
+       }
+
+      emit_stack_probe (plus_constant (g1, (i - PROBE_INTERVAL) - size));
+    }
+
+  /* Otherwise, do the same as above, but in a loop.  Note that we must be
+     extra careful with variables wrapping around because we might be at
+     the very top (or the very bottom) of the address space and we have
+     to be able to handle this case properly; in particular, we use an
+     equality test for the loop condition.  */
+  else
+    {
+      HOST_WIDE_INT rounded_size;
+      rtx g4 = gen_rtx_REG (Pmode, 4);
+
+      emit_move_insn (g1, GEN_INT (first));
+
+
+      /* Step 1: round SIZE to the previous multiple of the interval.  */
+
+      rounded_size = size & -PROBE_INTERVAL;
+      emit_move_insn (g4, GEN_INT (rounded_size));
+
+
+      /* Step 2: compute initial and final value of the loop counter.  */
+
+      /* TEST_ADDR = SP + FIRST.  */
+      emit_insn (gen_rtx_SET (VOIDmode, g1,
+                             gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
+
+      /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE.  */
+      emit_insn (gen_rtx_SET (VOIDmode, g4, gen_rtx_MINUS (Pmode, g1, g4)));
+
+
+      /* Step 3: the loop
+
+        while (TEST_ADDR != LAST_ADDR)
+          {
+            TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
+            probe at TEST_ADDR
+          }
+
+        probes at FIRST + N * PROBE_INTERVAL for values of N from 1
+        until it is equal to ROUNDED_SIZE.  */
+
+      if (TARGET_64BIT)
+       emit_insn (gen_probe_stack_rangedi (g1, g1, g4));
+      else
+       emit_insn (gen_probe_stack_rangesi (g1, g1, g4));
+
+
+      /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
+        that SIZE is equal to ROUNDED_SIZE.  */
+
+      if (size != rounded_size)
+       emit_stack_probe (plus_constant (g4, rounded_size - size));
+    }
+
+  /* Make sure nothing is scheduled before we are done.  */
+  emit_insn (gen_blockage ());
+}
+
+/* Probe a range of stack addresses from REG1 to REG2 inclusive.  These are
+   absolute addresses.  */
+
+const char *
+output_probe_stack_range (rtx reg1, rtx reg2)
+{
+  static int labelno = 0;
+  char loop_lab[32], end_lab[32];
+  rtx xops[2];
+
+  ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno);
+  ASM_GENERATE_INTERNAL_LABEL (end_lab, "LPSRE", labelno++);
+
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
+
+   /* Jump to END_LAB if TEST_ADDR == LAST_ADDR.  */
+  xops[0] = reg1;
+  xops[1] = reg2;
+  output_asm_insn ("cmp\t%0, %1", xops);
+  if (TARGET_ARCH64)
+    fputs ("\tbe,pn\t%xcc,", asm_out_file);
+  else
+    fputs ("\tbe\t", asm_out_file);
+  assemble_name_raw (asm_out_file, end_lab);
+  fputc ('\n', asm_out_file);
+
+  /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL.  */
+  xops[1] = GEN_INT (-PROBE_INTERVAL);
+  output_asm_insn (" add\t%0, %1, %0", xops);
+
+  /* Probe at TEST_ADDR and branch.  */
+  if (TARGET_ARCH64)
+    fputs ("\tba,pt\t%xcc,", asm_out_file);
+  else
+    fputs ("\tba\t", asm_out_file);
+  assemble_name_raw (asm_out_file, loop_lab);
+  fputc ('\n', asm_out_file);
+  xops[1] = GEN_INT (SPARC_STACK_BIAS);
+  output_asm_insn (" st\t%%g0, [%0+%1]", xops);
+
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab);
+
+  return "";
+}
+
 /* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
    as needed.  LOW should be double-word aligned for 32-bit registers.
    Return the new OFFSET.  */
@@ -4054,6 +4488,12 @@ sparc_expand_prologue (void)
   /* Advertise that the data calculated just above are now valid.  */
   sparc_prologue_data_valid_p = true;
 
+  if (flag_stack_usage)
+    current_function_static_stack_size = actual_fsize;
+
+  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && actual_fsize)
+    sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, actual_fsize);
+
   if (sparc_leaf_function_p)
     {
       frame_base_reg = stack_pointer_rtx;
@@ -4084,10 +4524,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,
-                              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;
@@ -4119,9 +4557,9 @@ sparc_expand_prologue (void)
 
   /* Load the PIC register if needed.  */
   if (flag_pic && crtl->uses_pic_offset_table)
-    load_pic_register (false);
+    load_pic_register ();
 }
+
 /* This function generates the assembly code for function entry, which boils
    down to emitting the necessary .register directives.  */
 
@@ -4172,17 +4610,17 @@ 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)
 {
-  /* If code does not drop into the epilogue, we have to still output
-     a dummy nop for the sake of sane backtraces.  Otherwise, if the
-     last two instructions of a function were "call foo; dslot;" this
-     can make the return PC of foo (i.e. address of call instruction
-     plus 8) point to the first instruction in the next function.  */
+  /* If the last two instructions of a function are "call foo; dslot;"
+     the return address might point to the first instruction in the next
+     function and we have to output a dummy nop for the sake of sane
+     backtraces in such cases.  This is pointless for sibling calls since
+     the return address is explicitly adjusted.  */
 
   rtx insn, last_real_insn;
 
@@ -4194,14 +4632,16 @@ sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
     last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
 
-  if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
+  if (last_real_insn
+      && CALL_P (last_real_insn)
+      && !SIBLING_CALL_P (last_real_insn))
     fputs("\tnop\n", file);
 
   sparc_output_deferred_case_vectors ();
 }
-  
+
 /* Output a 'restore' instruction.  */
+
 static void
 output_restore (rtx pat)
 {
@@ -4241,7 +4681,7 @@ output_restore (rtx pat)
        break;
     }
 }
-  
+
 /* Output a return.  */
 
 const char *
@@ -4424,7 +4864,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
@@ -4493,7 +4933,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.  */
 
 
@@ -4519,13 +4959,27 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
   cum->libcall_p = fntype == 0;
 }
 
-/* Handle the TARGET_PROMOTE_PROTOTYPES target hook.
-   When a prototype says `char' or `short', really pass an `int'.  */
+/* Handle promotion of pointer and integer arguments.  */
 
-static bool
-sparc_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
+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)
 {
-  return TARGET_ARCH32 ? true : false;
+  if (POINTER_TYPE_P (type))
+    {
+      *punsignedp = POINTERS_EXTEND_UNSIGNED;
+      return Pmode;
+    }
+
+  /* Integral arguments are passed as full words, as per the ABI.  */
+  if (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.  */
@@ -4546,11 +5000,12 @@ sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
    Sub-fields are not taken into account for the PACKED_P predicate.  */
 
 static void
-scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
+scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
+                 int *packed_p)
 {
   tree field;
 
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     {
       if (TREE_CODE (field) == FIELD_DECL)
        {
@@ -4586,7 +5041,7 @@ scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
 
 static int
 function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
-                    tree type, int named, int incoming_p,
+                    const_tree type, bool named, bool incoming_p,
                     int *pregno, int *ppadding)
 {
   int regbase = (incoming_p
@@ -4770,7 +5225,7 @@ function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
       }
 
   /* Compute how many registers we need.  */
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     {
       if (TREE_CODE (field) == FIELD_DECL)
        {
@@ -4843,7 +5298,7 @@ function_arg_record_value_1 (const_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)
 {
@@ -4909,7 +5364,7 @@ function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
   tree field;
 
   if (! packed_p)
-    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
       {
        if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
          {
@@ -4918,7 +5373,7 @@ function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
          }
       }
 
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+  for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
     {
       if (TREE_CODE (field) == FIELD_DECL)
        {
@@ -4994,10 +5449,10 @@ function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
     }
 }
 
-/* Used by function_arg and function_value to implement the complex
+/* Used by function_arg and sparc_function_value_1 to implement the complex
    conventions of the 64-bit ABI for passing and returning structures.
-   Return an expression valid as a return value for the two macros
-   FUNCTION_ARG and FUNCTION_VALUE.
+   Return an expression valid as a return value for the FUNCTION_ARG
+   and TARGET_FUNCTION_VALUE.
 
    TYPE is the data type of the argument (as a tree).
     This is null for libcalls where that information may
@@ -5007,7 +5462,7 @@ function_arg_record_value_2 (const_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 (const_tree type, enum machine_mode mode,
                           int slotno, int named, int regbase)
@@ -5095,10 +5550,10 @@ function_arg_record_value (const_tree type, enum machine_mode mode,
   return parms.ret;
 }
 
-/* Used by function_arg and function_value to implement the conventions
+/* Used by function_arg and sparc_function_value_1 to implement the conventions
    of the 64-bit ABI for passing and returning unions.
-   Return an expression valid as a return value for the two macros
-   FUNCTION_ARG and FUNCTION_VALUE.
+   Return an expression valid as a return value for the FUNCTION_ARG
+   and TARGET_FUNCTION_VALUE.
 
    SIZE is the size in bytes of the union.
    MODE is the argument's machine mode.
@@ -5133,10 +5588,10 @@ function_arg_union_value (int size, enum machine_mode mode, int slotno,
   return regs;
 }
 
-/* Used by function_arg and function_value to implement the conventions
+/* Used by function_arg and sparc_function_value_1 to implement the conventions
    for passing and returning large (BLKmode) vectors.
-   Return an expression valid as a return value for the two macros
-   FUNCTION_ARG and FUNCTION_VALUE.
+   Return an expression valid as a return value for the FUNCTION_ARG
+   and TARGET_FUNCTION_VALUE.
 
    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.  */
@@ -5160,8 +5615,7 @@ function_arg_vector_value (int size, int regno)
   return regs;
 }
 
-/* Handle the FUNCTION_ARG macro.
-   Determine where to put an argument to a function.
+/* Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
    or a hard register in which to store the argument.
 
@@ -5171,13 +5625,14 @@ function_arg_vector_value (int size, int regno)
    TYPE is the data type of the argument (as a tree).
     This is null for libcalls where that information may
     not be available.
-   NAMED is nonzero if this argument is a named parameter
+   NAMED is true if this argument is a named parameter
     (otherwise it is an extra parameter matching an ellipsis).
-   INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.  */
+   INCOMING_P is false for TARGET_FUNCTION_ARG, true for
+    TARGET_FUNCTION_INCOMING_ARG.  */
 
-rtx
-function_arg (const struct sparc_args *cum, enum machine_mode mode,
-             tree type, int named, int incoming_p)
+static rtx
+sparc_function_arg_1 (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                     const_tree type, bool named, bool incoming_p)
 {
   int regbase = (incoming_p
                 ? SPARC_INCOMING_INT_ARG_FIRST
@@ -5309,6 +5764,36 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
   return gen_rtx_REG (mode, regno);
 }
 
+/* Handle the TARGET_FUNCTION_ARG target hook.  */
+
+static rtx
+sparc_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                   const_tree type, bool named)
+{
+  return sparc_function_arg_1 (cum, mode, type, named, false);
+}
+
+/* Handle the TARGET_FUNCTION_INCOMING_ARG target hook.  */
+
+static rtx
+sparc_function_incoming_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                            const_tree type, bool named)
+{
+  return sparc_function_arg_1 (cum, mode, type, named, true);
+}
+
+/* For sparc64, objects requiring 16 byte alignment are passed that way.  */
+
+static unsigned int
+sparc_function_arg_boundary (enum machine_mode mode, const_tree type)
+{
+  return ((TARGET_ARCH64
+          && (GET_MODE_ALIGNMENT (mode) == 128
+              || (type && TYPE_ALIGN (type) == 128)))
+         ? 128
+         : PARM_BOUNDARY);
+}
+
 /* For an arg passed partly in registers and partly in memory,
    this is the number of bytes of registers used.
    For args passed entirely in registers or entirely in memory, zero.
@@ -5325,8 +5810,9 @@ sparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
 {
   int slotno, regno, padding;
 
-  /* We pass 0 for incoming_p here, it doesn't matter.  */
-  slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
+  /* We pass false for incoming_p here, it doesn't matter.  */
+  slotno = function_arg_slotno (cum, mode, type, named, false,
+                               &regno, &padding);
 
   if (slotno == -1)
     return 0;
@@ -5407,7 +5893,7 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
     /* 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.
-       
+
        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,
@@ -5424,23 +5910,22 @@ sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
            || GET_MODE_SIZE (mode) > 16);
 }
 
-/* Handle the FUNCTION_ARG_ADVANCE macro.
+/* Handle the TARGET_FUNCTION_ARG_ADVANCE hook.
    Update the data in CUM to advance over an argument
    of mode MODE and data type TYPE.
    TYPE is null for libcalls where that information may not be available.  */
 
-void
-function_arg_advance (struct sparc_args *cum, enum machine_mode mode,
-                     tree type, int named)
+static void
+sparc_function_arg_advance (struct sparc_args *cum, enum machine_mode mode,
+                           const_tree type, bool named)
 {
-  int slotno, regno, padding;
+  int regno, padding;
 
-  /* We pass 0 for incoming_p here, it doesn't matter.  */
-  slotno = function_arg_slotno (cum, mode, type, named, 0, &regno, &padding);
+  /* We pass false for incoming_p here, it doesn't matter.  */
+  function_arg_slotno (cum, mode, type, named, false, &regno, &padding);
 
-  /* If register required leading padding, add it.  */
-  if (slotno != -1)
-    cum->words += padding;
+  /* If argument requires leading padding, add it.  */
+  cum->words += padding;
 
   if (TARGET_ARCH32)
     {
@@ -5513,7 +5998,7 @@ sparc_return_in_memory (const_tree type, const_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
@@ -5523,8 +6008,8 @@ sparc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
        integers are returned like floats of the same size, that is in
        registers.  Return all vector floats like structure and unions;
        note that they always have BLKmode like the latter.  */
-    return ((TYPE_MODE (type) == BLKmode
-            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
+    return (TYPE_MODE (type) == BLKmode
+           && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32);
 }
 
 /* Handle the TARGET_STRUCT_VALUE target hook.
@@ -5546,10 +6031,10 @@ sparc_struct_value_rtx (tree fndecl, 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 
+      /* 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 
+      if (incoming == 2
          && sparc_std_struct_return
          && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
          && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
@@ -5559,28 +6044,28 @@ sparc_struct_value_rtx (tree fndecl, int incoming)
             provided.  */
          rtx ret_rtx = gen_rtx_REG (Pmode, 31);
          rtx scratch = gen_reg_rtx (SImode);
-         rtx endlab = gen_label_rtx (); 
+         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);
+         rtx temp_val
+           = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+         /* Implement SPARC 32-bit psABI callee return struct checking:
 
-         /* Implement SPARC 32-bit psABI callee returns struck checking
-            requirements: 
-           
-             Fetch the instruction where we will return to and see if
+            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_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
+         /* 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);
@@ -5591,17 +6076,18 @@ sparc_struct_value_rtx (tree fndecl, int incoming)
     }
 }
 
-/* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
+/* Handle TARGET_FUNCTION_VALUE, and TARGET_LIBCALL_VALUE target hook.
    For v9, function return values are subject to the same rules as arguments,
    except that up to 32 bytes may be returned in registers.  */
 
-rtx
-function_value (const_tree type, enum machine_mode mode, int incoming_p)
+static rtx
+sparc_function_value_1 (const_tree type, enum machine_mode mode,
+                       bool outgoing)
 {
   /* Beware that the two values are swapped here wrt function_arg.  */
-  int regbase = (incoming_p
-                ? SPARC_OUTGOING_INT_ARG_FIRST
-                : SPARC_INCOMING_INT_ARG_FIRST);
+  int regbase = (outgoing
+                ? SPARC_INCOMING_INT_ARG_FIRST
+                : SPARC_OUTGOING_INT_ARG_FIRST);
   enum mode_class mclass = GET_MODE_CLASS (mode);
   int regno;
 
@@ -5670,11 +6156,19 @@ function_value (const_tree type, enum machine_mode mode, int incoming_p)
            mclass = MODE_INT;
        }
 
-      /* This must match PROMOTE_FUNCTION_MODE.  */
+      /* We should only have pointer and integer types at this point.  This
+        must match sparc_promote_function_mode.  */
       else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        mode = word_mode;
     }
 
+  /* We should only have pointer and integer types at this point.  This must
+     match sparc_promote_function_mode.  */
+  else if (TARGET_ARCH32
+          && mclass == MODE_INT
+          && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+    mode = word_mode;
+
   if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
     regno = SPARC_FP_ARG_FIRST;
   else
@@ -5683,6 +6177,37 @@ function_value (const_tree type, enum machine_mode mode, int incoming_p)
   return gen_rtx_REG (mode, regno);
 }
 
+/* Handle TARGET_FUNCTION_VALUE.
+   On the SPARC, the value is found in the first "output" register, but the
+   called function leaves it in the first "input" register.  */
+
+static rtx
+sparc_function_value (const_tree valtype,
+                     const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+                     bool outgoing)
+{
+  return sparc_function_value_1 (valtype, TYPE_MODE (valtype), outgoing);
+}
+
+/* Handle TARGET_LIBCALL_VALUE.  */
+
+static rtx
+sparc_libcall_value (enum machine_mode mode,
+                    const_rtx fun ATTRIBUTE_UNUSED)
+{
+  return sparc_function_value_1 (NULL_TREE, mode, false);
+}
+
+/* Handle FUNCTION_VALUE_REGNO_P.
+   On the SPARC, the first "output" reg is used for integer values, and the
+   first floating point register is used for floating point values.  */
+
+static bool
+sparc_function_value_regno_p (const unsigned int regno)
+{
+  return (regno == 8 || regno == 32);
+}
+
 /* Do what is necessary for `va_start'.  We look at the current function
    to determine if stdarg or varargs is used and return the address of
    the first unnamed parameter.  */
@@ -5744,7 +6269,7 @@ sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_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.  */
@@ -5786,28 +6311,25 @@ sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
       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_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], 3,
-                                  dest_addr,
-                                  addr,
-                                  size_int (rsize));
-
+      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 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
+  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);
@@ -5822,6 +6344,27 @@ sparc_vector_mode_supported_p (enum machine_mode mode)
   return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false;
 }
 \f
+/* Implement the TARGET_VECTORIZE_PREFERRED_SIMD_MODE target hook.  */
+
+static enum machine_mode
+sparc_preferred_simd_mode (enum machine_mode mode)
+{
+  if (TARGET_VIS)
+    switch (mode)
+      {
+      case SImode:
+       return V2SImode;
+      case HImode:
+       return V4HImode;
+      case QImode:
+       return V8QImode;
+
+      default:;
+      }
+
+  return word_mode;
+}
+\f
 /* Return the string to output an unconditional branch to LABEL, which is
    the operand number of the label.
 
@@ -6116,11 +6659,11 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
    values as arguments instead of the TFmode registers themselves,
    that's why we cannot call emit_float_lib_cmp.  */
 
-enum rtx_code
+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;
 
@@ -6183,7 +6726,8 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
          emit_move_insn (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);
@@ -6191,7 +6735,8 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
     }
   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;
@@ -6202,37 +6747,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:
-      new_comparison = NE;
-      emit_cmp_insn (result, const0_rtx, new_comparison, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_NE (VOIDmode, result, const0_rtx);
     case ORDERED:
     case UNORDERED:
       new_comparison = (comparison == UNORDERED ? EQ : NE);
-      emit_cmp_insn (result, GEN_INT(3), new_comparison, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, GEN_INT(3));
     case UNGT:
     case UNGE:
       new_comparison = (comparison == UNGT ? GT : NE);
-      emit_cmp_insn (result, const1_rtx, new_comparison, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, const1_rtx);
     case UNLE:
-      new_comparison = NE;
-      emit_cmp_insn (result, const2_rtx, new_comparison, 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));
-      new_comparison = NE;
-      emit_cmp_insn (tem, const0_rtx, new_comparison, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_NE (VOIDmode, tem, const0_rtx);
     case UNEQ:
     case LTGT:
       tem = gen_reg_rtx (mode);
@@ -6246,11 +6783,10 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
       else
        emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
       new_comparison = (comparison == UNEQ ? EQ : NE);
-      emit_cmp_insn (tem2, const0_rtx, new_comparison, NULL_RTX, mode, 0);
-      break;
+      return gen_rtx_fmt_ee (new_comparison, VOIDmode, tem2, const0_rtx);
     }
 
-  return new_comparison;
+  gcc_unreachable ();
 }
 
 /* Generate an unsigned DImode to FP conversion.  This is the same code
@@ -6351,21 +6887,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  */
@@ -6617,7 +7153,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.  */
 
@@ -6625,22 +7161,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.
@@ -6683,10 +7219,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)
     {
@@ -6724,8 +7260,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;
@@ -6822,19 +7358,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. The exception here is that 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 
-        present. */
-     if (! TARGET_ARCH64
+        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
-        && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
-            == INTEGER_CST)
-        && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+        && !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);
@@ -7167,7 +7703,7 @@ sparc_type_code (register tree type)
        {
        case ERROR_MARK:
          return qualifiers;
-  
+
        case ARRAY_TYPE:
          qualifiers |= (3 << shift);
          break;
@@ -7215,16 +7751,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.  */
@@ -7237,9 +7773,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
@@ -7248,9 +7784,10 @@ sparc_type_code (register tree type)
 
        case VECTOR_TYPE:
        case BOOLEAN_TYPE:      /* Boolean truth value type.  */
-       case LANG_TYPE:         /* ? */
+       case LANG_TYPE:
+       case NULLPTR_TYPE:
          return qualifiers;
-  
+
        default:
          gcc_unreachable ();           /* Not a type! */
         }
@@ -7272,8 +7809,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:
 
@@ -7287,7 +7824,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),
@@ -7295,7 +7832,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),
@@ -7303,14 +7840,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)),
@@ -7318,19 +7855,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
       && sparc_cpu != PROCESSOR_NIAGARA
       && sparc_cpu != PROCESSOR_NIAGARA2)
-    emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
-                                                    plus_constant (tramp, 8)))));
+    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
 
 }
@@ -7339,8 +7875,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:
 
@@ -7351,31 +7887,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
       && sparc_cpu != PROCESSOR_NIAGARA
       && sparc_cpu != PROCESSOR_NIAGARA2)
-    emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
+    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.  */
@@ -7480,13 +8029,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;
 
@@ -7513,7 +8062,7 @@ hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
     default:
       break;
-    }    
+    }
 
   return cost;
 }
@@ -7540,9 +8089,8 @@ 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)
 {
@@ -7660,13 +8208,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
 
@@ -7682,20 +8230,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
 
@@ -7714,7 +8262,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
@@ -7736,7 +8284,7 @@ sparc_output_deferred_case_vectors (void)
   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))
@@ -7863,19 +8411,12 @@ sparc_profile_hook (int labelno)
     }
 }
 \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))
@@ -7891,7 +8432,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.
 
@@ -7926,7 +8466,6 @@ sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 }
 \f
 /* libfunc renaming.  */
-#include "config/gofast.h"
 
 static void
 sparc_init_libfuncs (void)
@@ -8020,8 +8559,6 @@ sparc_init_libfuncs (void)
          set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoul");
        }
     }
-
-  gofast_maybe_init_libfuncs ();
 }
 \f
 #define def_builtin(NAME, CODE, TYPE) \
@@ -8253,20 +8790,22 @@ sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
    function could not be folded.  */
 
 static tree
-sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
+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
-      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis
-      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis)
-    return fold_convert (rtype, integer_zero_node);
+      && icode != CODE_FOR_alignaddrsi_vis
+      && icode != CODE_FOR_alignaddrdi_vis)
+    return build_zero_cst (rtype);
 
-  switch (DECL_FUNCTION_CODE (fndecl))
+  switch (icode)
     {
     case CODE_FOR_fexpand_vis:
-      arg0 = TREE_VALUE (arglist);
+      arg0 = args[0];
       STRIP_NOPS (arg0);
 
       if (TREE_CODE (arg0) == VECTOR_CST)
@@ -8289,8 +8828,8 @@ sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
     case CODE_FOR_fmul8x16_vis:
     case CODE_FOR_fmul8x16au_vis:
     case CODE_FOR_fmul8x16al_vis:
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg0 = args[0];
+      arg1 = args[1];
       STRIP_NOPS (arg0);
       STRIP_NOPS (arg1);
 
@@ -8299,16 +8838,16 @@ sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
          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 (DECL_FUNCTION_CODE (fndecl),
-                                                 inner_type, elts0, elts1);
+         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 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg0 = args[0];
+      arg1 = args[1];
       STRIP_NOPS (arg0);
       STRIP_NOPS (arg1);
 
@@ -8330,9 +8869,9 @@ sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
       break;
 
     case CODE_FOR_pdist_vis:
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
-      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      arg0 = args[0];
+      arg1 = args[1];
+      arg2 = args[2];
       STRIP_NOPS (arg0);
       STRIP_NOPS (arg1);
       STRIP_NOPS (arg2);
@@ -8656,7 +9195,8 @@ 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))
+  if (TARGET_ARCH64
+      && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
     this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
   else
     this_rtx = gen_rtx_REG (Pmode, int_arg_first);
@@ -8757,8 +9297,8 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          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 = sparc_legitimize_pic_address (funexp, scratch);
          seq = get_insns ();
          end_sequence ();
          emit_and_preserve (seq, spill_reg, spill_reg2);
@@ -8813,7 +9353,6 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   final_start_function (insn, file, 1);
   final (insn, file, 1);
   final_end_function ();
-  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -8837,7 +9376,7 @@ sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
 static struct machine_function *
 sparc_init_machine_status (void)
 {
-  return GGC_CNEW (struct machine_function);
+  return ggc_alloc_cleared_machine_function ();
 }
 
 /* Locate some local-dynamic symbol still in use by this function
@@ -8913,9 +9452,60 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
 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);
+         cfun->is_thunk = 1;
+         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 ();
@@ -9020,14 +9610,12 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
                          gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
                                       res)));
 
-  sparc_compare_op0 = resv;
-  sparc_compare_op1 = val;
-  cc = gen_compare_reg (NE);
-
+  cc = gen_compare_reg_1 (NE, resv, val);
   emit_insn (gen_rtx_SET (VOIDmode, val, resv));
 
-  sparc_compare_emitted = cc;
-  emit_jump_insn (gen_bne (loop_label));
+  /* 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);
 
@@ -9040,4 +9628,74 @@ sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
   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 ());
+}
+
+/* If !TARGET_FPU, then make the fp registers and fp cc regs fixed so that
+   they won't be allocated.  */
+
+static void
+sparc_conditional_register_usage (void)
+{
+  if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+    {
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+    }
+  /* If the user has passed -f{fixed,call-{used,saved}}-g5 */
+  /* then honor it.  */
+  if (TARGET_ARCH32 && fixed_regs[5])
+    fixed_regs[5] = 1;
+  else if (TARGET_ARCH64 && fixed_regs[5] == 2)
+    fixed_regs[5] = 0;
+  if (! TARGET_V9)
+    {
+      int regno;
+      for (regno = SPARC_FIRST_V9_FP_REG;
+          regno <= SPARC_LAST_V9_FP_REG;
+          regno++)
+       fixed_regs[regno] = 1;
+      /* %fcc0 is used by v8 and v9.  */
+      for (regno = SPARC_FIRST_V9_FCC_REG + 1;
+          regno <= SPARC_LAST_V9_FCC_REG;
+          regno++)
+       fixed_regs[regno] = 1;
+    }
+  if (! TARGET_FPU)
+    {
+      int regno;
+      for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++)
+       fixed_regs[regno] = 1;
+    }
+  /* If the user has passed -f{fixed,call-{used,saved}}-g2 */
+  /* then honor it.  Likewise with g3 and g4.  */
+  if (fixed_regs[2] == 2)
+    fixed_regs[2] = ! TARGET_APP_REGS;
+  if (fixed_regs[3] == 2)
+    fixed_regs[3] = ! TARGET_APP_REGS;
+  if (TARGET_ARCH32 && fixed_regs[4] == 2)
+    fixed_regs[4] = ! TARGET_APP_REGS;
+  else if (TARGET_CM_EMBMEDANY)
+    fixed_regs[4] = 1;
+  else if (fixed_regs[4] == 2)
+    fixed_regs[4] = 0;
+}
+
 #include "gt-sparc.h"