]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/config/sparc/sparc.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / sparc / sparc.c
index 74435a51ac51a031390392f93b8f0e446df692ce..7e05e1a6f82a12832a88d55e079266368a47b211 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for SPARC.
-   Copyright (C) 1987-2016 Free Software Foundation, Inc.
+   Copyright (C) 1987-2020 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
    at Cygnus Support.
@@ -20,6 +20,8 @@ You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING3.  If not see
 <http://www.gnu.org/licenses/>.  */
 
+#define IN_TARGET_CODE 1
+
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -32,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
@@ -48,14 +51,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "explow.h"
 #include "expr.h"
 #include "debug.h"
+#include "cfgrtl.h"
 #include "common/common-target.h"
 #include "gimplify.h"
 #include "langhooks.h"
 #include "reload.h"
-#include "params.h"
 #include "tree-pass.h"
 #include "context.h"
 #include "builtins.h"
+#include "tree-vector-builder.h"
+#include "opts.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -134,6 +139,9 @@ struct processor_costs {
 
   /* penalty for shifts, due to scheduling rules etc. */
   const int shift_penalty;
+
+  /* cost of a (predictable) branch.  */
+  const int branch_cost;
 };
 
 static const
@@ -158,6 +166,7 @@ struct processor_costs cypress_costs = {
   COSTS_N_INSNS (1), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -182,6 +191,7 @@ struct processor_costs supersparc_costs = {
   COSTS_N_INSNS (4), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   1, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -206,6 +216,7 @@ struct processor_costs hypersparc_costs = {
   COSTS_N_INSNS (17), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -230,6 +241,7 @@ struct processor_costs leon_costs = {
   COSTS_N_INSNS (5), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -254,6 +266,7 @@ struct processor_costs leon3_costs = {
   COSTS_N_INSNS (35), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -278,6 +291,7 @@ struct processor_costs sparclet_costs = {
   COSTS_N_INSNS (5), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  3 /* branch cost */
 };
 
 static const
@@ -302,6 +316,7 @@ struct processor_costs ultrasparc_costs = {
   COSTS_N_INSNS (68), /* idivX */
   COSTS_N_INSNS (2), /* movcc/movr */
   2, /* shift penalty */
+  2 /* branch cost */
 };
 
 static const
@@ -326,6 +341,7 @@ struct processor_costs ultrasparc3_costs = {
   COSTS_N_INSNS (71), /* idivX */
   COSTS_N_INSNS (2), /* movcc/movr */
   0, /* shift penalty */
+  2 /* branch cost */
 };
 
 static const
@@ -350,6 +366,7 @@ struct processor_costs niagara_costs = {
   COSTS_N_INSNS (72), /* idivX */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  4 /* branch cost */
 };
 
 static const
@@ -374,6 +391,7 @@ struct processor_costs niagara2_costs = {
   COSTS_N_INSNS (26), /* idivX, average of 12 - 41 cycle range */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  5 /* branch cost */
 };
 
 static const
@@ -398,6 +416,7 @@ struct processor_costs niagara3_costs = {
   COSTS_N_INSNS (30), /* idivX, average of 16 - 44 cycle range */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  5 /* branch cost */
 };
 
 static const
@@ -422,6 +441,7 @@ struct processor_costs niagara4_costs = {
   COSTS_N_INSNS (35), /* idivX, average of 26 - 44 cycle range */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  2 /* branch cost */
 };
 
 static const
@@ -446,6 +466,32 @@ struct processor_costs niagara7_costs = {
   COSTS_N_INSNS (35), /* idivX, average of 26 - 44 cycle range */
   COSTS_N_INSNS (1), /* movcc/movr */
   0, /* shift penalty */
+  1 /* branch cost */
+};
+
+static const
+struct processor_costs m8_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (3), /* float load */
+  COSTS_N_INSNS (9), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (9), /* fadd, fsub */
+  COSTS_N_INSNS (9), /* fcmp */
+  COSTS_N_INSNS (9), /* fmov, fmovr */
+  COSTS_N_INSNS (9), /* fmul */
+  COSTS_N_INSNS (26), /* fdivs */
+  COSTS_N_INSNS (30), /* fdivd */
+  COSTS_N_INSNS (33), /* fsqrts */
+  COSTS_N_INSNS (41), /* fsqrtd */
+  COSTS_N_INSNS (12), /* imul */
+  COSTS_N_INSNS (10), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (57), /* udiv/sdiv */
+  COSTS_N_INSNS (30), /* udivx/sdivx */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+  1 /* branch cost */
 };
 
 static const struct processor_costs *sparc_costs = &cypress_costs;
@@ -560,8 +606,8 @@ 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_insn *);
-static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
-static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
+static void sparc_asm_function_prologue (FILE *);
+static void sparc_asm_function_epilogue (FILE *);
 #ifdef TARGET_SOLARIS
 static void sparc_solaris_elf_asm_named_section (const char *, unsigned int,
                                                 tree) ATTRIBUTE_UNUSED;
@@ -596,13 +642,8 @@ static rtx sparc_tls_got (void);
 static int sparc_register_move_cost (machine_mode,
                                     reg_class_t, reg_class_t);
 static bool sparc_rtx_costs (rtx, machine_mode, int, int, int *, bool);
-static rtx sparc_function_value (const_tree, const_tree, bool);
-static rtx sparc_libcall_value (machine_mode, const_rtx);
-static bool sparc_function_value_regno_p (const unsigned int);
-static rtx sparc_struct_value_rtx (tree, int);
 static machine_mode sparc_promote_function_mode (const_tree, machine_mode,
                                                      int *, const_tree, int);
-static bool sparc_return_in_memory (const_tree, const_tree);
 static bool sparc_strict_argument_naming (cumulative_args_t);
 static void sparc_va_start (tree, rtx);
 static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
@@ -614,57 +655,71 @@ static rtx sparc_legitimize_address (rtx, rtx, machine_mode);
 static rtx sparc_delegitimize_address (rtx);
 static bool sparc_mode_dependent_address_p (const_rtx, addr_space_t);
 static bool sparc_pass_by_reference (cumulative_args_t,
-                                    machine_mode, const_tree, bool);
+                                    const function_arg_info &);
 static void sparc_function_arg_advance (cumulative_args_t,
-                                       machine_mode, const_tree, bool);
-static rtx sparc_function_arg_1 (cumulative_args_t,
-                                machine_mode, const_tree, bool, bool);
-static rtx sparc_function_arg (cumulative_args_t,
-                              machine_mode, const_tree, bool);
+                                       const function_arg_info &);
+static rtx sparc_function_arg (cumulative_args_t, const function_arg_info &);
 static rtx sparc_function_incoming_arg (cumulative_args_t,
-                                       machine_mode, const_tree, bool);
+                                       const function_arg_info &);
+static pad_direction sparc_function_arg_padding (machine_mode, const_tree);
 static unsigned int sparc_function_arg_boundary (machine_mode,
                                                 const_tree);
 static int sparc_arg_partial_bytes (cumulative_args_t,
-                                   machine_mode, tree, bool);
+                                   const function_arg_info &);
+static bool sparc_return_in_memory (const_tree, const_tree);
+static rtx sparc_struct_value_rtx (tree, int);
+static rtx sparc_function_value (const_tree, const_tree, bool);
+static rtx sparc_libcall_value (machine_mode, const_rtx);
+static bool sparc_function_value_regno_p (const unsigned int);
+static unsigned HOST_WIDE_INT sparc_asan_shadow_offset (void);
 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 rtx sparc_builtin_setjmp_frame_value (void);
 static void sparc_conditional_register_usage (void);
+static bool sparc_use_pseudo_pic_reg (void);
+static void sparc_init_pic_reg (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 machine_mode sparc_preferred_simd_mode (machine_mode);
+static machine_mode sparc_preferred_simd_mode (scalar_mode);
 static reg_class_t sparc_preferred_reload_class (rtx x, reg_class_t rclass);
+static bool sparc_lra_p (void);
 static bool sparc_print_operand_punct_valid_p (unsigned char);
 static void sparc_print_operand (FILE *, rtx, int);
 static void sparc_print_operand_address (FILE *, machine_mode, rtx);
 static reg_class_t sparc_secondary_reload (bool, rtx, reg_class_t,
                                           machine_mode,
                                           secondary_reload_info *);
-static machine_mode sparc_cstore_mode (enum insn_code icode);
+static bool sparc_secondary_memory_needed (machine_mode, reg_class_t,
+                                          reg_class_t);
+static machine_mode sparc_secondary_memory_needed_mode (machine_mode);
+static scalar_int_mode sparc_cstore_mode (enum insn_code icode);
 static void sparc_atomic_assign_expand_fenv (tree *, tree *, tree *);
 static bool sparc_fixed_condition_code_regs (unsigned int *, unsigned int *);
+static unsigned int sparc_min_arithmetic_precision (void);
+static unsigned int sparc_hard_regno_nregs (unsigned int, machine_mode);
+static bool sparc_hard_regno_mode_ok (unsigned int, machine_mode);
+static bool sparc_modes_tieable_p (machine_mode, machine_mode);
+static bool sparc_can_change_mode_class (machine_mode, machine_mode,
+                                        reg_class_t);
+static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT);
+static bool sparc_vectorize_vec_perm_const (machine_mode, rtx, rtx, rtx,
+                                           const vec_perm_indices &);
+static bool sparc_can_follow_jump (const rtx_insn *, const rtx_insn *);
 \f
 #ifdef SUBTARGET_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,
-       do_diagnostic } */
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req,
+       do_diagnostic, handler, exclude } */
   SUBTARGET_ATTRIBUTE_TABLE,
-  { NULL,        0, 0, false, false, false, NULL, false }
+  { NULL,        0, 0, false, false, false, false, NULL, NULL }
 };
 #endif
 \f
-/* Option handling.  */
-
-/* Parsed value.  */
-enum cmodel sparc_cmodel;
-
 char sparc_hard_reg_printed[8];
 
 /* Initialize the GCC target structure.  */
@@ -742,18 +797,9 @@ char sparc_hard_reg_printed[8];
 
 #undef TARGET_PROMOTE_FUNCTION_MODE
 #define TARGET_PROMOTE_FUNCTION_MODE sparc_promote_function_mode
+#undef TARGET_STRICT_ARGUMENT_NAMING
+#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
 
-#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
-#undef TARGET_RETURN_IN_MEMORY
-#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
 #undef TARGET_PASS_BY_REFERENCE
@@ -766,13 +812,27 @@ char sparc_hard_reg_printed[8];
 #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_PADDING
+#define TARGET_FUNCTION_ARG_PADDING sparc_function_arg_padding
 #undef TARGET_FUNCTION_ARG_BOUNDARY
 #define TARGET_FUNCTION_ARG_BOUNDARY sparc_function_arg_boundary
 
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
+#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_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
-#undef TARGET_STRICT_ARGUMENT_NAMING
-#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
+
+#undef TARGET_ASAN_SHADOW_OFFSET
+#define TARGET_ASAN_SHADOW_OFFSET sparc_asan_shadow_offset
 
 #undef TARGET_EXPAND_BUILTIN_VA_START
 #define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start
@@ -814,9 +874,6 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_FRAME_POINTER_REQUIRED
 #define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required
 
-#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
-#define TARGET_BUILTIN_SETJMP_FRAME_VALUE sparc_builtin_setjmp_frame_value
-
 #undef TARGET_CAN_ELIMINATE
 #define TARGET_CAN_ELIMINATE sparc_can_eliminate
 
@@ -825,17 +882,27 @@ char sparc_hard_reg_printed[8];
 
 #undef TARGET_SECONDARY_RELOAD
 #define TARGET_SECONDARY_RELOAD sparc_secondary_reload
+#undef TARGET_SECONDARY_MEMORY_NEEDED
+#define TARGET_SECONDARY_MEMORY_NEEDED sparc_secondary_memory_needed
+#undef TARGET_SECONDARY_MEMORY_NEEDED_MODE
+#define TARGET_SECONDARY_MEMORY_NEEDED_MODE sparc_secondary_memory_needed_mode
 
 #undef TARGET_CONDITIONAL_REGISTER_USAGE
 #define TARGET_CONDITIONAL_REGISTER_USAGE sparc_conditional_register_usage
 
+#undef TARGET_INIT_PIC_REG
+#define TARGET_INIT_PIC_REG sparc_init_pic_reg
+
+#undef TARGET_USE_PSEUDO_PIC_REG
+#define TARGET_USE_PSEUDO_PIC_REG sparc_use_pseudo_pic_reg
+
 #ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE sparc_mangle_type
 #endif
 
 #undef TARGET_LRA_P
-#define TARGET_LRA_P hook_bool_void_false
+#define TARGET_LRA_P sparc_lra_p
 
 #undef TARGET_LEGITIMATE_ADDRESS_P
 #define TARGET_LEGITIMATE_ADDRESS_P sparc_legitimate_address_p
@@ -866,6 +933,32 @@ char sparc_hard_reg_printed[8];
 #undef TARGET_FIXED_CONDITION_CODE_REGS
 #define TARGET_FIXED_CONDITION_CODE_REGS sparc_fixed_condition_code_regs
 
+#undef TARGET_MIN_ARITHMETIC_PRECISION
+#define TARGET_MIN_ARITHMETIC_PRECISION sparc_min_arithmetic_precision
+
+#undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS
+#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 1
+
+#undef TARGET_HARD_REGNO_NREGS
+#define TARGET_HARD_REGNO_NREGS sparc_hard_regno_nregs
+#undef TARGET_HARD_REGNO_MODE_OK
+#define TARGET_HARD_REGNO_MODE_OK sparc_hard_regno_mode_ok
+
+#undef TARGET_MODES_TIEABLE_P
+#define TARGET_MODES_TIEABLE_P sparc_modes_tieable_p
+
+#undef TARGET_CAN_CHANGE_MODE_CLASS
+#define TARGET_CAN_CHANGE_MODE_CLASS sparc_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT sparc_constant_alignment
+
+#undef TARGET_VECTORIZE_VEC_PERM_CONST
+#define TARGET_VECTORIZE_VEC_PERM_CONST sparc_vectorize_vec_perm_const
+
+#undef TARGET_CAN_FOLLOW_JUMP
+#define TARGET_CAN_FOLLOW_JUMP sparc_can_follow_jump
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 /* Return the memory reference contained in X if any, zero otherwise.  */
@@ -882,12 +975,92 @@ mem_ref (rtx x)
   return NULL_RTX;
 }
 
+/* True if any of INSN's source register(s) is REG.  */
+
+static bool
+insn_uses_reg_p (rtx_insn *insn, unsigned int reg)
+{
+  extract_insn (insn);
+  return ((REG_P (recog_data.operand[1])
+          && REGNO (recog_data.operand[1]) == reg)
+         || (recog_data.n_operands == 3
+             && REG_P (recog_data.operand[2])
+             && REGNO (recog_data.operand[2]) == reg));
+}
+
+/* True if INSN is a floating-point division or square-root.  */
+
+static bool
+div_sqrt_insn_p (rtx_insn *insn)
+{
+  if (GET_CODE (PATTERN (insn)) != SET)
+    return false;
+
+  switch (get_attr_type (insn))
+    {
+    case TYPE_FPDIVS:
+    case TYPE_FPSQRTS:
+    case TYPE_FPDIVD:
+    case TYPE_FPSQRTD:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* True if INSN is a floating-point instruction.  */
+
+static bool
+fpop_insn_p (rtx_insn *insn)
+{
+  if (GET_CODE (PATTERN (insn)) != SET)
+    return false;
+
+  switch (get_attr_type (insn))
+    {
+    case TYPE_FPMOVE:
+    case TYPE_FPCMOVE:
+    case TYPE_FP:
+    case TYPE_FPCMP:
+    case TYPE_FPMUL:
+    case TYPE_FPDIVS:
+    case TYPE_FPSQRTS:
+    case TYPE_FPDIVD:
+    case TYPE_FPSQRTD:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* True if INSN is an atomic instruction.  */
+
+static bool
+atomic_insn_for_leon3_p (rtx_insn *insn)
+{
+  switch (INSN_CODE (insn))
+    {
+    case CODE_FOR_swapsi:
+    case CODE_FOR_ldstub:
+    case CODE_FOR_atomic_compare_and_swap_leon3_1:
+      return true;
+    default:
+      return false;
+    }
+}
+
 /* We use a machine specific pass to enable workarounds for errata.
 
    We need to have the (essentially) final form of the insn stream in order
    to properly detect the various hazards.  Therefore, this machine specific
    pass runs as late as possible.  */
 
+/* True if INSN is a md pattern or asm statement.  */
+#define USEFUL_INSN_P(INSN)                                            \
+  (NONDEBUG_INSN_P (INSN)                                              \
+   && GET_CODE (PATTERN (INSN)) != USE                                 \
+   && GET_CODE (PATTERN (INSN)) != CLOBBER)
+
 static unsigned int
 sparc_do_work_around_errata (void)
 {
@@ -901,21 +1074,219 @@ sparc_do_work_around_errata (void)
     {
       bool insert_nop = false;
       rtx set;
+      rtx_insn *jump;
+      rtx_sequence *seq;
 
       /* Look into the instruction in a delay slot.  */
-      if (NONJUMP_INSN_P (insn))
-       if (rtx_sequence *seq = dyn_cast <rtx_sequence *> (PATTERN (insn)))
+      if (NONJUMP_INSN_P (insn)
+         && (seq = dyn_cast <rtx_sequence *> (PATTERN (insn))))
+       {
+         jump = seq->insn (0);
          insn = seq->insn (1);
+       }
+      else if (JUMP_P (insn))
+       jump = insn;
+      else
+       jump = NULL;
+
+      /* Place a NOP at the branch target of an integer branch if it is a
+        floating-point operation or a floating-point branch.  */
+      if (sparc_fix_gr712rc
+         && jump
+         && jump_to_label_p (jump)
+         && get_attr_branch_type (jump) == BRANCH_TYPE_ICC)
+       {
+         rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
+         if (target
+             && (fpop_insn_p (target)
+                 || (JUMP_P (target)
+                     && get_attr_branch_type (target) == BRANCH_TYPE_FCC)))
+           emit_insn_before (gen_nop (), target);
+       }
+
+      /* Insert a NOP between load instruction and atomic instruction.  Insert
+        a NOP at branch target if there is a load in delay slot and an atomic
+        instruction at branch target.  */
+      if (sparc_fix_ut700
+         && NONJUMP_INSN_P (insn)
+         && (set = single_set (insn)) != NULL_RTX
+         && mem_ref (SET_SRC (set))
+         && REG_P (SET_DEST (set)))
+       {
+         if (jump && jump_to_label_p (jump))
+           {
+             rtx_insn *target = next_active_insn (JUMP_LABEL_AS_INSN (jump));
+             if (target && atomic_insn_for_leon3_p (target))
+               emit_insn_before (gen_nop (), target);
+           }
 
-      /* Look for a single-word load into an odd-numbered FP register.  */
-      if (sparc_fix_at697f
+         next = next_active_insn (insn);
+         if (!next)
+           break;
+
+         if (atomic_insn_for_leon3_p (next))
+           insert_nop = true;
+       }
+
+      /* Look for a sequence that starts with a fdiv or fsqrt instruction and
+        ends with another fdiv or fsqrt instruction with no dependencies on
+        the former, along with an appropriate pattern in between.  */
+      if (sparc_fix_lost_divsqrt
+         && NONJUMP_INSN_P (insn)
+         && div_sqrt_insn_p (insn))
+       {
+         int i;
+         int fp_found = 0;
+         rtx_insn *after;
+
+         const unsigned int dest_reg = REGNO (SET_DEST (single_set (insn)));
+
+         next = next_active_insn (insn);
+         if (!next)
+           break;
+
+         for (after = next, i = 0; i < 4; i++)
+           {
+             /* Count floating-point operations.  */
+             if (i != 3 && fpop_insn_p (after))
+               {
+                 /* If the insn uses the destination register of
+                    the div/sqrt, then it cannot be problematic.  */
+                 if (insn_uses_reg_p (after, dest_reg))
+                   break;
+                 fp_found++;
+               }
+
+             /* Count floating-point loads.  */
+             if (i != 3
+                 && (set = single_set (after)) != NULL_RTX
+                 && REG_P (SET_DEST (set))
+                 && REGNO (SET_DEST (set)) > 31)
+               {
+                 /* If the insn uses the destination register of
+                    the div/sqrt, then it cannot be problematic.  */
+                 if (REGNO (SET_DEST (set)) == dest_reg)
+                   break;
+                 fp_found++;
+               }
+
+             /* Check if this is a problematic sequence.  */
+             if (i > 1
+                 && fp_found >= 2
+                 && div_sqrt_insn_p (after))
+               {
+                 /* If this is the short version of the problematic
+                    sequence we add two NOPs in a row to also prevent
+                    the long version.  */
+                 if (i == 2)
+                   emit_insn_before (gen_nop (), next);
+                 insert_nop = true;
+                 break;
+               }
+
+             /* No need to scan past a second div/sqrt.  */
+             if (div_sqrt_insn_p (after))
+               break;
+
+             /* Insert NOP before branch.  */
+             if (i < 3
+                 && (!NONJUMP_INSN_P (after)
+                     || GET_CODE (PATTERN (after)) == SEQUENCE))
+               {
+                 insert_nop = true;
+                 break;
+               }
+
+             after = next_active_insn (after);
+             if (!after)
+               break;
+           }
+       }
+
+      /* Look for either of these two sequences:
+
+        Sequence A:
+        1. store of word size or less (e.g. st / stb / sth / stf)
+        2. any single instruction that is not a load or store
+        3. any store instruction (e.g. st / stb / sth / stf / std / stdf)
+
+        Sequence B:
+        1. store of double word size (e.g. std / stdf)
+        2. any store instruction (e.g. st / stb / sth / stf / std / stdf)  */
+      if (sparc_fix_b2bst
          && NONJUMP_INSN_P (insn)
          && (set = single_set (insn)) != NULL_RTX
-         && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
-         && MEM_P (SET_SRC (set))
-         && REG_P (SET_DEST (set))
-         && REGNO (SET_DEST (set)) > 31
-         && REGNO (SET_DEST (set)) % 2 != 0)
+         && MEM_P (SET_DEST (set)))
+       {
+         /* Sequence B begins with a double-word store.  */
+         bool seq_b = GET_MODE_SIZE (GET_MODE (SET_DEST (set))) == 8;
+         rtx_insn *after;
+         int i;
+
+         next = next_active_insn (insn);
+         if (!next)
+           break;
+
+         for (after = next, i = 0; i < 2; i++)
+           {
+             /* Skip empty assembly statements.  */
+             if ((GET_CODE (PATTERN (after)) == UNSPEC_VOLATILE)
+                 || (USEFUL_INSN_P (after)
+                     && (asm_noperands (PATTERN (after))>=0)
+                     && !strcmp (decode_asm_operands (PATTERN (after),
+                                                      NULL, NULL, NULL,
+                                                      NULL, NULL), "")))
+               after = next_active_insn (after);
+             if (!after)
+               break;
+
+             /* If the insn is a branch, then it cannot be problematic.  */
+             if (!NONJUMP_INSN_P (after)
+                 || GET_CODE (PATTERN (after)) == SEQUENCE)
+               break;
+
+             /* Sequence B is only two instructions long.  */
+             if (seq_b)
+               {
+                 /* Add NOP if followed by a store.  */
+                 if ((set = single_set (after)) != NULL_RTX
+                     && MEM_P (SET_DEST (set)))
+                   insert_nop = true;
+
+                 /* Otherwise it is ok.  */
+                 break;
+               }
+
+             /* If the second instruction is a load or a store,
+                then the sequence cannot be problematic.  */
+             if (i == 0)
+               {
+                 if ((set = single_set (after)) != NULL_RTX
+                     && (MEM_P (SET_DEST (set)) || mem_ref (SET_SRC (set))))
+                   break;
+
+                 after = next_active_insn (after);
+                 if (!after)
+                   break;
+               }
+
+             /* Add NOP if third instruction is a store.  */
+             if (i == 1
+                 && (set = single_set (after)) != NULL_RTX
+                 && MEM_P (SET_DEST (set)))
+               insert_nop = true;
+           }
+       }
+
+      /* Look for a single-word load into an odd-numbered FP register.  */
+      else if (sparc_fix_at697f
+              && NONJUMP_INSN_P (insn)
+              && (set = single_set (insn)) != NULL_RTX
+              && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
+              && mem_ref (SET_SRC (set))
+              && REG_P (SET_DEST (set))
+              && REGNO (SET_DEST (set)) > 31
+              && REGNO (SET_DEST (set)) % 2 != 0)
        {
          /* The wrong dependency is on the enclosing double register.  */
          const unsigned int x = REGNO (SET_DEST (set)) - 1;
@@ -982,7 +1353,8 @@ sparc_do_work_around_errata (void)
               && NONJUMP_INSN_P (insn)
               && (set = single_set (insn)) != NULL_RTX
               && GET_MODE_SIZE (GET_MODE (SET_SRC (set))) <= 4
-              && mem_ref (SET_SRC (set)) != NULL_RTX
+              && (mem_ref (SET_SRC (set)) != NULL_RTX
+                  || INSN_CODE (insn) == CODE_FOR_movsi_pic_gotdata_op)
               && REG_P (SET_DEST (set))
               && REGNO (SET_DEST (set)) < 32)
        {
@@ -1020,6 +1392,11 @@ sparc_do_work_around_errata (void)
                               && REGNO (src) != REGNO (x)))
                       && !reg_mentioned_p (x, XEXP (dest, 0)))
                insert_nop = true;
+
+             /* GOT accesses uses LD.  */
+             else if (INSN_CODE (next) == CODE_FOR_movsi_pic_gotdata_op
+                      && !reg_mentioned_p (x, XEXP (XEXP (src, 0), 1)))
+               insert_nop = true;
            }
        }
 
@@ -1159,8 +1536,9 @@ public:
   /* opt_pass methods: */
   virtual bool gate (function *)
     {
-      /* The only errata we handle are those of the AT697F and UT699.  */
-      return sparc_fix_at697f != 0 || sparc_fix_ut699 != 0;
+      return sparc_fix_at697f
+            || sparc_fix_ut699 || sparc_fix_ut700 || sparc_fix_gr712rc
+            || sparc_fix_b2bst || sparc_fix_lost_divsqrt;
     }
 
   virtual unsigned int execute (function *)
@@ -1192,6 +1570,8 @@ dump_target_flag_bits (const int flags)
     fprintf (stderr, "FLAT ");
   if (flags & MASK_FMAF)
     fprintf (stderr, "FMAF ");
+  if (flags & MASK_FSMULD)
+    fprintf (stderr, "FSMULD ");
   if (flags & MASK_FPU)
     fprintf (stderr, "FPU ");
   if (flags & MASK_HARD_QUAD)
@@ -1214,6 +1594,8 @@ dump_target_flag_bits (const int flags)
     fprintf (stderr, "VIS3 ");
   if (flags & MASK_VIS4)
     fprintf (stderr, "VIS4 ");
+  if (flags & MASK_VIS4B)
+    fprintf (stderr, "VIS4B ");
   if (flags & MASK_CBCOND)
     fprintf (stderr, "CBCOND ");
   if (flags & MASK_DEPRECATED_V8_INSNS)
@@ -1242,22 +1624,10 @@ dump_target_flags (const char *prefix, const int flags)
 static void
 sparc_option_override (void)
 {
-  static struct code_model {
-    const char *const name;
-    const enum cmodel value;
-  } const cmodels[] = {
-    { "32", CM_32 },
-    { "medlow", CM_MEDLOW },
-    { "medmid", CM_MEDMID },
-    { "medany", CM_MEDANY },
-    { "embmedany", CM_EMBMEDANY },
-    { NULL, (enum cmodel) 0 }
-  };
-  const struct code_model *cmodel;
   /* Map TARGET_CPU_DEFAULT to value for -m{cpu,tune}=.  */
   static struct cpu_default {
     const int cpu;
-    const enum processor_type processor;
+    const enum sparc_processor_type processor;
   } const cpu_default[] = {
     /* There must be one entry here for each TARGET_CPU value.  */
     { TARGET_CPU_sparc, PROCESSOR_CYPRESS },
@@ -1278,6 +1648,7 @@ sparc_option_override (void)
     { TARGET_CPU_niagara3, PROCESSOR_NIAGARA3 },
     { TARGET_CPU_niagara4, PROCESSOR_NIAGARA4 },
     { TARGET_CPU_niagara7, PROCESSOR_NIAGARA7 },
+    { TARGET_CPU_m8, PROCESSOR_M8 },
     { -1, PROCESSOR_V7 }
   };
   const struct cpu_default *def;
@@ -1293,15 +1664,15 @@ sparc_option_override (void)
     { "v8",            MASK_ISA, MASK_V8 },
     /* TI TMS390Z55 supersparc */
     { "supersparc",    MASK_ISA, MASK_V8 },
-    { "hypersparc",    MASK_ISA, MASK_V8|MASK_FPU },
-    { "leon",          MASK_ISA, MASK_V8|MASK_LEON|MASK_FPU },
-    { "leon3",         MASK_ISA, MASK_V8|MASK_LEON3|MASK_FPU },
-    { "leon3v7",       MASK_ISA, MASK_LEON3|MASK_FPU },
+    { "hypersparc",    MASK_ISA, MASK_V8 },
+    { "leon",          MASK_ISA|MASK_FSMULD, MASK_V8|MASK_LEON },
+    { "leon3",         MASK_ISA, MASK_V8|MASK_LEON3 },
+    { "leon3v7",       MASK_ISA, MASK_LEON3 },
     { "sparclite",     MASK_ISA, MASK_SPARCLITE },
     /* The Fujitsu MB86930 is the original sparclite chip, with no FPU.  */
     { "f930",          MASK_ISA|MASK_FPU, MASK_SPARCLITE },
     /* The Fujitsu MB86934 is the recent sparclite chip, with an FPU.  */
-    { "f934",          MASK_ISA, MASK_SPARCLITE|MASK_FPU },
+    { "f934",          MASK_ISA, MASK_SPARCLITE },
     { "sparclite86x",  MASK_ISA|MASK_FPU, MASK_SPARCLITE },
     { "sparclet",      MASK_ISA, MASK_SPARCLET },
     /* TEMIC sparclet */
@@ -1329,11 +1700,13 @@ sparc_option_override (void)
       MASK_V9|MASK_POPC|MASK_VIS3|MASK_FMAF|MASK_CBCOND },
     /* UltraSPARC M7 */
     { "niagara7",      MASK_ISA,
-      MASK_V9|MASK_POPC|MASK_VIS4|MASK_FMAF|MASK_CBCOND|MASK_SUBXC }
+      MASK_V9|MASK_POPC|MASK_VIS4|MASK_FMAF|MASK_CBCOND|MASK_SUBXC },
+    /* UltraSPARC M8 */
+    { "m8",            MASK_ISA,
+      MASK_V9|MASK_POPC|MASK_VIS4B|MASK_FMAF|MASK_CBCOND|MASK_SUBXC }
   };
   const struct cpu_table *cpu;
   unsigned int i;
-  int fpu;
 
   if (sparc_debug_string != NULL)
     {
@@ -1360,7 +1733,7 @@ sparc_option_override (void)
          else if (! strcmp (q, "options"))
            mask = MASK_DEBUG_OPTIONS;
          else
-           error ("unknown -mdebug-%s switch", q);
+           error ("unknown %<-mdebug-%s%> switch", q);
 
          if (invert)
            sparc_debug &= ~mask;
@@ -1369,6 +1742,11 @@ sparc_option_override (void)
        }
     }
 
+  /* Enable the FsMULd instruction by default if not explicitly specified by
+     the user.  It may be later disabled by the CPU (explicitly or not).  */
+  if (TARGET_FPU && !(target_flags_explicit & MASK_FSMULD))
+    target_flags |= MASK_FSMULD;
+
   if (TARGET_DEBUG_OPTIONS)
     {
       dump_target_flags("Initial target_flags", target_flags);
@@ -1381,53 +1759,27 @@ sparc_option_override (void)
 
 #ifndef SPARC_BI_ARCH
   /* Check for unsupported architecture size.  */
-  if (! TARGET_64BIT != DEFAULT_ARCH32_P)
+  if (!TARGET_64BIT != DEFAULT_ARCH32_P)
     error ("%s is not supported by this configuration",
           DEFAULT_ARCH32_P ? "-m64" : "-m32");
 #endif
 
   /* We force all 64bit archs to use 128 bit long double */
-  if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
+  if (TARGET_ARCH64 && !TARGET_LONG_DOUBLE_128)
     {
-      error ("-mlong-double-64 not allowed with -m64");
+      error ("%<-mlong-double-64%> not allowed with %<-m64%>");
       target_flags |= MASK_LONG_DOUBLE_128;
     }
 
-  /* Code model selection.  */
-  sparc_cmodel = SPARC_DEFAULT_CMODEL;
-
-#ifdef SPARC_BI_ARCH
-  if (TARGET_ARCH32)
-    sparc_cmodel = CM_32;
-#endif
-
-  if (sparc_cmodel_string != NULL)
-    {
-      if (TARGET_ARCH64)
-       {
-         for (cmodel = &cmodels[0]; cmodel->name; cmodel++)
-           if (strcmp (sparc_cmodel_string, cmodel->name) == 0)
-             break;
-         if (cmodel->name == NULL)
-           error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string);
-         else
-           sparc_cmodel = cmodel->value;
-       }
-      else
-       error ("-mcmodel= is not supported on 32 bit systems");
-    }
-
   /* Check that -fcall-saved-REG wasn't specified for out registers.  */
   for (i = 8; i < 16; i++)
     if (!call_used_regs [i])
       {
-       error ("-fcall-saved-REG is not supported for out registers");
+       error ("%<-fcall-saved-REG%> is not supported for out registers");
         call_used_regs [i] = 1;
       }
 
-  fpu = target_flags & MASK_FPU; /* save current -mfpu status */
-
-  /* Set the default CPU.  */
+  /* Set the default CPU if no -mcpu option was specified.  */
   if (!global_options_set.x_sparc_cpu_and_features)
     {
       for (def = &cpu_default[0]; def->cpu != -1; ++def)
@@ -1437,6 +1789,7 @@ sparc_option_override (void)
       sparc_cpu_and_features = def->processor;
     }
 
+  /* Set the default CPU if no -mtune option was specified.  */
   if (!global_options_set.x_sparc_cpu)
     sparc_cpu = sparc_cpu_and_features;
 
@@ -1445,8 +1798,6 @@ sparc_option_override (void)
   if (TARGET_DEBUG_OPTIONS)
     {
       fprintf (stderr, "sparc_cpu_and_features: %s\n", cpu->name);
-      fprintf (stderr, "sparc_cpu: %s\n",
-              cpu_table[(int) sparc_cpu].name);
       dump_target_flags ("cpu->disable", cpu->disable);
       dump_target_flags ("cpu->enable", cpu->enable);
     }
@@ -1462,69 +1813,136 @@ sparc_option_override (void)
 #ifndef HAVE_AS_SPARC5_VIS4
                   & ~(MASK_VIS4 | MASK_SUBXC)
 #endif
+#ifndef HAVE_AS_SPARC6
+                  & ~(MASK_VIS4B)
+#endif
 #ifndef HAVE_AS_LEON
                   & ~(MASK_LEON | MASK_LEON3)
 #endif
+                  & ~(target_flags_explicit & MASK_FEATURES)
                   );
 
-  /* If -mfpu or -mno-fpu was explicitly used, don't override with
-     the processor default.  */
-  if (target_flags_explicit & MASK_FPU)
-    target_flags = (target_flags & ~MASK_FPU) | fpu;
+  /* FsMULd is a V8 instruction.  */
+  if (!TARGET_V8 && !TARGET_V9)
+    target_flags &= ~MASK_FSMULD;
 
-  /* -mvis2 implies -mvis */
+  /* -mvis2 implies -mvis */
   if (TARGET_VIS2)
     target_flags |= MASK_VIS;
 
-  /* -mvis3 implies -mvis2 and -mvis */
+  /* -mvis3 implies -mvis2 and -mvis */
   if (TARGET_VIS3)
     target_flags |= MASK_VIS2 | MASK_VIS;
 
-  /* -mvis4 implies -mvis3, -mvis2 and -mvis */
+  /* -mvis4 implies -mvis3, -mvis2 and -mvis */
   if (TARGET_VIS4)
     target_flags |= MASK_VIS3 | MASK_VIS2 | MASK_VIS;
 
-  /* Don't allow -mvis, -mvis2, -mvis3, -mvis4 or -mfmaf if FPU is
-     disabled.  */
-  if (! TARGET_FPU)
+  /* -mvis4b implies -mvis4, -mvis3, -mvis2 and -mvis */
+  if (TARGET_VIS4B)
+    target_flags |= MASK_VIS4 | MASK_VIS3 | MASK_VIS2 | MASK_VIS;
+
+  /* Don't allow -mvis, -mvis2, -mvis3, -mvis4, -mvis4b, -mfmaf and -mfsmuld if
+     FPU is disabled.  */
+  if (!TARGET_FPU)
     target_flags &= ~(MASK_VIS | MASK_VIS2 | MASK_VIS3 | MASK_VIS4
-                     | MASK_FMAF);
+                     | MASK_VIS4B | MASK_FMAF | MASK_FSMULD);
 
   /* -mvis assumes UltraSPARC+, so we are sure v9 instructions
-     are available.
-     -m64 also implies v9.  */
+     are available; -m64 also implies v9.  */
   if (TARGET_VIS || TARGET_ARCH64)
     {
       target_flags |= MASK_V9;
       target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE);
     }
 
-  /* -mvis also implies -mv8plus on 32-bit */
-  if (TARGET_VIS && ! TARGET_ARCH64)
+  /* -mvis also implies -mv8plus on 32-bit */
+  if (TARGET_VIS && !TARGET_ARCH64)
     target_flags |= MASK_V8PLUS;
 
-  /* Use the deprecated v8 insns for sparc64 in 32 bit mode.  */
+  /* Use the deprecated v8 insns for sparc64 in 32-bit mode.  */
   if (TARGET_V9 && TARGET_ARCH32)
     target_flags |= MASK_DEPRECATED_V8_INSNS;
 
-  /* V8PLUS requires V9, makes no sense in 64 bit mode.  */
-  if (! TARGET_V9 || TARGET_ARCH64)
+  /* V8PLUS requires V9 and makes no sense in 64-bit mode.  */
+  if (!TARGET_V9 || TARGET_ARCH64)
     target_flags &= ~MASK_V8PLUS;
 
-  /* Don't use stack biasing in 32 bit mode.  */
+  /* Don't use stack biasing in 32-bit mode.  */
   if (TARGET_ARCH32)
     target_flags &= ~MASK_STACK_BIAS;
 
+  /* Use LRA instead of reload, unless otherwise instructed.  */
+  if (!(target_flags_explicit & MASK_LRA))
+    target_flags |= MASK_LRA;
+
+  /* Enable applicable errata workarounds for LEON3FT.  */
+  if (sparc_fix_ut699 || sparc_fix_ut700 || sparc_fix_gr712rc)
+    {
+      sparc_fix_b2bst = 1;
+      sparc_fix_lost_divsqrt = 1;
+    }
+
+  /* Disable FsMULd for the UT699 since it doesn't work correctly.  */
+  if (sparc_fix_ut699)
+    target_flags &= ~MASK_FSMULD;
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+    target_flags |= MASK_LONG_DOUBLE_128;
+#endif
+
+  if (TARGET_DEBUG_OPTIONS)
+    dump_target_flags ("Final target_flags", target_flags);
+
+  /* Set the code model if no -mcmodel option was specified.  */
+  if (global_options_set.x_sparc_code_model)
+    {
+      if (TARGET_ARCH32)
+       error ("%<-mcmodel=%> is not supported in 32-bit mode");
+    }
+  else
+    {
+      if (TARGET_ARCH32)
+       sparc_code_model = CM_32;
+      else
+       sparc_code_model = SPARC_DEFAULT_CMODEL;
+    }
+
+  /* Set the memory model if no -mmemory-model option was specified.  */
+  if (!global_options_set.x_sparc_memory_model)
+    {
+      /* Choose the memory model for the operating system.  */
+      enum sparc_memory_model_type os_default = SUBTARGET_DEFAULT_MEMORY_MODEL;
+      if (os_default != SMM_DEFAULT)
+       sparc_memory_model = os_default;
+      /* Choose the most relaxed model for the processor.  */
+      else if (TARGET_V9)
+       sparc_memory_model = SMM_RMO;
+      else if (TARGET_LEON3)
+       sparc_memory_model = SMM_TSO;
+      else if (TARGET_LEON)
+       sparc_memory_model = SMM_SC;
+      else if (TARGET_V8)
+       sparc_memory_model = SMM_PSO;
+      else
+       sparc_memory_model = SMM_SC;
+    }
+
   /* Supply a default value for align_functions.  */
-  if (align_functions == 0
-      && (sparc_cpu == PROCESSOR_ULTRASPARC
+  if (flag_align_functions && !str_align_functions)
+    {
+      if (sparc_cpu == PROCESSOR_ULTRASPARC
          || sparc_cpu == PROCESSOR_ULTRASPARC3
          || sparc_cpu == PROCESSOR_NIAGARA
          || sparc_cpu == PROCESSOR_NIAGARA2
          || sparc_cpu == PROCESSOR_NIAGARA3
-         || sparc_cpu == PROCESSOR_NIAGARA4
-         || sparc_cpu == PROCESSOR_NIAGARA7))
-    align_functions = 32;
+         || sparc_cpu == PROCESSOR_NIAGARA4)
+       str_align_functions = "32";
+      else if (sparc_cpu == PROCESSOR_NIAGARA7
+              || sparc_cpu == PROCESSOR_M8)
+       str_align_functions = "64";
+    }
 
   /* Validate PCC_STRUCT_RETURN.  */
   if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN)
@@ -1534,12 +1952,7 @@ sparc_option_override (void)
   if (!TARGET_ARCH64)
     targetm.asm_out.unaligned_op.di = NULL;
 
-  /* Do various machine dependent initializations.  */
-  sparc_init_modes ();
-
-  /* Set up function hooks.  */
-  init_machine_status = sparc_init_machine_status;
-
+  /* Set the processor costs.  */
   switch (sparc_cpu)
     {
     case PROCESSOR_V7:
@@ -1590,38 +2003,14 @@ sparc_option_override (void)
     case PROCESSOR_NIAGARA7:
       sparc_costs = &niagara7_costs;
       break;
+    case PROCESSOR_M8:
+      sparc_costs = &m8_costs;
+      break;
     case PROCESSOR_NATIVE:
       gcc_unreachable ();
     };
 
-  if (sparc_memory_model == SMM_DEFAULT)
-    {
-      /* Choose the memory model for the operating system.  */
-      enum sparc_memory_model_type os_default = SUBTARGET_DEFAULT_MEMORY_MODEL;
-      if (os_default != SMM_DEFAULT)
-       sparc_memory_model = os_default;
-      /* Choose the most relaxed model for the processor.  */
-      else if (TARGET_V9)
-       sparc_memory_model = SMM_RMO;
-      else if (TARGET_LEON3)
-       sparc_memory_model = SMM_TSO;
-      else if (TARGET_LEON)
-       sparc_memory_model = SMM_SC;
-      else if (TARGET_V8)
-       sparc_memory_model = SMM_PSO;
-      else
-       sparc_memory_model = SMM_SC;
-    }
-
-#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
-  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
-    target_flags |= MASK_LONG_DOUBLE_128;
-#endif
-
-  if (TARGET_DEBUG_OPTIONS)
-    dump_target_flags ("Final target_flags", target_flags);
-
-  /* PARAM_SIMULTANEOUS_PREFETCHES is the number of prefetches that
+  /* param_simultaneous_prefetches is the number of prefetches that
      can run at the same time.  More important, it is the threshold
      defining when additional prefetches will be dropped by the
      hardware.
@@ -1644,21 +2033,21 @@ sparc_option_override (void)
      single-threaded program.  Experimental results show that setting
      this parameter to 32 works well when the number of threads is not
      high.  */
-  maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
-                        ((sparc_cpu == PROCESSOR_ULTRASPARC
-                          || sparc_cpu == PROCESSOR_NIAGARA
-                          || sparc_cpu == PROCESSOR_NIAGARA2
-                          || sparc_cpu == PROCESSOR_NIAGARA3
-                          || sparc_cpu == PROCESSOR_NIAGARA4)
-                         ? 2
-                         : (sparc_cpu == PROCESSOR_ULTRASPARC3
-                            ? 8 : (sparc_cpu == PROCESSOR_NIAGARA7
-                                   ? 32 : 3))),
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-
-  /* For PARAM_L1_CACHE_LINE_SIZE we use the default 32 bytes (see
-     params.def), so no maybe_set_param_value is needed.
+  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+                      param_simultaneous_prefetches,
+                      ((sparc_cpu == PROCESSOR_ULTRASPARC
+                        || sparc_cpu == PROCESSOR_NIAGARA
+                        || sparc_cpu == PROCESSOR_NIAGARA2
+                        || sparc_cpu == PROCESSOR_NIAGARA3
+                        || sparc_cpu == PROCESSOR_NIAGARA4)
+                       ? 2
+                       : (sparc_cpu == PROCESSOR_ULTRASPARC3
+                          ? 8 : ((sparc_cpu == PROCESSOR_NIAGARA7
+                                  || sparc_cpu == PROCESSOR_M8)
+                                 ? 32 : 3))));
+
+  /* param_l1_cache_line_size is the size of the L1 cache line, in
+     bytes.
 
      The Oracle SPARC Architecture (previously the UltraSPARC
      Architecture) specification states that when a PREFETCH[A]
@@ -1674,31 +2063,33 @@ sparc_option_override (void)
      L2 and L3, but only 32B are brought into the L1D$. (Assuming it
      is a read_n prefetch, which is the only type which allocates to
      the L1.)  */
+  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+                      param_l1_cache_line_size,
+                      (sparc_cpu == PROCESSOR_M8 ? 64 : 32));
 
-  /* PARAM_L1_CACHE_SIZE is the size of the L1D$ (most SPARC chips use
+  /* param_l1_cache_size is the size of the L1D$ (most SPARC chips use
      Hardvard level-1 caches) in kilobytes.  Both UltraSPARC and
      Niagara processors feature a L1D$ of 16KB.  */
-  maybe_set_param_value (PARAM_L1_CACHE_SIZE,
-                        ((sparc_cpu == PROCESSOR_ULTRASPARC
-                          || sparc_cpu == PROCESSOR_ULTRASPARC3
-                          || sparc_cpu == PROCESSOR_NIAGARA
-                          || sparc_cpu == PROCESSOR_NIAGARA2
-                          || sparc_cpu == PROCESSOR_NIAGARA3
-                          || sparc_cpu == PROCESSOR_NIAGARA4
-                          || sparc_cpu == PROCESSOR_NIAGARA7)
-                         ? 16 : 64),
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
-
-
-  /* PARAM_L2_CACHE_SIZE is the size fo the L2 in kilobytes.  Note
+  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+                      param_l1_cache_size,
+                      ((sparc_cpu == PROCESSOR_ULTRASPARC
+                        || sparc_cpu == PROCESSOR_ULTRASPARC3
+                        || sparc_cpu == PROCESSOR_NIAGARA
+                        || sparc_cpu == PROCESSOR_NIAGARA2
+                        || sparc_cpu == PROCESSOR_NIAGARA3
+                        || sparc_cpu == PROCESSOR_NIAGARA4
+                        || sparc_cpu == PROCESSOR_NIAGARA7
+                        || sparc_cpu == PROCESSOR_M8)
+                       ? 16 : 64));
+
+  /* param_l2_cache_size is the size fo the L2 in kilobytes.  Note
      that 512 is the default in params.def.  */
-  maybe_set_param_value (PARAM_L2_CACHE_SIZE,
-                        (sparc_cpu == PROCESSOR_NIAGARA4
-                         ? 128 : (sparc_cpu == PROCESSOR_NIAGARA7
-                                  ? 256 : 512)),
-                        global_options.x_param_values,
-                        global_options_set.x_param_values);
+  SET_OPTION_IF_UNSET (&global_options, &global_options_set,
+                      param_l2_cache_size,
+                      ((sparc_cpu == PROCESSOR_NIAGARA4
+                        || sparc_cpu == PROCESSOR_M8)
+                       ? 128 : (sparc_cpu == PROCESSOR_NIAGARA7
+                                ? 256 : 512)));
   
 
   /* Disable save slot sharing for call-clobbered registers by default.
@@ -1706,6 +2097,17 @@ sparc_option_override (void)
      pessimizes for double floating-point registers.  */
   if (!global_options_set.x_flag_ira_share_save_slots)
     flag_ira_share_save_slots = 0;
+
+  /* Only enable REE by default in 64-bit mode where it helps to eliminate
+     redundant 32-to-64-bit extensions.  */
+  if (!global_options_set.x_flag_ree && TARGET_ARCH32)
+    flag_ree = 0;
+
+  /* Do various machine dependent initializations.  */
+  sparc_init_modes ();
+
+  /* Set up function hooks.  */
+  init_machine_status = sparc_init_machine_status;
 }
 \f
 /* Miscellaneous utilities.  */
@@ -1826,7 +2228,7 @@ sparc_expand_move (machine_mode mode, rtx *operands)
        }
     }
 
-  /* Fixup TLS cases.  */
+  /* Fix up TLS cases.  */
   if (TARGET_HAVE_TLS
       && CONSTANT_P (operands[1])
       && sparc_tls_referenced_p (operands [1]))
@@ -1835,15 +2237,20 @@ sparc_expand_move (machine_mode mode, rtx *operands)
       return false;
     }
 
-  /* Fixup PIC cases.  */
+  /* Fix up PIC cases.  */
   if (flag_pic && CONSTANT_P (operands[1]))
     {
       if (pic_address_needs_scratch (operands[1]))
        operands[1] = sparc_legitimize_pic_address (operands[1], NULL_RTX);
 
       /* 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 ((GET_CODE (operands[1]) == LABEL_REF
+          && can_use_mov_pic_label_ref (operands[1]))
+         || (GET_CODE (operands[1]) == CONST
+             && GET_CODE (XEXP (operands[1], 0)) == PLUS
+             && GET_CODE (XEXP (XEXP (operands[1], 0), 0)) == LABEL_REF
+             && GET_CODE (XEXP (XEXP (operands[1], 0), 1)) == CONST_INT
+             && can_use_mov_pic_label_ref (XEXP (XEXP (operands[1], 0), 0))))
        {
          if (mode == SImode)
            {
@@ -1853,7 +2260,6 @@ sparc_expand_move (machine_mode mode, rtx *operands)
 
          if (mode == DImode)
            {
-             gcc_assert (TARGET_ARCH64);
              emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
              return true;
            }
@@ -1894,9 +2300,8 @@ sparc_expand_move (machine_mode mode, rtx *operands)
          /* We are able to build any SF constant in integer registers
             with at most 2 instructions.  */
          && (mode == SFmode
-             /* And any DF constant in integer registers.  */
-             || (mode == DFmode
-                 && ! can_create_pseudo_p ())))
+             /* And any DF constant in integer registers if needed.  */
+             || (mode == DFmode && !can_create_pseudo_p ())))
        return false;
 
       operands[1] = force_const_mem (mode, operands[1]);
@@ -1913,21 +2318,21 @@ sparc_expand_move (machine_mode mode, rtx *operands)
 
   switch (mode)
     {
-    case QImode:
+    case E_QImode:
       /* All QImode constants require only one insn, so proceed.  */
       break;
 
-    case HImode:
-    case SImode:
+    case E_HImode:
+    case E_SImode:
       sparc_emit_set_const32 (operands[0], operands[1]);
       return true;
 
-    case DImode:
+    case E_DImode:
       /* input_operand should have filtered out 32-bit mode.  */
       sparc_emit_set_const64 (operands[0], operands[1]);
       return true;
 
-    case TImode:
+    case E_TImode:
       {
        rtx high, low;
        /* TImode isn't available in 32-bit mode.  */
@@ -1992,17 +2397,33 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
 void
 sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
-  rtx temp1, temp2, temp3, temp4, temp5;
+  rtx cst, temp1, temp2, temp3, temp4, temp5;
   rtx ti_temp = 0;
 
+  /* Deal with too large offsets.  */
+  if (GET_CODE (op1) == CONST
+      && GET_CODE (XEXP (op1, 0)) == PLUS
+      && CONST_INT_P (cst = XEXP (XEXP (op1, 0), 1))
+      && trunc_int_for_mode (INTVAL (cst), SImode) != INTVAL (cst))
+    {
+      gcc_assert (!temp);
+      temp1 = gen_reg_rtx (DImode);
+      temp2 = gen_reg_rtx (DImode);
+      sparc_emit_set_const64 (temp2, cst);
+      sparc_emit_set_symbolic_const64 (temp1, XEXP (XEXP (op1, 0), 0),
+                                      NULL_RTX);
+      emit_insn (gen_rtx_SET (op0, gen_rtx_PLUS (DImode, temp1, temp2)));
+      return;
+    }
+
   if (temp && GET_MODE (temp) == TImode)
     {
       ti_temp = temp;
       temp = gen_rtx_REG (DImode, REGNO (temp));
     }
 
-  /* SPARC-V9 code-model support.  */
-  switch (sparc_cmodel)
+  /* SPARC-V9 code model support.  */
+  switch (sparc_code_model)
     {
     case CM_MEDLOW:
       /* The range spanned by all instructions in the object is less
@@ -2746,6 +3167,14 @@ sparc_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
   return true;
 }
 
+/* Implement TARGET_MIN_ARITHMETIC_PRECISION.  */
+
+static unsigned int
+sparc_min_arithmetic_precision (void)
+{
+  return 32;
+}
+
 /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
    return the mode to be used for the comparison.  For floating-point,
    CCFP[E]mode is used.  CCNZmode should be used when the first operand
@@ -2768,21 +3197,22 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y)
        case UNGT:
        case UNGE:
        case UNEQ:
-       case LTGT:
          return CCFPmode;
 
        case LT:
        case LE:
        case GT:
        case GE:
+       case LTGT:
          return CCFPEmode;
 
        default:
          gcc_unreachable ();
        }
     }
-  else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
-          || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+  else if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
+           || GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
+          && y == const0_rtx)
     {
       if (TARGET_ARCH64 && GET_MODE (x) == DImode)
        return CCXNZmode;
@@ -2800,6 +3230,18 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y)
            return CCCmode;
        }
 
+      /* This is for the [u]addvdi4_sp32 and [u]subvdi4_sp32 patterns.  */
+      if (!TARGET_ARCH64 && GET_MODE (x) == DImode)
+       {
+         if (GET_CODE (y) == UNSPEC
+             && (XINT (y, 1) == UNSPEC_ADDV
+                || XINT (y, 1) == UNSPEC_SUBV
+                || XINT (y, 1) == UNSPEC_NEGV))
+           return CCVmode;
+         else
+           return CCCmode;
+       }
+
       if (TARGET_ARCH64 && GET_MODE (x) == DImode)
        return CCXmode;
       else
@@ -3223,11 +3665,11 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
   if (GET_MODE (operands[0]) == TFmode)
     {
       if (nargs == 2)
-       emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2,
+       emit_library_call (func_sym, LCT_NORMAL, VOIDmode,
                           arg[0], GET_MODE (arg[0]),
                           arg[1], GET_MODE (arg[1]));
       else
-       emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3,
+       emit_library_call (func_sym, LCT_NORMAL, VOIDmode,
                           arg[0], GET_MODE (arg[0]),
                           arg[1], GET_MODE (arg[1]),
                           arg[2], GET_MODE (arg[2]));
@@ -3242,7 +3684,7 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
       gcc_assert (nargs == 2);
 
       ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
-                                    GET_MODE (operands[0]), 1,
+                                    GET_MODE (operands[0]),
                                     arg[1], GET_MODE (arg[1]));
 
       if (ret != operands[0])
@@ -3299,10 +3741,10 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case FLOAT_EXTEND:
       switch (GET_MODE (operands[1]))
        {
-       case SFmode:
+       case E_SFmode:
          func = "_Qp_stoq";
          break;
-       case DFmode:
+       case E_DFmode:
          func = "_Qp_dtoq";
          break;
        default:
@@ -3313,10 +3755,10 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case FLOAT_TRUNCATE:
       switch (GET_MODE (operands[0]))
        {
-       case SFmode:
+       case E_SFmode:
          func = "_Qp_qtos";
          break;
-       case DFmode:
+       case E_DFmode:
          func = "_Qp_qtod";
          break;
        default:
@@ -3327,12 +3769,12 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case FLOAT:
       switch (GET_MODE (operands[1]))
        {
-       case SImode:
+       case E_SImode:
          func = "_Qp_itoq";
          if (TARGET_ARCH64)
            operands[1] = gen_rtx_SIGN_EXTEND (DImode, operands[1]);
          break;
-       case DImode:
+       case E_DImode:
          func = "_Qp_xtoq";
          break;
        default:
@@ -3343,12 +3785,12 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case UNSIGNED_FLOAT:
       switch (GET_MODE (operands[1]))
        {
-       case SImode:
+       case E_SImode:
          func = "_Qp_uitoq";
          if (TARGET_ARCH64)
            operands[1] = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
          break;
-       case DImode:
+       case E_DImode:
          func = "_Qp_uxtoq";
          break;
        default:
@@ -3359,10 +3801,10 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case FIX:
       switch (GET_MODE (operands[0]))
        {
-       case SImode:
+       case E_SImode:
          func = "_Qp_qtoi";
          break;
-       case DImode:
+       case E_DImode:
          func = "_Qp_qtox";
          break;
        default:
@@ -3373,10 +3815,10 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
     case UNSIGNED_FIX:
       switch (GET_MODE (operands[0]))
        {
-       case SImode:
+       case E_SImode:
          func = "_Qp_qtoui";
          break;
-       case DImode:
+       case E_DImode:
          func = "_Qp_qtoux";
          break;
        default:
@@ -3788,20 +4230,114 @@ sparc_cannot_force_const_mem (machine_mode mode, rtx x)
 }
 \f
 /* Global Offset Table support.  */
+static GTY(()) rtx got_symbol_rtx = NULL_RTX;
+static GTY(()) rtx got_register_rtx = NULL_RTX;
 static GTY(()) rtx got_helper_rtx = NULL_RTX;
-static GTY(()) rtx global_offset_table_rtx = NULL_RTX;
+
+static GTY(()) bool got_helper_needed = false;
 
 /* Return the SYMBOL_REF for the Global Offset Table.  */
 
-static GTY(()) rtx sparc_got_symbol = NULL_RTX;
+static rtx
+sparc_got (void)
+{
+  if (!got_symbol_rtx)
+    got_symbol_rtx = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+
+  return got_symbol_rtx;
+}
+
+/* Wrapper around the load_pcrel_sym{si,di} patterns.  */
+
+static rtx
+gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2)
+{
+  int orig_flag_pic = flag_pic;
+  rtx insn;
+
+  /* The load_pcrel_sym{si,di} patterns require absolute addressing.  */
+  flag_pic = 0;
+  if (TARGET_ARCH64)
+    insn = gen_load_pcrel_symdi (op0, op1, op2, GEN_INT (REGNO (op0)));
+  else
+    insn = gen_load_pcrel_symsi (op0, op1, op2, GEN_INT (REGNO (op0)));
+  flag_pic = orig_flag_pic;
+
+  return insn;
+}
+
+/* Output the load_pcrel_sym{si,di} patterns.  */
+
+const char *
+output_load_pcrel_sym (rtx *operands)
+{
+  if (flag_delayed_branch)
+    {
+      output_asm_insn ("sethi\t%%hi(%a1-4), %0", operands);
+      output_asm_insn ("call\t%a2", operands);
+      output_asm_insn (" add\t%0, %%lo(%a1+4), %0", operands);
+    }
+  else
+    {
+      output_asm_insn ("sethi\t%%hi(%a1-8), %0", operands);
+      output_asm_insn ("add\t%0, %%lo(%a1-4), %0", operands);
+      output_asm_insn ("call\t%a2", operands);
+      output_asm_insn (" nop", NULL);
+    }
+
+  if (operands[2] == got_helper_rtx)
+    got_helper_needed = true;
+
+  return "";
+}
+
+#ifdef HAVE_GAS_HIDDEN
+# define USE_HIDDEN_LINKONCE 1
+#else
+# define USE_HIDDEN_LINKONCE 0
+#endif
+
+/* Emit code to load the GOT register.  */
+
+void
+load_got_register (void)
+{
+  rtx insn;
+
+  if (TARGET_VXWORKS_RTP)
+    {
+      if (!got_register_rtx)
+       got_register_rtx = pic_offset_table_rtx;
+
+      insn = gen_vxworks_load_got ();
+    }
+  else
+    {
+      if (!got_register_rtx)
+       got_register_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM);
+
+      /* The GOT symbol is subject to a PC-relative relocation so we need a
+        helper function to add the PC value and thus get the final value.  */
+      if (!got_helper_rtx)
+       {
+         char name[32];
+
+         /* Skip the leading '%' as that cannot be used in a symbol name.  */
+         if (USE_HIDDEN_LINKONCE)
+           sprintf (name, "__sparc_get_pc_thunk.%s",
+                    reg_names[REGNO (got_register_rtx)] + 1);
+         else
+           ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC",
+                                        REGNO (got_register_rtx));
+
+         got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
+       }
 
-static rtx
-sparc_got (void)
-{
-  if (!sparc_got_symbol)
-    sparc_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+      insn
+       = gen_load_pcrel_sym (got_register_rtx, sparc_got (), got_helper_rtx);
+    }
 
-  return sparc_got_symbol;
+  emit_insn (insn);
 }
 
 /* Ensure that we are not using patterns that are not OK with PIC.  */
@@ -3834,10 +4370,11 @@ int
 pic_address_needs_scratch (rtx x)
 {
   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
-  if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+  if (GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-      && ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
+      && !SMALL_INT (XEXP (XEXP (x, 0), 1)))
     return 1;
 
   return 0;
@@ -3924,6 +4461,25 @@ legitimate_pic_operand_p (rtx x)
   return true;
 }
 
+/* Return true if X is a representation of the PIC register.  */
+
+static bool
+sparc_pic_register_p (rtx x)
+{
+  if (!REG_P (x) || !pic_offset_table_rtx)
+    return false;
+
+  if (x == pic_offset_table_rtx)
+    return true;
+
+  if (!HARD_REGISTER_P (pic_offset_table_rtx)
+      && (HARD_REGISTER_P (x) || lra_in_progress || reload_in_progress)
+      && ORIGINAL_REGNO (x) == REGNO (pic_offset_table_rtx))
+    return true;
+
+  return false;
+}
+
 #define RTX_OK_FOR_OFFSET_P(X, MODE)                   \
   (CONST_INT_P (X)                                     \
    && INTVAL (X) >= -0x1000                            \
@@ -3964,7 +4520,7 @@ sparc_legitimate_address_p (machine_mode mode, rtx addr, bool strict)
        }
 
       if ((flag_pic == 1
-          && rs1 == pic_offset_table_rtx
+          && sparc_pic_register_p (rs1)
           && !REG_P (rs2)
           && GET_CODE (rs2) != SUBREG
           && GET_CODE (rs2) != LO_SUM
@@ -4107,7 +4663,7 @@ sparc_tls_got (void)
   if (TARGET_SUN_TLS && TARGET_ARCH32)
     {
       load_got_register ();
-      return global_offset_table_rtx;
+      return got_register_rtx;
     }
 
   /* In all other cases, we load a new pseudo with the GOT symbol.  */
@@ -4144,30 +4700,38 @@ sparc_legitimize_tls_address (rtx addr)
   gcc_assert (can_create_pseudo_p ());
 
   if (GET_CODE (addr) == SYMBOL_REF)
+    /* Although the various sethi/or sequences generate SImode values, many of
+       them can be transformed by the linker when relaxing and, if relaxing to
+       local-exec, will become a sethi/xor pair, which is signed and therefore
+       a full DImode value in 64-bit mode.  Thus we must use Pmode, lest these
+       values be spilled onto the stack in 64-bit mode.  */
     switch (SYMBOL_REF_TLS_MODEL (addr))
       {
       case TLS_MODEL_GLOBAL_DYNAMIC:
        start_sequence ();
-       temp1 = gen_reg_rtx (SImode);
-       temp2 = gen_reg_rtx (SImode);
+       temp1 = gen_reg_rtx (Pmode);
+       temp2 = gen_reg_rtx (Pmode);
        ret = gen_reg_rtx (Pmode);
        o0 = gen_rtx_REG (Pmode, 8);
        got = sparc_tls_got ();
-       emit_insn (gen_tgd_hi22 (temp1, addr));
-       emit_insn (gen_tgd_lo10 (temp2, temp1, addr));
        if (TARGET_ARCH32)
          {
-           emit_insn (gen_tgd_add32 (o0, got, temp2, addr));
-           insn = emit_call_insn (gen_tgd_call32 (o0, sparc_tls_get_addr (),
+           emit_insn (gen_tgd_hi22si (temp1, addr));
+           emit_insn (gen_tgd_lo10si (temp2, temp1, addr));
+           emit_insn (gen_tgd_addsi (o0, got, temp2, addr));
+           insn = emit_call_insn (gen_tgd_callsi (o0, sparc_tls_get_addr (),
                                                   addr, const1_rtx));
          }
        else
          {
-           emit_insn (gen_tgd_add64 (o0, got, temp2, addr));
-           insn = emit_call_insn (gen_tgd_call64 (o0, sparc_tls_get_addr (),
+           emit_insn (gen_tgd_hi22di (temp1, addr));
+           emit_insn (gen_tgd_lo10di (temp2, temp1, addr));
+           emit_insn (gen_tgd_adddi (o0, got, temp2, addr));
+           insn = emit_call_insn (gen_tgd_calldi (o0, sparc_tls_get_addr (),
                                                   addr, const1_rtx));
          }
        use_reg (&CALL_INSN_FUNCTION_USAGE (insn), o0);
+       RTL_CONST_CALL_P (insn) = 1;
        insn = get_insns ();
        end_sequence ();
        emit_libcall_block (insn, ret, o0, addr);
@@ -4175,61 +4739,78 @@ sparc_legitimize_tls_address (rtx addr)
 
       case TLS_MODEL_LOCAL_DYNAMIC:
        start_sequence ();
-       temp1 = gen_reg_rtx (SImode);
-       temp2 = gen_reg_rtx (SImode);
+       temp1 = gen_reg_rtx (Pmode);
+       temp2 = gen_reg_rtx (Pmode);
        temp3 = gen_reg_rtx (Pmode);
        ret = gen_reg_rtx (Pmode);
        o0 = gen_rtx_REG (Pmode, 8);
        got = sparc_tls_got ();
-       emit_insn (gen_tldm_hi22 (temp1));
-       emit_insn (gen_tldm_lo10 (temp2, temp1));
        if (TARGET_ARCH32)
          {
-           emit_insn (gen_tldm_add32 (o0, got, temp2));
-           insn = emit_call_insn (gen_tldm_call32 (o0, sparc_tls_get_addr (),
+           emit_insn (gen_tldm_hi22si (temp1));
+           emit_insn (gen_tldm_lo10si (temp2, temp1));
+           emit_insn (gen_tldm_addsi (o0, got, temp2));
+           insn = emit_call_insn (gen_tldm_callsi (o0, sparc_tls_get_addr (),
                                                    const1_rtx));
          }
        else
          {
-           emit_insn (gen_tldm_add64 (o0, got, temp2));
-           insn = emit_call_insn (gen_tldm_call64 (o0, sparc_tls_get_addr (),
+           emit_insn (gen_tldm_hi22di (temp1));
+           emit_insn (gen_tldm_lo10di (temp2, temp1));
+           emit_insn (gen_tldm_adddi (o0, got, temp2));
+           insn = emit_call_insn (gen_tldm_calldi (o0, sparc_tls_get_addr (),
                                                    const1_rtx));
          }
        use_reg (&CALL_INSN_FUNCTION_USAGE (insn), o0);
+       RTL_CONST_CALL_P (insn) = 1;
        insn = get_insns ();
        end_sequence ();
+       /* Attach a unique REG_EQUAL, to allow the RTL optimizers to
+         share the LD_BASE result with other LD model accesses.  */
        emit_libcall_block (insn, temp3, o0,
                            gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
                                            UNSPEC_TLSLD_BASE));
-       temp1 = gen_reg_rtx (SImode);
-       temp2 = gen_reg_rtx (SImode);
-       emit_insn (gen_tldo_hix22 (temp1, addr));
-       emit_insn (gen_tldo_lox10 (temp2, temp1, addr));
+       temp1 = gen_reg_rtx (Pmode);
+       temp2 = gen_reg_rtx (Pmode);
        if (TARGET_ARCH32)
-         emit_insn (gen_tldo_add32 (ret, temp3, temp2, addr));
+         {
+           emit_insn (gen_tldo_hix22si (temp1, addr));
+           emit_insn (gen_tldo_lox10si (temp2, temp1, addr));
+           emit_insn (gen_tldo_addsi (ret, temp3, temp2, addr));
+         }
        else
-         emit_insn (gen_tldo_add64 (ret, temp3, temp2, addr));
+         {
+           emit_insn (gen_tldo_hix22di (temp1, addr));
+           emit_insn (gen_tldo_lox10di (temp2, temp1, addr));
+           emit_insn (gen_tldo_adddi (ret, temp3, temp2, addr));
+         }
        break;
 
       case TLS_MODEL_INITIAL_EXEC:
-       temp1 = gen_reg_rtx (SImode);
-       temp2 = gen_reg_rtx (SImode);
+       temp1 = gen_reg_rtx (Pmode);
+       temp2 = gen_reg_rtx (Pmode);
        temp3 = gen_reg_rtx (Pmode);
        got = sparc_tls_got ();
-       emit_insn (gen_tie_hi22 (temp1, addr));
-       emit_insn (gen_tie_lo10 (temp2, temp1, addr));
        if (TARGET_ARCH32)
-         emit_insn (gen_tie_ld32 (temp3, got, temp2, addr));
+         {
+           emit_insn (gen_tie_hi22si (temp1, addr));
+           emit_insn (gen_tie_lo10si (temp2, temp1, addr));
+           emit_insn (gen_tie_ld32 (temp3, got, temp2, addr));
+         }
        else
-         emit_insn (gen_tie_ld64 (temp3, got, temp2, addr));
+         {
+           emit_insn (gen_tie_hi22di (temp1, addr));
+           emit_insn (gen_tie_lo10di (temp2, temp1, addr));
+           emit_insn (gen_tie_ld64 (temp3, got, temp2, addr));
+         }
         if (TARGET_SUN_TLS)
          {
            ret = gen_reg_rtx (Pmode);
            if (TARGET_ARCH32)
-             emit_insn (gen_tie_add32 (ret, gen_rtx_REG (Pmode, 7),
+             emit_insn (gen_tie_addsi (ret, gen_rtx_REG (Pmode, 7),
                                        temp3, addr));
            else
-             emit_insn (gen_tie_add64 (ret, gen_rtx_REG (Pmode, 7),
+             emit_insn (gen_tie_adddi (ret, gen_rtx_REG (Pmode, 7),
                                        temp3, addr));
          }
        else
@@ -4241,13 +4822,13 @@ sparc_legitimize_tls_address (rtx addr)
        temp2 = gen_reg_rtx (Pmode);
        if (TARGET_ARCH32)
          {
-           emit_insn (gen_tle_hix22_sp32 (temp1, addr));
-           emit_insn (gen_tle_lox10_sp32 (temp2, temp1, addr));
+           emit_insn (gen_tle_hix22si (temp1, addr));
+           emit_insn (gen_tle_lox10si (temp2, temp1, addr));
          }
        else
          {
-           emit_insn (gen_tle_hix22_sp64 (temp1, addr));
-           emit_insn (gen_tle_lox10_sp64 (temp2, temp1, addr));
+           emit_insn (gen_tle_hix22di (temp1, addr));
+           emit_insn (gen_tle_lox10di (temp2, temp1, addr));
          }
        ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp2);
        break;
@@ -4285,16 +4866,15 @@ sparc_legitimize_tls_address (rtx addr)
 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.  */
       || (GET_CODE (orig) == LABEL_REF && !can_use_mov_pic_label_ref (orig)))
     {
+      bool gotdata_op = false;
       rtx pic_ref, address;
       rtx_insn *insn;
 
-      if (reg == 0)
+      if (!reg)
        {
          gcc_assert (can_create_pseudo_p ());
          reg = gen_reg_rtx (Pmode);
@@ -4305,8 +4885,7 @@ sparc_legitimize_pic_address (rtx orig, rtx reg)
          /* If not during reload, allocate another temp reg here for loading
             in the address, so that these instructions can be optimized
             properly.  */
-         rtx temp_reg = (! can_create_pseudo_p ()
-                         ? reg : gen_reg_rtx (Pmode));
+         rtx temp_reg = can_create_pseudo_p () ? gen_reg_rtx (Pmode) : reg;
 
          /* Must put the SYMBOL_REF inside an UNSPEC here so that cse
             won't get confused into thinking that these two instructions
@@ -4322,6 +4901,7 @@ sparc_legitimize_pic_address (rtx orig, rtx reg)
              emit_insn (gen_movsi_high_pic (temp_reg, orig));
              emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
+
          address = temp_reg;
          gotdata_op = true;
        }
@@ -4359,10 +4939,10 @@ sparc_legitimize_pic_address (rtx orig, rtx reg)
       rtx base, offset;
 
       if (GET_CODE (XEXP (orig, 0)) == PLUS
-         && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+         && sparc_pic_register_p (XEXP (XEXP (orig, 0), 0)))
        return orig;
 
-      if (reg == 0)
+      if (!reg)
        {
          gcc_assert (can_create_pseudo_p ());
          reg = gen_reg_rtx (Pmode);
@@ -4450,12 +5030,19 @@ sparc_delegitimize_address (rtx x)
 {
   x = delegitimize_mem_from_attrs (x);
 
-  if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 1)) == UNSPEC)
-    switch (XINT (XEXP (x, 1), 1))
+  if (GET_CODE (x) == LO_SUM)
+    x = XEXP (x, 1);
+
+  if (GET_CODE (x) == UNSPEC)
+    switch (XINT (x, 1))
       {
       case UNSPEC_MOVE_PIC:
       case UNSPEC_TLSLE:
-       x = XVECEXP (XEXP (x, 1), 0, 0);
+       x = XVECEXP (x, 0, 0);
+       gcc_assert (GET_CODE (x) == SYMBOL_REF);
+       break;
+      case UNSPEC_MOVE_GOTDATA:
+       x = XVECEXP (x, 0, 2);
        gcc_assert (GET_CODE (x) == SYMBOL_REF);
        break;
       default:
@@ -4464,14 +5051,23 @@ sparc_delegitimize_address (rtx x)
 
   /* This is generated by mov{si,di}_pic_label_ref in PIC mode.  */
   if (GET_CODE (x) == MINUS
-      && REG_P (XEXP (x, 0))
-      && REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM
-      && GET_CODE (XEXP (x, 1)) == LO_SUM
-      && GET_CODE (XEXP (XEXP (x, 1), 1)) == UNSPEC
-      && XINT (XEXP (XEXP (x, 1), 1), 1) == UNSPEC_MOVE_PIC_LABEL)
+      && (XEXP (x, 0) == got_register_rtx
+         || sparc_pic_register_p (XEXP (x, 0))))
     {
-      x = XVECEXP (XEXP (XEXP (x, 1), 1), 0, 0);
-      gcc_assert (GET_CODE (x) == LABEL_REF);
+      rtx y = XEXP (x, 1);
+
+      if (GET_CODE (y) == LO_SUM)
+       y = XEXP (y, 1);
+
+      if (GET_CODE (y) == UNSPEC && XINT (y, 1) == UNSPEC_MOVE_PIC_LABEL)
+       {
+         x = XVECEXP (y, 0, 0);
+         gcc_assert (GET_CODE (x) == LABEL_REF
+                     || (GET_CODE (x) == CONST
+                         && GET_CODE (XEXP (x, 0)) == PLUS
+                         && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
+                         && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT));
+       }
     }
 
   return x;
@@ -4500,7 +5096,7 @@ sparc_legitimize_reload_address (rtx x, machine_mode mode,
       && GET_MODE (x) == SImode
       && GET_CODE (x) != LO_SUM
       && GET_CODE (x) != HIGH
-      && sparc_cmodel <= CM_MEDLOW
+      && sparc_code_model <= CM_MEDLOW
       && !(flag_pic
           && (symbolic_operand (x, Pmode) || pic_address_needs_scratch (x))))
     {
@@ -4544,92 +5140,14 @@ static bool
 sparc_mode_dependent_address_p (const_rtx addr,
                                addr_space_t as ATTRIBUTE_UNUSED)
 {
-  if (flag_pic && GET_CODE (addr) == PLUS)
-    {
-      rtx op0 = XEXP (addr, 0);
-      rtx op1 = XEXP (addr, 1);
-      if (op0 == pic_offset_table_rtx
-         && symbolic_operand (op1, VOIDmode))
-       return true;
-    }
+  if (GET_CODE (addr) == PLUS
+      && sparc_pic_register_p (XEXP (addr, 0))
+      && symbolic_operand (XEXP (addr, 1), VOIDmode))
+    return true;
 
   return false;
 }
 
-#ifdef HAVE_GAS_HIDDEN
-# define USE_HIDDEN_LINKONCE 1
-#else
-# define USE_HIDDEN_LINKONCE 0
-#endif
-
-static void
-get_pc_thunk_name (char name[32], unsigned int regno)
-{
-  const char *reg_name = reg_names[regno];
-
-  /* Skip the leading '%' as that cannot be used in a
-     symbol name.  */
-  reg_name += 1;
-
-  if (USE_HIDDEN_LINKONCE)
-    sprintf (name, "__sparc_get_pc_thunk.%s", reg_name);
-  else
-    ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno);
-}
-
-/* Wrapper around the load_pcrel_sym{si,di} patterns.  */
-
-static rtx
-gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3)
-{
-  int orig_flag_pic = flag_pic;
-  rtx insn;
-
-  /* The load_pcrel_sym{si,di} patterns require absolute addressing.  */
-  flag_pic = 0;
-  if (TARGET_ARCH64)
-    insn = gen_load_pcrel_symdi (op0, op1, op2, op3);
-  else
-    insn = gen_load_pcrel_symsi (op0, op1, op2, op3);
-  flag_pic = orig_flag_pic;
-
-  return insn;
-}
-
-/* Emit code to load the GOT register.  */
-
-void
-load_got_register (void)
-{
-  /* In PIC mode, this will retrieve pic_offset_table_rtx.  */
-  if (!global_offset_table_rtx)
-    global_offset_table_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM);
-
-  if (TARGET_VXWORKS_RTP)
-    emit_insn (gen_vxworks_load_got ());
-  else
-    {
-      /* The GOT symbol is subject to a PC-relative relocation so we need a
-        helper function to add the PC value and thus get the final value.  */
-      if (!got_helper_rtx)
-       {
-         char name[32];
-         get_pc_thunk_name (name, GLOBAL_OFFSET_TABLE_REGNUM);
-         got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
-       }
-
-      emit_insn (gen_load_pcrel_sym (global_offset_table_rtx, sparc_got (),
-                                    got_helper_rtx,
-                                    GEN_INT (GLOBAL_OFFSET_TABLE_REGNUM)));
-    }
-
-  /* Need to emit this whether or not we obey regdecls,
-     since setjmp/longjmp can cause life info to screw up.
-     ??? In the case where we don't obey regdecls, this is not sufficient
-     since we may not fall out the bottom.  */
-  emit_use (global_offset_table_rtx);
-}
-
 /* Emit a call instruction with the pattern given by PAT.  ADDR is the
    address of the call target.  */
 
@@ -4754,7 +5272,7 @@ enum sparc_mode_class {
   ((1 << (int) H_MODE) | (1 << (int) S_MODE) | (1 << (int) SF_MODE))
 
 /* Modes for double-word and smaller quantities.  */
-#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
+#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << (int) DF_MODE))
 
 /* Modes for quad-word and smaller quantities.  */
 #define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
@@ -4766,7 +5284,7 @@ enum sparc_mode_class {
 #define SF_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
 
 /* Modes for double-float and smaller quantities.  */
-#define DF_MODES (SF_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
+#define DF_MODES (SF_MODES | (1 << (int) D_MODE) | (1 << (int) DF_MODE))
 
 /* Modes for quad-float and smaller quantities.  */
 #define TF_MODES (DF_MODES | (1 << (int) TF_MODE))
@@ -4797,8 +5315,8 @@ enum sparc_mode_class {
    ??? Note that, despite the settings, non-double-aligned parameter
    registers can hold double-word quantities in 32-bit mode.  */
 
-/* This points to either the 32 bit or the 64 bit version.  */
-const int *hard_regno_mode_classes;
+/* This points to either the 32-bit or the 64-bit version.  */
+static const int *hard_regno_mode_classes;
 
 static const int hard_32bit_mode_classes[] = {
   S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
@@ -4850,7 +5368,7 @@ static const int hard_64bit_mode_classes[] = {
   CC_MODES, 0, D_MODES
 };
 
-int sparc_mode_class [NUM_MACHINE_MODES];
+static int sparc_mode_class [NUM_MACHINE_MODES];
 
 enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
 
@@ -4944,7 +5462,7 @@ static inline bool
 save_global_or_fp_reg_p (unsigned int regno,
                         int leaf_function ATTRIBUTE_UNUSED)
 {
-  return !call_used_regs[regno] && df_regs_ever_live_p (regno);
+  return !call_used_or_fixed_reg_p (regno) && df_regs_ever_live_p (regno);
 }
 
 /* Return whether the return address register (%i7) is needed.  */
@@ -4972,7 +5490,7 @@ static bool
 save_local_or_in_reg_p (unsigned int regno, int leaf_function)
 {
   /* General case: call-saved registers live at some point.  */
-  if (!call_used_regs[regno] && df_regs_ever_live_p (regno))
+  if (!call_used_or_fixed_reg_p (regno) && df_regs_ever_live_p (regno))
     return true;
 
   /* Frame pointer register (%fp) if needed.  */
@@ -4984,7 +5502,7 @@ save_local_or_in_reg_p (unsigned int regno, int leaf_function)
     return true;
 
   /* GOT register (%l7) if needed.  */
-  if (regno == PIC_OFFSET_TABLE_REGNUM && crtl->uses_pic_offset_table)
+  if (got_register_rtx && regno == REGNO (got_register_rtx))
     return true;
 
   /* If the function accesses prior frames, the frame pointer and the return
@@ -4999,7 +5517,7 @@ save_local_or_in_reg_p (unsigned int regno, int leaf_function)
 /* Compute the frame size required by the function.  This function is called
    during the reload pass and also by sparc_expand_prologue.  */
 
-HOST_WIDE_INT
+static HOST_WIDE_INT
 sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function)
 {
   HOST_WIDE_INT frame_size, apparent_frame_size;
@@ -5054,9 +5572,8 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function)
     frame_size = apparent_frame_size = 0;
   else
     {
-      /* We subtract STARTING_FRAME_OFFSET, remember it's negative.  */
-      apparent_frame_size = ROUND_UP (size - STARTING_FRAME_OFFSET, 8);
-      apparent_frame_size += n_global_fp_regs * 4;
+      /* Start from the apparent frame size.  */
+      apparent_frame_size = ROUND_UP (size, 8) + n_global_fp_regs * 4;
 
       /* We need to add the size of the outgoing argument area.  */
       frame_size = apparent_frame_size + ROUND_UP (args_size, 8);
@@ -5098,7 +5615,6 @@ sparc_initial_elimination_offset (int to)
 void
 sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
 {
-#ifdef HAVE_AS_REGISTER_PSEUDO_OP
   int i;
 
   if (TARGET_ARCH32)
@@ -5119,7 +5635,6 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
        }
       if (i == 3) i = 5;
     }
-#endif
 }
 
 #define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
@@ -5336,17 +5851,17 @@ emit_save_or_restore_regs (unsigned int low, unsigned int high, rtx base,
 
          if (reg0 && reg1)
            {
-             mode = SPARC_INT_REG_P (i) ? DImode : DFmode;
+             mode = SPARC_INT_REG_P (i) ? E_DImode : E_DFmode;
              regno = i;
            }
          else if (reg0)
            {
-             mode = SPARC_INT_REG_P (i) ? SImode : SFmode;
+             mode = SPARC_INT_REG_P (i) ? E_SImode : E_SFmode;
              regno = i;
            }
          else if (reg1)
            {
-             mode = SPARC_INT_REG_P (i) ? SImode : SFmode;
+             mode = SPARC_INT_REG_P (i) ? E_SImode : E_SFmode;
              regno = i + 1;
              offset += 4;
            }
@@ -5516,16 +6031,17 @@ sparc_expand_prologue (void)
   if (flag_stack_usage_info)
     current_function_static_stack_size = size;
 
-  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+      || flag_stack_clash_protection)
     {
       if (crtl->is_leaf && !cfun->calls_alloca)
        {
-         if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
-           sparc_emit_probe_stack_range (STACK_CHECK_PROTECT,
-                                         size - STACK_CHECK_PROTECT);
+         if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+           sparc_emit_probe_stack_range (get_stack_check_protect (),
+                                         size - get_stack_check_protect ());
        }
       else if (size > 0)
-       sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+       sparc_emit_probe_stack_range (get_stack_check_protect (), size);
     }
 
   if (size == 0)
@@ -5602,10 +6118,6 @@ sparc_expand_prologue (void)
                                           - sparc_apparent_frame_size,
                                         SORR_SAVE);
 
-  /* Load the GOT register if needed.  */
-  if (crtl->uses_pic_offset_table)
-    load_got_register ();
-
   /* Advertise that the data calculated just above are now valid.  */
   sparc_prologue_data_valid_p = true;
 }
@@ -5627,16 +6139,17 @@ sparc_flat_expand_prologue (void)
   if (flag_stack_usage_info)
     current_function_static_stack_size = size;
 
-  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+  if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+      || flag_stack_clash_protection)
     {
       if (crtl->is_leaf && !cfun->calls_alloca)
        {
-         if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
-           sparc_emit_probe_stack_range (STACK_CHECK_PROTECT,
-                                         size - STACK_CHECK_PROTECT);
+         if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+           sparc_emit_probe_stack_range (get_stack_check_protect (),
+                                         size - get_stack_check_protect ());
        }
       else if (size > 0)
-       sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+       sparc_emit_probe_stack_range (get_stack_check_protect (), size);
     }
 
   if (sparc_save_local_in_regs_p)
@@ -5723,10 +6236,6 @@ sparc_flat_expand_prologue (void)
                                           - sparc_apparent_frame_size,
                                         SORR_SAVE);
 
-  /* Load the GOT register if needed.  */
-  if (crtl->uses_pic_offset_table)
-    load_got_register ();
-
   /* Advertise that the data calculated just above are now valid.  */
   sparc_prologue_data_valid_p = true;
 }
@@ -5735,7 +6244,7 @@ sparc_flat_expand_prologue (void)
    down to emitting the necessary .register directives.  */
 
 static void
-sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+sparc_asm_function_prologue (FILE *file)
 {
   /* Check that the assumption we made in sparc_expand_prologue is valid.  */
   if (!TARGET_FLAT)
@@ -5752,6 +6261,9 @@ sparc_expand_epilogue (bool for_eh)
 {
   HOST_WIDE_INT size = sparc_frame_size;
 
+  if (cfun->calls_alloca)
+    emit_insn (gen_frame_blockage ());
+
   if (sparc_n_global_fp_regs > 0)
     emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
                                         sparc_frame_base_offset
@@ -5854,7 +6366,7 @@ sparc_can_use_return_insn_p (void)
 /* This function generates the assembly code for function exit.  */
 
 static void
-sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+sparc_asm_function_epilogue (FILE *file)
 {
   /* If the last two instructions of a function are "call foo; dslot;"
      the return address might point to the first instruction in the next
@@ -5972,7 +6484,8 @@ output_return (rtx_insn *insn)
 
       if (final_sequence)
        {
-         rtx delay, pat;
+         rtx_insn *delay;
+         rtx pat;
 
          delay = NEXT_INSN (insn);
          gcc_assert (delay);
@@ -5987,9 +6500,15 @@ output_return (rtx_insn *insn)
          else
            {
              output_asm_insn ("jmp\t%%i7+%)", NULL);
-             output_restore (pat);
+
+             /* We're going to output the insn in the delay slot manually.
+                Make sure to output its source location first.  */
              PATTERN (delay) = gen_blockage ();
              INSN_CODE (delay) = -1;
+             final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
+             INSN_LOCATION (delay) = UNKNOWN_LOCATION;
+
+             output_restore (pat);
            }
        }
       else
@@ -6045,13 +6564,22 @@ output_sibcall (rtx_insn *insn, rtx call_operand)
 
       if (final_sequence)
        {
-         rtx_insn *delay = NEXT_INSN (insn);
+         rtx_insn *delay;
+         rtx pat;
+
+         delay = NEXT_INSN (insn);
          gcc_assert (delay);
 
-         output_restore (PATTERN (delay));
+         pat = PATTERN (delay);
 
+         /* We're going to output the insn in the delay slot manually.
+            Make sure to output its source location first.  */
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
+         final_scan_insn (delay, asm_out_file, optimize, 0, NULL);
+         INSN_LOCATION (delay) = UNKNOWN_LOCATION;
+
+         output_restore (pat);
        }
       else
        output_restore (NULL_RTX);
@@ -6176,7 +6704,7 @@ output_sibcall (rtx_insn *insn, rtx call_operand)
 Note #1: complex floating-point types follow the extended SPARC ABIs as
 implemented by the Sun compiler.
 
-Note #2: integral vector types follow the scalar floating-point types
+Note #2: integer 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
@@ -6231,15 +6759,65 @@ sparc_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
   return TARGET_ARCH64 ? true : false;
 }
 
+/* Handle the TARGET_PASS_BY_REFERENCE target hook.
+   Specify whether to pass the argument by reference.  */
+
+static bool
+sparc_pass_by_reference (cumulative_args_t, const function_arg_info &arg)
+{
+  tree type = arg.type;
+  machine_mode mode = arg.mode;
+  if (TARGET_ARCH32)
+    /* Original SPARC 32-bit ABI says that structures and unions,
+       and quad-precision floats are passed by reference.
+       All other base types are passed in registers.
+
+       Extended ABI (as implemented by the Sun compiler) says that all
+       complex floats are passed by reference.  Pass complex integers
+       in registers up to 8 bytes.  More generally, enforce the 2-word
+       cap for passing arguments in registers.
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that integer
+       vectors are passed like floats of the same size, that is in
+       registers up to 8 bytes.  Pass all vector floats by reference
+       like structure and unions.  */
+    return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
+           || mode == SCmode
+           /* Catch CDImode, TFmode, DCmode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 8
+           || (type
+               && VECTOR_TYPE_P (type)
+               && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
+  else
+    /* Original SPARC 64-bit ABI says that structures and unions
+       smaller than 16 bytes are passed in registers, as well as
+       all other base types.
+
+       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,
+       enforce the 2-word cap for passing arguments in registers.
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that integer
+       vectors are passed like floats of the same size, that is in
+       registers (up to 16 bytes).  Pass all vector floats like structure
+       and unions.  */
+    return ((type
+            && (AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type))
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
+           /* Catch CTImode and TCmode.  */
+           || GET_MODE_SIZE (mode) > 16);
+}
+
 /* Traverse the record TYPE recursively and call FUNC on its fields.
    NAMED is true if this is for a named parameter.  DATA is passed
    to FUNC for each field.  OFFSET is the starting position and
    PACKED is true if we are inside a packed record.  */
 
-template <typename T, void Func (const_tree, HOST_WIDE_INT, bool, T*)>
+template <typename T, void Func (const_tree, int, bool, T*)>
 static void
 traverse_record_type (const_tree type, bool named, T *data,
-                     HOST_WIDE_INT offset = 0, bool packed = false)
+                     int offset = 0, bool packed = false)
 {
   /* The ABI obviously doesn't specify how packed structures are passed.
      These are passed in integer regs if possible, otherwise memory.  */
@@ -6259,7 +6837,7 @@ traverse_record_type (const_tree type, bool named, T *data,
        if (!DECL_SIZE (field) || integer_zerop (DECL_SIZE (field)))
          continue;
 
-       HOST_WIDE_INT bitpos = offset;
+       int bitpos = offset;
        if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
          bitpos += int_bit_position (field);
 
@@ -6288,8 +6866,7 @@ typedef struct
 /* A subroutine of function_arg_slotno.  Classify the field.  */
 
 inline void
-classify_registers (const_tree, HOST_WIDE_INT bitpos, bool fp,
-                   classify_data_t *data)
+classify_registers (const_tree, int bitpos, bool fp, classify_data_t *data)
 {
   if (fp)
     {
@@ -6319,36 +6896,33 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
                     const_tree type, bool named, bool incoming,
                     int *pregno, int *ppadding)
 {
-  int regbase = (incoming
-                ? SPARC_INCOMING_INT_ARG_FIRST
-                : SPARC_OUTGOING_INT_ARG_FIRST);
-  int slotno = cum->words;
-  enum mode_class mclass;
-  int regno;
+  const int regbase
+    = incoming ? SPARC_INCOMING_INT_ARG_FIRST : SPARC_OUTGOING_INT_ARG_FIRST;
+  int slotno = cum->words, regno;
+  enum mode_class mclass = GET_MODE_CLASS (mode);
 
-  *ppadding = 0;
+  /* Silence warnings in the callers.  */
+  *pregno = -1;
+  *ppadding = -1;
 
   if (type && TREE_ADDRESSABLE (type))
     return -1;
 
-  if (TARGET_ARCH32
-      && mode == BLKmode
-      && type
-      && TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
-    return -1;
-
-  /* For SPARC64, objects requiring 16-byte alignment get it.  */
+  /* In 64-bit mode, objects requiring 16-byte alignment get it.  */
   if (TARGET_ARCH64
       && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
       && (slotno & 1) != 0)
-    slotno++, *ppadding = 1;
+    {
+      slotno++;
+      *ppadding = 1;
+    }
+  else
+    *ppadding = 0;
 
-  mclass = GET_MODE_CLASS (mode);
-  if (type && TREE_CODE (type) == VECTOR_TYPE)
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
+  if (type && VECTOR_TYPE_P (type))
     {
-      /* Vector types deserve special treatment because they are
-        polymorphic wrt their mode, depending upon whether VIS
-        instructions are enabled.  */
       if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
        {
          /* The SPARC port defines no floating-point vector modes.  */
@@ -6356,13 +6930,13 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
        }
       else
        {
-         /* Integral vector types should either have a vector
+         /* Integer vector types should either have a vector
             mode or an integral mode, because we are guaranteed
             by pass_by_reference that their size is not greater
             than 16 bytes and TImode is 16-byte wide.  */
          gcc_assert (mode != BLKmode);
 
-         /* Vector integers are handled like floats according to
+         /* Integer vectors are handled like floats as per
             the Sun VIS SDK.  */
          mclass = MODE_FLOAT;
        }
@@ -6398,24 +6972,13 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
       break;
 
     case MODE_RANDOM:
+      /* MODE is VOIDmode when generating the actual call.  */
       if (mode == VOIDmode)
-       /* MODE is VOIDmode when generating the actual call.  */
        return -1;
 
-      gcc_assert (mode == BLKmode);
-
-      if (TARGET_ARCH32
-         || !type
-         || (TREE_CODE (type) != RECORD_TYPE
-             && TREE_CODE (type) != VECTOR_TYPE))
-       {
-         /* If all arg slots are filled, then must pass on stack.  */
-         if (slotno >= SPARC_INT_ARG_MAX)
-           return -1;
-
-         regno = regbase + slotno;
-       }
-      else  /* TARGET_ARCH64 && type */
+      if (TARGET_64BIT && TARGET_FPU && named
+         && type
+         && (TREE_CODE (type) == RECORD_TYPE || VECTOR_TYPE_P (type)))
        {
          /* If all arg slots are filled, then must pass on stack.  */
          if (slotno >= SPARC_FP_ARG_MAX)
@@ -6442,10 +7005,20 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
                  if (slotno >= SPARC_INT_ARG_MAX)
                    return -1;
                }
+
+             /* PREGNO isn't set since both int and FP regs can be used.  */
+             return slotno;
            }
 
-         /* PREGNO isn't set since both int and FP regs can be used.  */
-         return slotno;
+         regno = SPARC_FP_ARG_FIRST + slotno * 2;
+       }
+      else
+       {
+         /* If all arg slots are filled, then must pass on stack.  */
+         if (slotno >= SPARC_INT_ARG_MAX)
+           return -1;
+
+         regno = regbase + slotno;
        }
       break;
 
@@ -6474,7 +7047,7 @@ typedef struct
    true if at least one integer register is assigned or false otherwise.  */
 
 static bool
-compute_int_layout (HOST_WIDE_INT bitpos, assign_data_t *data, int *pnregs)
+compute_int_layout (int bitpos, assign_data_t *data, int *pnregs)
 {
   if (data->intoffset < 0)
     return false;
@@ -6507,8 +7080,7 @@ compute_int_layout (HOST_WIDE_INT bitpos, assign_data_t *data, int *pnregs)
    FP register is assigned or false otherwise.  */
 
 static bool
-compute_fp_layout (const_tree field, HOST_WIDE_INT bitpos,
-                  assign_data_t *data,
+compute_fp_layout (const_tree field, int bitpos, assign_data_t *data,
                   int *pnregs, machine_mode *pmode)
 {
   const int this_slotno = data->slotno + bitpos / BITS_PER_WORD;
@@ -6517,7 +7089,7 @@ compute_fp_layout (const_tree field, HOST_WIDE_INT bitpos,
 
   /* Slots are counted as words while regs are counted as having the size of
      the (inner) mode.  */
-  if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE && mode == BLKmode)
+  if (VECTOR_TYPE_P (TREE_TYPE (field)) && mode == BLKmode)
     {
       mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
       nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
@@ -6553,8 +7125,7 @@ compute_fp_layout (const_tree field, HOST_WIDE_INT bitpos,
    to be assigned for FIELD and between PARMS->intoffset and BITPOS.  */
 
 inline void
-count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
-                assign_data_t *data)
+count_registers (const_tree field, int bitpos, bool fp, assign_data_t *data)
 {
   if (fp)
     {
@@ -6578,7 +7149,7 @@ count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
    structure between PARMS->intoffset and BITPOS to integer registers.  */
 
 static void
-assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
+assign_int_registers (int bitpos, assign_data_t *data)
 {
   int intoffset = data->intoffset;
   machine_mode mode;
@@ -6592,8 +7163,8 @@ assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
      the latter case we may pick up unwanted bits.  It's not a problem
      at the moment but may wish to revisit.  */
   if (intoffset % BITS_PER_WORD != 0)
-    mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
-                                  MODE_INT);
+    mode = smallest_int_mode_for_size (BITS_PER_WORD
+                                      - intoffset % BITS_PER_WORD);
   else
     mode = word_mode;
 
@@ -6618,8 +7189,7 @@ assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
    BITPOS to FP registers.  */
 
 static void
-assign_fp_registers (const_tree field, HOST_WIDE_INT bitpos,
-                            assign_data_t *data)
+assign_fp_registers (const_tree field, int bitpos, assign_data_t *data)
 {
   int nregs;
   machine_mode mode;
@@ -6649,8 +7219,7 @@ assign_fp_registers (const_tree field, HOST_WIDE_INT bitpos,
    the structure between PARMS->intoffset and BITPOS to registers.  */
 
 inline void
-assign_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
-                 assign_data_t *data)
+assign_registers (const_tree field, int bitpos, bool fp, assign_data_t *data)
 {
   if (fp)
     {
@@ -6665,7 +7234,7 @@ assign_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
     }
 }
 
-/* Used by function_arg and sparc_function_value_1 to implement the complex
+/* Used by function_arg and function_value 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 FUNCTION_ARG
    and TARGET_FUNCTION_VALUE.
@@ -6683,7 +7252,7 @@ static rtx
 function_arg_record_value (const_tree type, machine_mode mode,
                           int slotno, bool named, int regbase)
 {
-  HOST_WIDE_INT typesize = int_size_in_bytes (type);
+  const int size = int_size_in_bytes (type);
   assign_data_t data;
   int nregs;
 
@@ -6697,7 +7266,7 @@ function_arg_record_value (const_tree type, machine_mode mode,
   traverse_record_type<assign_data_t, count_registers> (type, named, &data);
 
   /* Take into account pending integer fields.  */
-  if (compute_int_layout (typesize * BITS_PER_UNIT, &data, &nregs))
+  if (compute_int_layout (size * BITS_PER_UNIT, &data, &nregs))
     data.nregs += nregs;
 
   /* Allocate the vector and handle some annoying special cases.  */
@@ -6706,7 +7275,7 @@ function_arg_record_value (const_tree type, machine_mode mode,
   if (nregs == 0)
     {
       /* ??? Empty structure has no value?  Duh?  */
-      if (typesize <= 0)
+      if (size <= 0)
        {
          /* Though there's nothing really to store, return a word register
             anyway so the rest of gcc doesn't go nuts.  Returning a PARALLEL
@@ -6717,7 +7286,7 @@ function_arg_record_value (const_tree type, machine_mode mode,
 
       /* ??? C++ has structures with no fields, and yet a size.  Give up
         for now and pass everything back in integer registers.  */
-      nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+      nregs = CEIL_NWORDS (size);
       if (nregs + slotno > SPARC_INT_ARG_MAX)
        nregs = SPARC_INT_ARG_MAX - slotno;
     }
@@ -6742,76 +7311,84 @@ function_arg_record_value (const_tree type, machine_mode mode,
   traverse_record_type<assign_data_t, assign_registers> (type, named, &data);
 
   /* Assign pending integer fields.  */
-  assign_int_registers (typesize * BITS_PER_UNIT, &data);
+  assign_int_registers (size * BITS_PER_UNIT, &data);
 
   gcc_assert (data.nregs == nregs);
 
   return data.ret;
 }
 
-/* Used by function_arg and sparc_function_value_1 to implement the conventions
+/* Used by function_arg and function_value to implement the conventions
    of the 64-bit ABI for passing and returning unions.
    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.
+   SLOTNO is the index number of the argument's slot in the parameter array.
    REGNO is the hard register the union will be passed in.  */
 
 static rtx
-function_arg_union_value (int size, machine_mode mode, int slotno,
-                         int regno)
+function_arg_union_value (int size, machine_mode mode, int slotno, int regno)
 {
-  int nwords = CEIL_NWORDS (size), i;
-  rtx regs;
+  unsigned int nwords;
 
-  /* See comment in previous function for empty structures.  */
-  if (nwords == 0)
+  /* See comment in function_arg_record_value for empty structures.  */
+  if (size <= 0)
     return gen_rtx_REG (mode, regno);
 
   if (slotno == SPARC_INT_ARG_MAX - 1)
     nwords = 1;
+  else
+    nwords = CEIL_NWORDS (size);
 
-  regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
+  rtx regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
 
-  for (i = 0; i < nwords; i++)
-    {
-      /* Unions are passed left-justified.  */
-      XVECEXP (regs, 0, i)
-       = gen_rtx_EXPR_LIST (VOIDmode,
-                            gen_rtx_REG (word_mode, regno),
-                            GEN_INT (UNITS_PER_WORD * i));
-      regno++;
-    }
+  /* Unions are passed left-justified.  */
+  for (unsigned int i = 0; i < nwords; i++)
+    XVECEXP (regs, 0, i)
+    = gen_rtx_EXPR_LIST (VOIDmode,
+                        gen_rtx_REG (word_mode, regno + i),
+                        GEN_INT (UNITS_PER_WORD * i));
 
   return regs;
 }
 
-/* Used by function_arg and sparc_function_value_1 to implement the conventions
-   for passing and returning BLKmode vectors.
+/* Used by function_arg and function_value to implement the conventions
+   of the 64-bit ABI for passing and returning BLKmode vectors.
    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.
-   REGNO is the FP hard register the vector will be passed in.  */
+   SLOTNO is the index number of the argument's slot in the parameter array.
+   NAMED is true if this argument is a named parameter
+    (otherwise it is an extra parameter matching an ellipsis).
+   REGNO is the hard register the vector will be passed in.  */
 
 static rtx
-function_arg_vector_value (int size, int regno)
+function_arg_vector_value (int size, int slotno, bool named, int regno)
 {
-  const int nregs = MAX (1, size / 8);
-  rtx regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
+  const int mult = (named ? 2 : 1);
+  unsigned int nwords;
+
+  if (slotno == (named ? SPARC_FP_ARG_MAX : SPARC_INT_ARG_MAX) - 1)
+    nwords = 1;
+  else
+    nwords = CEIL_NWORDS (size);
 
-  if (size < 8)
+  rtx regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nwords));
+
+  if (size < UNITS_PER_WORD)
     XVECEXP (regs, 0, 0)
       = gen_rtx_EXPR_LIST (VOIDmode,
                           gen_rtx_REG (SImode, regno),
                           const0_rtx);
   else
-    for (int i = 0; i < nregs; i++)
+    for (unsigned int i = 0; i < nwords; i++)
       XVECEXP (regs, 0, i)
        = gen_rtx_EXPR_LIST (VOIDmode,
-                            gen_rtx_REG (DImode, regno + 2*i),
-                            GEN_INT (i*8));
+                            gen_rtx_REG (word_mode, regno + i * mult),
+                            GEN_INT (i * UNITS_PER_WORD));
 
   return regs;
 }
@@ -6822,45 +7399,31 @@ function_arg_vector_value (int size, int regno)
 
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
-   MODE is the argument's machine mode.
-   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 true if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).
+   ARG is a description of the argument.
    INCOMING_P is false for TARGET_FUNCTION_ARG, true for
     TARGET_FUNCTION_INCOMING_ARG.  */
 
 static rtx
-sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
-                     const_tree type, bool named, bool incoming)
+sparc_function_arg_1 (cumulative_args_t cum_v, const function_arg_info &arg,
+                     bool incoming)
 {
   const CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
-
-  int regbase = (incoming
-                ? SPARC_INCOMING_INT_ARG_FIRST
-                : SPARC_OUTGOING_INT_ARG_FIRST);
+  const int regbase
+    = incoming ? SPARC_INCOMING_INT_ARG_FIRST : SPARC_OUTGOING_INT_ARG_FIRST;
   int slotno, regno, padding;
+  tree type = arg.type;
+  machine_mode mode = arg.mode;
   enum mode_class mclass = GET_MODE_CLASS (mode);
+  bool named = arg.named;
 
-  slotno = function_arg_slotno (cum, mode, type, named, incoming,
-                               &regno, &padding);
+  slotno
+    = function_arg_slotno (cum, mode, type, named, incoming, &regno, &padding);
   if (slotno == -1)
     return 0;
 
-  /* Vector types deserve special treatment because they are polymorphic wrt
-     their mode, depending upon whether VIS instructions are enabled.  */
-  if (type && TREE_CODE (type) == VECTOR_TYPE)
-    {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
-      gcc_assert ((TARGET_ARCH32 && size <= 8)
-                 || (TARGET_ARCH64 && size <= 16));
-
-      if (mode == BLKmode)
-       return function_arg_vector_value (size, SPARC_FP_ARG_FIRST + 2*slotno);
-
-      mclass = MODE_FLOAT;
-    }
+  /* Integer vectors are handled like floats as per the Sun VIS SDK.  */
+  if (type && VECTOR_INTEGER_TYPE_P (type))
+    mclass = MODE_FLOAT;
 
   if (TARGET_ARCH32)
     return gen_rtx_REG (mode, regno);
@@ -6869,7 +7432,7 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
      and are promoted to registers if possible.  */
   if (type && TREE_CODE (type) == RECORD_TYPE)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
+      const int size = int_size_in_bytes (type);
       gcc_assert (size <= 16);
 
       return function_arg_record_value (type, mode, slotno, named, regbase);
@@ -6878,12 +7441,21 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
   /* Unions up to 16 bytes in size are passed in integer registers.  */
   else if (type && TREE_CODE (type) == UNION_TYPE)
     {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
+      const int size = int_size_in_bytes (type);
       gcc_assert (size <= 16);
 
       return function_arg_union_value (size, mode, slotno, regno);
     }
 
+   /* Floating-point vectors up to 16 bytes are passed in registers.  */
+  else if (type && VECTOR_TYPE_P (type) && mode == BLKmode)
+    {
+      const int size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
+
+      return function_arg_vector_value (size, slotno, named, regno);
+    }
+
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
@@ -6929,10 +7501,10 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
      corresponding to the size of the type.  */
   else if (type && AGGREGATE_TYPE_P (type))
     {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
+      const int size = int_size_in_bytes (type);
       gcc_assert (size <= 16);
 
-      mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+      mode = int_mode_for_size (size * BITS_PER_UNIT, 0).else_blk ();
     }
 
   return gen_rtx_REG (mode, regno);
@@ -6941,19 +7513,18 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
 /* Handle the TARGET_FUNCTION_ARG target hook.  */
 
 static rtx
-sparc_function_arg (cumulative_args_t cum, machine_mode mode,
-                   const_tree type, bool named)
+sparc_function_arg (cumulative_args_t cum, const function_arg_info &arg)
 {
-  return sparc_function_arg_1 (cum, mode, type, named, false);
+  return sparc_function_arg_1 (cum, arg, false);
 }
 
 /* Handle the TARGET_FUNCTION_INCOMING_ARG target hook.  */
 
 static rtx
-sparc_function_incoming_arg (cumulative_args_t cum, machine_mode mode,
-                            const_tree type, bool named)
+sparc_function_incoming_arg (cumulative_args_t cum,
+                            const function_arg_info &arg)
 {
-  return sparc_function_arg_1 (cum, mode, type, named, true);
+  return sparc_function_arg_1 (cum, arg, true);
 }
 
 /* For sparc64, objects requiring 16 byte alignment are passed that way.  */
@@ -6979,166 +7550,117 @@ sparc_function_arg_boundary (machine_mode mode, const_tree type)
    mode] will be split between that reg and memory.  */
 
 static int
-sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
-                        tree type, bool named)
+sparc_arg_partial_bytes (cumulative_args_t cum, const function_arg_info &arg)
 {
   int slotno, regno, padding;
 
   /* We pass false for incoming here, it doesn't matter.  */
-  slotno = function_arg_slotno (get_cumulative_args (cum), mode, type, named,
-                               false, &regno, &padding);
+  slotno = function_arg_slotno (get_cumulative_args (cum), arg.mode, arg.type,
+                               arg.named, false, &regno, &padding);
 
   if (slotno == -1)
     return 0;
 
   if (TARGET_ARCH32)
     {
-      if ((slotno + (mode == BLKmode
-                    ? CEIL_NWORDS (int_size_in_bytes (type))
-                    : CEIL_NWORDS (GET_MODE_SIZE (mode))))
-         > SPARC_INT_ARG_MAX)
-       return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
+      /* We are guaranteed by pass_by_reference that the size of the
+        argument is not greater than 8 bytes, so we only need to return
+        one word if the argument is partially passed in registers.  */
+      const int size = GET_MODE_SIZE (arg.mode);
+
+      if (size > UNITS_PER_WORD && slotno == SPARC_INT_ARG_MAX - 1)
+       return UNITS_PER_WORD;
     }
   else
     {
       /* We are guaranteed by pass_by_reference that the size of the
         argument is not greater than 16 bytes, so we only need to return
         one word if the argument is partially passed in registers.  */
-
-      if (type && AGGREGATE_TYPE_P (type))
+      if (arg.aggregate_type_p ())
        {
-         int size = int_size_in_bytes (type);
+         const int size = int_size_in_bytes (arg.type);
 
          if (size > UNITS_PER_WORD
              && (slotno == SPARC_INT_ARG_MAX - 1
                  || slotno == SPARC_FP_ARG_MAX - 1))
            return UNITS_PER_WORD;
        }
-      else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
-              || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-                  && ! (TARGET_FPU && named)))
+      else if (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_INT
+              || ((GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
+                   || (arg.type && VECTOR_TYPE_P (arg.type)))
+                  && !(TARGET_FPU && arg.named)))
        {
-         /* The complex types are passed as packed types.  */
-         if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
-             && slotno == SPARC_INT_ARG_MAX - 1)
+         const int size = (arg.type && VECTOR_FLOAT_TYPE_P (arg.type))
+                          ? int_size_in_bytes (arg.type)
+                          : GET_MODE_SIZE (arg.mode);
+
+         if (size > UNITS_PER_WORD && slotno == SPARC_INT_ARG_MAX - 1)
            return UNITS_PER_WORD;
        }
-      else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+      else if (GET_MODE_CLASS (arg.mode) == MODE_COMPLEX_FLOAT
+              || (arg.type && VECTOR_TYPE_P (arg.type)))
        {
-         if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
-             > SPARC_FP_ARG_MAX)
+         const int size = (arg.type && VECTOR_FLOAT_TYPE_P (arg.type))
+                          ? int_size_in_bytes (arg.type)
+                          : GET_MODE_SIZE (arg.mode);
+
+         if (size > UNITS_PER_WORD && slotno == SPARC_FP_ARG_MAX - 1)
            return UNITS_PER_WORD;
        }
     }
-
-  return 0;
-}
-
-/* Handle the TARGET_PASS_BY_REFERENCE target hook.
-   Specify whether to pass the argument by reference.  */
-
-static bool
-sparc_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
-                        machine_mode mode, const_tree type,
-                        bool named ATTRIBUTE_UNUSED)
-{
-  if (TARGET_ARCH32)
-    /* Original SPARC 32-bit ABI says that structures and unions,
-       and quad-precision floats are passed by reference.  For Pascal,
-       also pass arrays by reference.  All other base types are passed
-       in registers.
-
-       Extended ABI (as implemented by the Sun compiler) says that all
-       complex floats are passed by reference.  Pass complex integers
-       in registers up to 8 bytes.  More generally, enforce the 2-word
-       cap for passing arguments in registers.
-
-       Vector ABI (as implemented by the Sun VIS SDK) says that vector
-       integers are passed like floats of the same size, that is in
-       registers up to 8 bytes.  Pass all vector floats by reference
-       like structure and unions.  */
-    return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
-           || mode == SCmode
-           /* Catch CDImode, TFmode, DCmode and TCmode.  */
-           || GET_MODE_SIZE (mode) > 8
-           || (type
-               && TREE_CODE (type) == VECTOR_TYPE
-               && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
-  else
-    /* Original SPARC 64-bit ABI says that structures and unions
-       smaller than 16 bytes are passed in registers, as well as
-       all other base types.
-
-       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,
-       enforce the 2-word cap for passing arguments in registers.
-
-       Vector ABI (as implemented by the Sun VIS SDK) says that vector
-       integers are passed like floats of the same size, that is in
-       registers (up to 16 bytes).  Pass all vector floats like structure
-       and unions.  */
-    return ((type
-            && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
-            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
-           /* Catch CTImode and TCmode.  */
-           || GET_MODE_SIZE (mode) > 16);
+
+  return 0;
 }
 
 /* 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.  */
+   Update the data in CUM to advance over argument ARG.  */
 
 static void
-sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
-                           const_tree type, bool named)
+sparc_function_arg_advance (cumulative_args_t cum_v,
+                           const function_arg_info &arg)
 {
   CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+  tree type = arg.type;
+  machine_mode mode = arg.mode;
   int regno, padding;
 
   /* We pass false for incoming here, it doesn't matter.  */
-  function_arg_slotno (cum, mode, type, named, false, &regno, &padding);
+  function_arg_slotno (cum, mode, type, arg.named, false, &regno, &padding);
 
   /* If argument requires leading padding, add it.  */
   cum->words += padding;
 
   if (TARGET_ARCH32)
-    cum->words += (mode == BLKmode
-                  ? CEIL_NWORDS (int_size_in_bytes (type))
-                  : CEIL_NWORDS (GET_MODE_SIZE (mode)));
+    cum->words += CEIL_NWORDS (GET_MODE_SIZE (mode));
   else
     {
-      if (type && AGGREGATE_TYPE_P (type))
+      /* For types that can have BLKmode, get the size from the type.  */
+      if (type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
        {
-         int size = int_size_in_bytes (type);
+         const int size = int_size_in_bytes (type);
 
-         if (size <= 8)
-           ++cum->words;
-         else if (size <= 16)
-           cum->words += 2;
-         else /* passed by reference */
-           ++cum->words;
+         /* See comment in function_arg_record_value for empty structures.  */
+         if (size <= 0)
+           cum->words++;
+         else
+           cum->words += CEIL_NWORDS (size);
        }
       else
-       cum->words += (mode == BLKmode
-                      ? CEIL_NWORDS (int_size_in_bytes (type))
-                      : CEIL_NWORDS (GET_MODE_SIZE (mode)));
+       cum->words += CEIL_NWORDS (GET_MODE_SIZE (mode));
     }
 }
 
-/* Handle the FUNCTION_ARG_PADDING macro.
-   For the 64 bit ABI structs are always stored left shifted in their
-   argument slot.  */
+/* Implement TARGET_FUNCTION_ARG_PADDING.  For the 64-bit ABI structs
+   are always stored left shifted in their argument slot.  */
 
-enum direction
-function_arg_padding (machine_mode mode, const_tree type)
+static pad_direction
+sparc_function_arg_padding (machine_mode mode, const_tree type)
 {
   if (TARGET_ARCH64 && type && AGGREGATE_TYPE_P (type))
-    return upward;
+    return PAD_UPWARD;
 
   /* Fall back to the default.  */
-  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
+  return default_function_arg_padding (mode, type);
 }
 
 /* Handle the TARGET_RETURN_IN_MEMORY target hook.
@@ -7148,9 +7670,11 @@ static bool
 sparc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
-    /* Original SPARC 32-bit ABI says that structures and unions,
-       and quad-precision floats are returned in memory.  All other
-       base types are returned in registers.
+    /* Original SPARC 32-bit ABI says that structures and unions, and
+       quad-precision floats are returned in memory.  But note that the
+       first part is implemented through -fpcc-struct-return being the
+       default, so here we only implement -freg-struct-return instead.
+       All other base types are returned in registers.
 
        Extended ABI (as implemented by the Sun compiler) says that
        all complex floats are returned in registers (8 FP registers
@@ -7191,7 +7715,7 @@ static rtx
 sparc_struct_value_rtx (tree fndecl, int incoming)
 {
   if (TARGET_ARCH64)
-    return 0;
+    return NULL_RTX;
   else
     {
       rtx mem;
@@ -7252,50 +7776,49 @@ sparc_struct_value_rtx (tree fndecl, int incoming)
    except that up to 32 bytes may be returned in registers.  */
 
 static rtx
-sparc_function_value_1 (const_tree type, machine_mode mode,
-                       bool outgoing)
+sparc_function_value_1 (const_tree type, machine_mode mode, bool outgoing)
 {
   /* Beware that the two values are swapped here wrt function_arg.  */
-  int regbase = (outgoing
-                ? SPARC_INCOMING_INT_ARG_FIRST
-                : SPARC_OUTGOING_INT_ARG_FIRST);
+  const int regbase
+    = outgoing ? SPARC_INCOMING_INT_ARG_FIRST : SPARC_OUTGOING_INT_ARG_FIRST;
   enum mode_class mclass = GET_MODE_CLASS (mode);
   int regno;
 
-  /* Vector types deserve special treatment because they are polymorphic wrt
-     their mode, depending upon whether VIS instructions are enabled.  */
-  if (type && TREE_CODE (type) == VECTOR_TYPE)
-    {
-      HOST_WIDE_INT size = int_size_in_bytes (type);
-      gcc_assert ((TARGET_ARCH32 && size <= 8)
-                 || (TARGET_ARCH64 && size <= 32));
-
-      if (mode == BLKmode)
-       return function_arg_vector_value (size, SPARC_FP_ARG_FIRST);
-
-      mclass = MODE_FLOAT;
-    }
+  /* Integer vectors are handled like floats as per the Sun VIS SDK.
+     Note that integer vectors larger than 16 bytes have BLKmode so
+     they need to be handled like floating-point vectors below.  */
+  if (type && VECTOR_INTEGER_TYPE_P (type) && mode != BLKmode)
+    mclass = MODE_FLOAT;
 
   if (TARGET_ARCH64 && type)
     {
       /* Structures up to 32 bytes in size are returned in registers.  */
       if (TREE_CODE (type) == RECORD_TYPE)
        {
-         HOST_WIDE_INT size = int_size_in_bytes (type);
+         const int size = int_size_in_bytes (type);
          gcc_assert (size <= 32);
 
-         return function_arg_record_value (type, mode, 0, 1, regbase);
+         return function_arg_record_value (type, mode, 0, true, regbase);
        }
 
       /* Unions up to 32 bytes in size are returned in integer registers.  */
       else if (TREE_CODE (type) == UNION_TYPE)
        {
-         HOST_WIDE_INT size = int_size_in_bytes (type);
+         const int size = int_size_in_bytes (type);
          gcc_assert (size <= 32);
 
          return function_arg_union_value (size, mode, 0, regbase);
        }
 
+      /* Vectors up to 32 bytes are returned in FP registers.  */
+      else if (VECTOR_TYPE_P (type) && mode == BLKmode)
+       {
+         const int size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
+
+         return function_arg_vector_value (size, 0, true, SPARC_FP_ARG_FIRST);
+       }
+
       /* Objects that require it are returned in FP registers.  */
       else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
        ;
@@ -7306,10 +7829,10 @@ sparc_function_value_1 (const_tree type, machine_mode mode,
        {
          /* All other aggregate types are passed in an integer register
             in a mode corresponding to the size of the type.  */
-         HOST_WIDE_INT size = int_size_in_bytes (type);
+         const int size = int_size_in_bytes (type);
          gcc_assert (size <= 32);
 
-         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
+         mode = int_mode_for_size (size * BITS_PER_UNIT, 0).else_blk ();
 
          /* ??? We probably should have made the same ABI change in
             3.4.0 as the one we made for unions.   The latter was
@@ -7428,7 +7951,7 @@ sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
   bool indirect;
   tree ptrtype = build_pointer_type (type);
 
-  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
+  if (pass_va_arg_by_reference (type))
     {
       indirect = true;
       size = rsize = UNITS_PER_WORD;
@@ -7515,16 +8038,16 @@ sparc_vector_mode_supported_p (machine_mode mode)
 /* Implement the TARGET_VECTORIZE_PREFERRED_SIMD_MODE target hook.  */
 
 static machine_mode
-sparc_preferred_simd_mode (machine_mode mode)
+sparc_preferred_simd_mode (scalar_mode mode)
 {
   if (TARGET_VIS)
     switch (mode)
       {
-      case SImode:
+      case E_SImode:
        return V2SImode;
-      case HImode:
+      case E_HImode:
        return V4HImode;
-      case QImode:
+      case E_QImode:
        return V8QImode;
 
       default:;
@@ -7533,6 +8056,19 @@ sparc_preferred_simd_mode (machine_mode mode)
   return word_mode;
 }
 \f
+\f/* Implement TARGET_CAN_FOLLOW_JUMP.  */
+
+static bool
+sparc_can_follow_jump (const rtx_insn *follower, const rtx_insn *followee)
+{
+  /* Do not fold unconditional jumps that have been created for crossing
+     partition boundaries.  */
+  if (CROSSING_JUMP_P (followee) && !CROSSING_JUMP_P (follower))
+    return false;
+
+  return true;
+}
+
 /* Return the string to output an unconditional branch to LABEL, which is
    the operand number of the label.
 
@@ -7548,9 +8084,8 @@ output_ubranch (rtx dest, rtx_insn *insn)
 
   /* Even if we are trying to use cbcond for this, evaluate
      whether we can use V9 branches as our backup plan.  */
-
   delta = 5000000;
-  if (INSN_ADDRESSES_SET_P ())
+  if (!CROSSING_JUMP_P (insn) && INSN_ADDRESSES_SET_P ())
     delta = (INSN_ADDRESSES (INSN_UID (dest))
             - INSN_ADDRESSES (INSN_UID (insn)));
 
@@ -7721,10 +8256,16 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       switch (code)
        {
        case NE:
-         branch = "bne";
+         if (mode == CCVmode || mode == CCXVmode)
+           branch = "bvs";
+         else
+           branch = "bne";
          break;
        case EQ:
-         branch = "be";
+         if (mode == CCVmode || mode == CCXVmode)
+           branch = "bvc";
+         else
+           branch = "be";
          break;
        case GE:
          if (mode == CCNZmode || mode == CCXNZmode)
@@ -7788,21 +8329,23 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
 
       switch (mode)
        {
-       case CCmode:
-       case CCNZmode:
-       case CCCmode:
+       case E_CCmode:
+       case E_CCNZmode:
+       case E_CCCmode:
+       case E_CCVmode:
          labelno = "%%icc, ";
          if (v8)
            labelno = "";
          break;
-       case CCXmode:
-       case CCXNZmode:
-       case CCXCmode:
+       case E_CCXmode:
+       case E_CCXNZmode:
+       case E_CCXCmode:
+       case E_CCXVmode:
          labelno = "%%xcc, ";
          gcc_assert (!v8);
          break;
-       case CCFPmode:
-       case CCFPEmode:
+       case E_CCFPmode:
+       case E_CCFPEmode:
          {
            static char v9_fcc_labelno[] = "%%fccX, ";
            /* Set the char indicating the number of the fcc reg to use.  */
@@ -7822,7 +8365,8 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
       if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
        {
          strcpy (p,
-                 ((XINT (note, 0) >= REG_BR_PROB_BASE / 2) ^ far)
+                 ((profile_probability::from_reg_br_prob_note (XINT (note, 0))
+                  >= profile_probability::even ()) ^ far)
                  ? ",pt" : ",pn");
          p += 3;
          spaces -= 3;
@@ -7943,7 +8487,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
 
       libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
       emit_library_call (libfunc, LCT_NORMAL,
-                        DImode, 2,
+                        DImode,
                         XEXP (slot0, 0), Pmode,
                         XEXP (slot1, 0), Pmode);
       mode = DImode;
@@ -7952,7 +8496,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
     {
       libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
       emit_library_call (libfunc, LCT_NORMAL,
-                        SImode, 2,
+                        SImode,
                         x, TFmode, y, TFmode);
       mode = SImode;
     }
@@ -8238,7 +8782,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
   if (reversed ^ far)
     code = reverse_condition (code);
 
-  /* Only 64 bit versions of these instructions exist.  */
+  /* Only 64-bit versions of these instructions exist.  */
   gcc_assert (mode == DImode);
 
   /* Start by writing the branch condition.  */
@@ -8285,7 +8829,8 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
   if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
     {
       strcpy (p,
-             ((XINT (note, 0) >= REG_BR_PROB_BASE / 2) ^ far)
+             ((profile_probability::from_reg_br_prob_note (XINT (note, 0))
+              >= profile_probability::even ()) ^ far)
              ? ",pt" : ",pn");
       p += 3;
     }
@@ -8442,46 +8987,82 @@ order_regs_for_local_alloc (void)
 }
 \f
 /* Return 1 if REG and MEM are legitimate enough to allow the various
-   mem<-->reg splits to be run.  */
+   MEM<-->REG splits to be run.  */
 
 int
-sparc_splitdi_legitimate (rtx reg, rtx mem)
+sparc_split_reg_mem_legitimate (rtx reg, rtx mem)
 {
   /* Punt if we are here by mistake.  */
   gcc_assert (reload_completed);
 
   /* We must have an offsettable memory reference.  */
-  if (! offsettable_memref_p (mem))
+  if (!offsettable_memref_p (mem))
     return 0;
 
   /* If we have legitimate args for ldd/std, we do not want
      the split to happen.  */
-  if ((REGNO (reg) % 2) == 0
-      && mem_min_alignment (mem, 8))
+  if ((REGNO (reg) % 2) == 0 && mem_min_alignment (mem, 8))
     return 0;
 
   /* Success.  */
   return 1;
 }
 
-/* Like sparc_splitdi_legitimate but for REG <--> REG moves.  */
+/* Split a REG <-- MEM move into a pair of moves in MODE.  */
+
+void
+sparc_split_reg_mem (rtx dest, rtx src, machine_mode mode)
+{
+  rtx high_part = gen_highpart (mode, dest);
+  rtx low_part = gen_lowpart (mode, dest);
+  rtx word0 = adjust_address (src, mode, 0);
+  rtx word1 = adjust_address (src, mode, 4);
+
+  if (reg_overlap_mentioned_p (high_part, word1))
+    {
+      emit_move_insn_1 (low_part, word1);
+      emit_move_insn_1 (high_part, word0);
+    }
+  else
+    {
+      emit_move_insn_1 (high_part, word0);
+      emit_move_insn_1 (low_part, word1);
+    }
+}
+
+/* Split a MEM <-- REG move into a pair of moves in MODE.  */
+
+void
+sparc_split_mem_reg (rtx dest, rtx src, machine_mode mode)
+{
+  rtx word0 = adjust_address (dest, mode, 0);
+  rtx word1 = adjust_address (dest, mode, 4);
+  rtx high_part = gen_highpart (mode, src);
+  rtx low_part = gen_lowpart (mode, src);
+
+  emit_move_insn_1 (word0, high_part);
+  emit_move_insn_1 (word1, low_part);
+}
+
+/* Like sparc_split_reg_mem_legitimate but for REG <--> REG moves.  */
 
 int
-sparc_split_regreg_legitimate (rtx reg1, rtx reg2)
+sparc_split_reg_reg_legitimate (rtx reg1, rtx reg2)
 {
-  int regno1, regno2;
+  /* Punt if we are here by mistake.  */
+  gcc_assert (reload_completed);
 
   if (GET_CODE (reg1) == SUBREG)
     reg1 = SUBREG_REG (reg1);
   if (GET_CODE (reg1) != REG)
     return 0;
-  regno1 = REGNO (reg1);
+  const int regno1 = REGNO (reg1);
 
   if (GET_CODE (reg2) == SUBREG)
     reg2 = SUBREG_REG (reg2);
   if (GET_CODE (reg2) != REG)
     return 0;
-  regno2 = REGNO (reg2);
+  const int regno2 = REGNO (reg2);
 
   if (SPARC_INT_REG_P (regno1) && SPARC_INT_REG_P (regno2))
     return 1;
@@ -8496,6 +9077,30 @@ sparc_split_regreg_legitimate (rtx reg1, rtx reg2)
   return 0;
 }
 
+/* Split a REG <--> REG move into a pair of moves in MODE.  */
+
+void
+sparc_split_reg_reg (rtx dest, rtx src, machine_mode mode)
+{
+  rtx dest1 = gen_highpart (mode, dest);
+  rtx dest2 = gen_lowpart (mode, dest);
+  rtx src1 = gen_highpart (mode, src);
+  rtx src2 = gen_lowpart (mode, src);
+
+  /* Now emit using the real source and destination we found, swapping
+     the order if we detect overlap.  */
+  if (reg_overlap_mentioned_p (dest1, src2))
+    {
+      emit_move_insn_1 (dest2, src2);
+      emit_move_insn_1 (dest1, src1);
+    }
+  else
+    {
+      emit_move_insn_1 (dest1, src1);
+      emit_move_insn_1 (dest2, src2);
+    }
+}
+
 /* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
    This makes them candidates for using ldd and std insns.
 
@@ -8606,7 +9211,7 @@ mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
     return 0;
 
   /* The first offset must be evenly divisible by 8 to ensure the
-     address is 64 bit aligned.  */
+     address is 64-bit aligned.  */
   if (offset1 % 8 != 0)
     return 0;
 
@@ -8798,14 +9403,16 @@ sparc_print_operand (FILE *file, rtx x, int code)
        {
          switch (GET_MODE (x))
            {
-           case CCmode:
-           case CCNZmode:
-           case CCCmode:
+           case E_CCmode:
+           case E_CCNZmode:
+           case E_CCCmode:
+           case E_CCVmode:
              s = "%icc";
              break;
-           case CCXmode:
-           case CCXNZmode:
-           case CCXCmode:
+           case E_CCXmode:
+           case E_CCXNZmode:
+           case E_CCXCmode:
+           case E_CCXVmode:
              s = "%xcc";
              break;
            default:
@@ -8880,10 +9487,16 @@ sparc_print_operand (FILE *file, rtx x, int code)
        switch (GET_CODE (x))
          {
          case NE:
-           s = "ne";
+           if (mode == CCVmode || mode == CCXVmode)
+             s = "vs";
+           else
+             s = "ne";
            break;
          case EQ:
-           s = "e";
+           if (mode == CCVmode || mode == CCXVmode)
+             s = "vc";
+           else
+             s = "e";
            break;
          case GE:
            if (mode == CCNZmode || mode == CCXNZmode)
@@ -9367,14 +9980,15 @@ sparc32_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
       && sparc_cpu != PROCESSOR_NIAGARA2
       && sparc_cpu != PROCESSOR_NIAGARA3
       && sparc_cpu != PROCESSOR_NIAGARA4
-      && sparc_cpu != PROCESSOR_NIAGARA7)
+      && sparc_cpu != PROCESSOR_NIAGARA7
+      && sparc_cpu != PROCESSOR_M8)
     emit_insn (gen_flushsi (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 HAVE_ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
+                     LCT_NORMAL, VOIDmode, XEXP (m_tramp, 0), Pmode);
 #endif
 
 }
@@ -9413,14 +10027,15 @@ sparc64_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
       && sparc_cpu != PROCESSOR_NIAGARA2
       && sparc_cpu != PROCESSOR_NIAGARA3
       && sparc_cpu != PROCESSOR_NIAGARA4
-      && sparc_cpu != PROCESSOR_NIAGARA7)
+      && sparc_cpu != PROCESSOR_NIAGARA7
+      && sparc_cpu != PROCESSOR_M8)
     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 HAVE_ENABLE_EXECUTE_STACK
   emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
+                     LCT_NORMAL, VOIDmode, XEXP (m_tramp, 0), Pmode);
 #endif
 }
 
@@ -9608,21 +10223,25 @@ sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
 static int
 sparc_use_sched_lookahead (void)
 {
-  if (sparc_cpu == PROCESSOR_NIAGARA
-      || sparc_cpu == PROCESSOR_NIAGARA2
-      || sparc_cpu == PROCESSOR_NIAGARA3)
-    return 0;
-  if (sparc_cpu == PROCESSOR_NIAGARA4
-      || sparc_cpu == PROCESSOR_NIAGARA7)
-    return 2;
-  if (sparc_cpu == PROCESSOR_ULTRASPARC
-      || sparc_cpu == PROCESSOR_ULTRASPARC3)
-    return 4;
-  if ((1 << sparc_cpu) &
-      ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
-       (1 << PROCESSOR_SPARCLITE86X)))
-    return 3;
-  return 0;
+  switch (sparc_cpu)
+    {
+    case PROCESSOR_ULTRASPARC:
+    case PROCESSOR_ULTRASPARC3:
+      return 4;
+    case PROCESSOR_SUPERSPARC:
+    case PROCESSOR_HYPERSPARC:
+    case PROCESSOR_SPARCLITE86X:
+      return 3;
+    case PROCESSOR_NIAGARA4:
+    case PROCESSOR_NIAGARA7:
+    case PROCESSOR_M8:
+      return 2;
+    case PROCESSOR_NIAGARA:
+    case PROCESSOR_NIAGARA2:
+    case PROCESSOR_NIAGARA3:
+    default:
+      return 0;
+    }
 }
 
 static int
@@ -9630,27 +10249,60 @@ sparc_issue_rate (void)
 {
   switch (sparc_cpu)
     {
+    case PROCESSOR_ULTRASPARC:
+    case PROCESSOR_ULTRASPARC3:
+    case PROCESSOR_M8:
+      return 4;
+    case PROCESSOR_SUPERSPARC:
+      return 3;
+    case PROCESSOR_HYPERSPARC:
+    case PROCESSOR_SPARCLITE86X:
+    case PROCESSOR_V9:
+      /* Assume V9 processors are capable of at least dual-issue.  */
+    case PROCESSOR_NIAGARA4:
+    case PROCESSOR_NIAGARA7:
+      return 2;
     case PROCESSOR_NIAGARA:
     case PROCESSOR_NIAGARA2:
     case PROCESSOR_NIAGARA3:
     default:
       return 1;
-    case PROCESSOR_NIAGARA4:
-    case PROCESSOR_NIAGARA7:
+    }
+}
+
+int
+sparc_branch_cost (bool speed_p, bool predictable_p)
+{
+  if (!speed_p)
+    return 2;
+
+  /* For pre-V9 processors we use a single value (usually 3) to take into
+     account the potential annulling of the delay slot (which ends up being
+     a bubble in the pipeline slot) plus a cycle to take into consideration
+     the instruction cache effects.
+
+     On V9 and later processors, which have branch prediction facilities,
+     we take into account whether the branch is (easily) predictable.  */
+  const int cost = sparc_costs->branch_cost;
+
+  switch (sparc_cpu)
+    {
     case PROCESSOR_V9:
-      /* Assume V9 processors are capable of at least dual-issue.  */
-      return 2;
-    case PROCESSOR_SUPERSPARC:
-      return 3;
-    case PROCESSOR_HYPERSPARC:
-    case PROCESSOR_SPARCLITE86X:
-      return 2;
     case PROCESSOR_ULTRASPARC:
     case PROCESSOR_ULTRASPARC3:
-      return 4;
+    case PROCESSOR_NIAGARA:
+    case PROCESSOR_NIAGARA2:
+    case PROCESSOR_NIAGARA3:
+    case PROCESSOR_NIAGARA4:
+    case PROCESSOR_NIAGARA7:
+    case PROCESSOR_M8:
+      return cost + (predictable_p ? 0 : 2);
+
+    default:
+      return cost;
     }
 }
-
+      
 static int
 set_extends (rtx_insn *insn)
 {
@@ -9922,13 +10574,13 @@ sparc_profile_hook (int labelno)
   fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
   if (NO_PROFILE_COUNTERS)
     {
-      emit_library_call (fun, LCT_NORMAL, VOIDmode, 0);
+      emit_library_call (fun, LCT_NORMAL, VOIDmode);
     }
   else
     {
       ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
       lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
-      emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
+      emit_library_call (fun, LCT_NORMAL, VOIDmode, lab, Pmode);
     }
 }
 \f
@@ -9949,6 +10601,10 @@ sparc_solaris_elf_asm_named_section (const char *name, unsigned int flags,
 
   if (!(flags & SECTION_DEBUG))
     fputs (",#alloc", asm_out_file);
+#if HAVE_GAS_SECTION_EXCLUDE
+  if (flags & SECTION_EXCLUDE)
+    fputs (",#exclude", asm_out_file);
+#endif
   if (flags & SECTION_WRITE)
     fputs (",#write", asm_out_file);
   if (flags & SECTION_TLS)
@@ -10229,6 +10885,45 @@ enum sparc_builtins
   SPARC_BUILTIN_FPSUBS8,
   SPARC_BUILTIN_FPSUBUS8,
   SPARC_BUILTIN_FPSUBUS16,
+
+  /* VIS 4.0B builtins.  */
+
+  /* Note that all the DICTUNPACK* entries should be kept
+     contiguous.  */
+  SPARC_BUILTIN_FIRST_DICTUNPACK,
+  SPARC_BUILTIN_DICTUNPACK8 = SPARC_BUILTIN_FIRST_DICTUNPACK,
+  SPARC_BUILTIN_DICTUNPACK16,
+  SPARC_BUILTIN_DICTUNPACK32,
+  SPARC_BUILTIN_LAST_DICTUNPACK = SPARC_BUILTIN_DICTUNPACK32,
+
+  /* Note that all the FPCMP*SHL entries should be kept
+     contiguous.  */
+  SPARC_BUILTIN_FIRST_FPCMPSHL,
+  SPARC_BUILTIN_FPCMPLE8SHL = SPARC_BUILTIN_FIRST_FPCMPSHL,
+  SPARC_BUILTIN_FPCMPGT8SHL,
+  SPARC_BUILTIN_FPCMPEQ8SHL,
+  SPARC_BUILTIN_FPCMPNE8SHL,
+  SPARC_BUILTIN_FPCMPLE16SHL,
+  SPARC_BUILTIN_FPCMPGT16SHL,
+  SPARC_BUILTIN_FPCMPEQ16SHL,
+  SPARC_BUILTIN_FPCMPNE16SHL,
+  SPARC_BUILTIN_FPCMPLE32SHL,
+  SPARC_BUILTIN_FPCMPGT32SHL,
+  SPARC_BUILTIN_FPCMPEQ32SHL,
+  SPARC_BUILTIN_FPCMPNE32SHL,
+  SPARC_BUILTIN_FPCMPULE8SHL,
+  SPARC_BUILTIN_FPCMPUGT8SHL,
+  SPARC_BUILTIN_FPCMPULE16SHL,
+  SPARC_BUILTIN_FPCMPUGT16SHL,
+  SPARC_BUILTIN_FPCMPULE32SHL,
+  SPARC_BUILTIN_FPCMPUGT32SHL,
+  SPARC_BUILTIN_FPCMPDE8SHL,
+  SPARC_BUILTIN_FPCMPDE16SHL,
+  SPARC_BUILTIN_FPCMPDE32SHL,
+  SPARC_BUILTIN_FPCMPUR8SHL,
+  SPARC_BUILTIN_FPCMPUR16SHL,
+  SPARC_BUILTIN_FPCMPUR32SHL,
+  SPARC_BUILTIN_LAST_FPCMPSHL = SPARC_BUILTIN_FPCMPUR32SHL,
   
   SPARC_BUILTIN_MAX
 };
@@ -10236,6 +10931,27 @@ enum sparc_builtins
 static GTY (()) tree sparc_builtins[(int) SPARC_BUILTIN_MAX];
 static enum insn_code sparc_builtins_icode[(int) SPARC_BUILTIN_MAX];
 
+/* Return true if OPVAL can be used for operand OPNUM of instruction ICODE.
+   The instruction should require a constant operand of some sort.  The
+   function prints an error if OPVAL is not valid.  */
+
+static int
+check_constant_argument (enum insn_code icode, int opnum, rtx opval)
+{
+  if (GET_CODE (opval) != CONST_INT)
+    {
+      error ("%qs expects a constant argument", insn_data[icode].name);
+      return false;
+    }
+
+  if (!(*insn_data[icode].operand[opnum].predicate) (opval, VOIDmode))
+    {
+      error ("constant argument out of range for %qs", insn_data[icode].name);
+      return false;
+    }
+  return true;
+}
+
 /* Add a SPARC builtin function with NAME, ICODE, CODE and TYPE.  Return the
    function decl or NULL_TREE if the builtin was not added.  */
 
@@ -10329,6 +11045,12 @@ sparc_vis_init_builtins (void)
                                                      v8qi, v8qi, 0);
   tree si_ftype_v8qi_v8qi = build_function_type_list (intSI_type_node,
                                                      v8qi, v8qi, 0);
+  tree v8qi_ftype_df_si = build_function_type_list (v8qi, double_type_node,
+                                                   intSI_type_node, 0);
+  tree v4hi_ftype_df_si = build_function_type_list (v4hi, double_type_node,
+                                                   intSI_type_node, 0);
+  tree v2si_ftype_df_si = build_function_type_list (v2si, double_type_node,
+                                                   intDI_type_node, 0);
   tree di_ftype_di_di = build_function_type_list (intDI_type_node,
                                                  intDI_type_node,
                                                  intDI_type_node, 0);
@@ -10783,6 +11505,156 @@ sparc_vis_init_builtins (void)
       def_builtin_const ("__builtin_vis_fpsubus16", CODE_FOR_ussubv4hi3,
                         SPARC_BUILTIN_FPSUBUS16, v4hi_ftype_v4hi_v4hi);
     }
+
+  if (TARGET_VIS4B)
+    {
+      def_builtin_const ("__builtin_vis_dictunpack8", CODE_FOR_dictunpack8,
+                        SPARC_BUILTIN_DICTUNPACK8, v8qi_ftype_df_si);
+      def_builtin_const ("__builtin_vis_dictunpack16", CODE_FOR_dictunpack16,
+                        SPARC_BUILTIN_DICTUNPACK16, v4hi_ftype_df_si);
+      def_builtin_const ("__builtin_vis_dictunpack32", CODE_FOR_dictunpack32,
+                        SPARC_BUILTIN_DICTUNPACK32, v2si_ftype_df_si);
+
+      if (TARGET_ARCH64)
+       {
+         tree di_ftype_v8qi_v8qi_si = build_function_type_list (intDI_type_node,
+                                                                v8qi, v8qi,
+                                                                intSI_type_node, 0);
+         tree di_ftype_v4hi_v4hi_si = build_function_type_list (intDI_type_node,
+                                                                v4hi, v4hi,
+                                                                intSI_type_node, 0);
+         tree di_ftype_v2si_v2si_si = build_function_type_list (intDI_type_node,
+                                                                v2si, v2si,
+                                                                intSI_type_node, 0);
+         
+         def_builtin_const ("__builtin_vis_fpcmple8shl", CODE_FOR_fpcmple8dishl,
+                            SPARC_BUILTIN_FPCMPLE8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt8shl", CODE_FOR_fpcmpgt8dishl,
+                            SPARC_BUILTIN_FPCMPGT8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq8shl", CODE_FOR_fpcmpeq8dishl,
+                            SPARC_BUILTIN_FPCMPEQ8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpne8shl", CODE_FOR_fpcmpne8dishl,
+                            SPARC_BUILTIN_FPCMPNE8SHL, di_ftype_v8qi_v8qi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmple16shl", CODE_FOR_fpcmple16dishl,
+                            SPARC_BUILTIN_FPCMPLE16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt16shl", CODE_FOR_fpcmpgt16dishl,
+                            SPARC_BUILTIN_FPCMPGT16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq16shl", CODE_FOR_fpcmpeq16dishl,
+                            SPARC_BUILTIN_FPCMPEQ16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpne16shl", CODE_FOR_fpcmpne16dishl,
+                            SPARC_BUILTIN_FPCMPNE16SHL, di_ftype_v4hi_v4hi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmple32shl", CODE_FOR_fpcmple32dishl,
+                            SPARC_BUILTIN_FPCMPLE32SHL, di_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt32shl", CODE_FOR_fpcmpgt32dishl,
+                            SPARC_BUILTIN_FPCMPGT32SHL, di_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq32shl", CODE_FOR_fpcmpeq32dishl,
+                            SPARC_BUILTIN_FPCMPEQ32SHL, di_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpne32shl", CODE_FOR_fpcmpne32dishl,
+                            SPARC_BUILTIN_FPCMPNE32SHL, di_ftype_v2si_v2si_si);
+
+
+         def_builtin_const ("__builtin_vis_fpcmpule8shl", CODE_FOR_fpcmpule8dishl,
+                            SPARC_BUILTIN_FPCMPULE8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt8shl", CODE_FOR_fpcmpugt8dishl,
+                            SPARC_BUILTIN_FPCMPUGT8SHL, di_ftype_v8qi_v8qi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpule16shl", CODE_FOR_fpcmpule16dishl,
+                            SPARC_BUILTIN_FPCMPULE16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt16shl", CODE_FOR_fpcmpugt16dishl,
+                            SPARC_BUILTIN_FPCMPUGT16SHL, di_ftype_v4hi_v4hi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpule32shl", CODE_FOR_fpcmpule32dishl,
+                            SPARC_BUILTIN_FPCMPULE32SHL, di_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt32shl", CODE_FOR_fpcmpugt32dishl,
+                            SPARC_BUILTIN_FPCMPUGT32SHL, di_ftype_v2si_v2si_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpde8shl", CODE_FOR_fpcmpde8dishl,
+                            SPARC_BUILTIN_FPCMPDE8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpde16shl", CODE_FOR_fpcmpde16dishl,
+                            SPARC_BUILTIN_FPCMPDE16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpde32shl", CODE_FOR_fpcmpde32dishl,
+                            SPARC_BUILTIN_FPCMPDE32SHL, di_ftype_v2si_v2si_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpur8shl", CODE_FOR_fpcmpur8dishl,
+                            SPARC_BUILTIN_FPCMPUR8SHL, di_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpur16shl", CODE_FOR_fpcmpur16dishl,
+                            SPARC_BUILTIN_FPCMPUR16SHL, di_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpur32shl", CODE_FOR_fpcmpur32dishl,
+                            SPARC_BUILTIN_FPCMPUR32SHL, di_ftype_v2si_v2si_si);
+
+       }
+      else
+       {
+         tree si_ftype_v8qi_v8qi_si = build_function_type_list (intSI_type_node,
+                                                                v8qi, v8qi,
+                                                                intSI_type_node, 0);
+         tree si_ftype_v4hi_v4hi_si = build_function_type_list (intSI_type_node,
+                                                                v4hi, v4hi,
+                                                                intSI_type_node, 0);
+         tree si_ftype_v2si_v2si_si = build_function_type_list (intSI_type_node,
+                                                                v2si, v2si,
+                                                                intSI_type_node, 0);
+         
+         def_builtin_const ("__builtin_vis_fpcmple8shl", CODE_FOR_fpcmple8sishl,
+                            SPARC_BUILTIN_FPCMPLE8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt8shl", CODE_FOR_fpcmpgt8sishl,
+                            SPARC_BUILTIN_FPCMPGT8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq8shl", CODE_FOR_fpcmpeq8sishl,
+                            SPARC_BUILTIN_FPCMPEQ8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpne8shl", CODE_FOR_fpcmpne8sishl,
+                            SPARC_BUILTIN_FPCMPNE8SHL, si_ftype_v8qi_v8qi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmple16shl", CODE_FOR_fpcmple16sishl,
+                            SPARC_BUILTIN_FPCMPLE16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt16shl", CODE_FOR_fpcmpgt16sishl,
+                            SPARC_BUILTIN_FPCMPGT16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq16shl", CODE_FOR_fpcmpeq16sishl,
+                            SPARC_BUILTIN_FPCMPEQ16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpne16shl", CODE_FOR_fpcmpne16sishl,
+                            SPARC_BUILTIN_FPCMPNE16SHL, si_ftype_v4hi_v4hi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmple32shl", CODE_FOR_fpcmple32sishl,
+                            SPARC_BUILTIN_FPCMPLE32SHL, si_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpgt32shl", CODE_FOR_fpcmpgt32sishl,
+                            SPARC_BUILTIN_FPCMPGT32SHL, si_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpeq32shl", CODE_FOR_fpcmpeq32sishl,
+                            SPARC_BUILTIN_FPCMPEQ32SHL, si_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpne32shl", CODE_FOR_fpcmpne32sishl,
+                            SPARC_BUILTIN_FPCMPNE32SHL, si_ftype_v2si_v2si_si);
+
+
+         def_builtin_const ("__builtin_vis_fpcmpule8shl", CODE_FOR_fpcmpule8sishl,
+                            SPARC_BUILTIN_FPCMPULE8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt8shl", CODE_FOR_fpcmpugt8sishl,
+                            SPARC_BUILTIN_FPCMPUGT8SHL, si_ftype_v8qi_v8qi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpule16shl", CODE_FOR_fpcmpule16sishl,
+                            SPARC_BUILTIN_FPCMPULE16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt16shl", CODE_FOR_fpcmpugt16sishl,
+                            SPARC_BUILTIN_FPCMPUGT16SHL, si_ftype_v4hi_v4hi_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpule32shl", CODE_FOR_fpcmpule32sishl,
+                            SPARC_BUILTIN_FPCMPULE32SHL, si_ftype_v2si_v2si_si);
+         def_builtin_const ("__builtin_vis_fpcmpugt32shl", CODE_FOR_fpcmpugt32sishl,
+                            SPARC_BUILTIN_FPCMPUGT32SHL, si_ftype_v2si_v2si_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpde8shl", CODE_FOR_fpcmpde8sishl,
+                            SPARC_BUILTIN_FPCMPDE8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpde16shl", CODE_FOR_fpcmpde16sishl,
+                            SPARC_BUILTIN_FPCMPDE16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpde32shl", CODE_FOR_fpcmpde32sishl,
+                            SPARC_BUILTIN_FPCMPDE32SHL, si_ftype_v2si_v2si_si);
+
+         def_builtin_const ("__builtin_vis_fpcmpur8shl", CODE_FOR_fpcmpur8sishl,
+                            SPARC_BUILTIN_FPCMPUR8SHL, si_ftype_v8qi_v8qi_si);
+         def_builtin_const ("__builtin_vis_fpcmpur16shl", CODE_FOR_fpcmpur16sishl,
+                            SPARC_BUILTIN_FPCMPUR16SHL, si_ftype_v4hi_v4hi_si);
+         def_builtin_const ("__builtin_vis_fpcmpur32shl", CODE_FOR_fpcmpur32sishl,
+                            SPARC_BUILTIN_FPCMPUR32SHL, si_ftype_v2si_v2si_si);
+       }
+    }
 }
 
 /* Implement TARGET_BUILTIN_DECL hook.  */
@@ -10805,7 +11677,8 @@ sparc_expand_builtin (tree exp, rtx target,
                      int ignore ATTRIBUTE_UNUSED)
 {
   tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
-  enum sparc_builtins code = (enum sparc_builtins) DECL_FUNCTION_CODE (fndecl);
+  enum sparc_builtins code
+    = (enum sparc_builtins) DECL_MD_FUNCTION_CODE (fndecl);
   enum insn_code icode = sparc_builtins_icode[code];
   bool nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
   call_expr_arg_iterator iter;
@@ -10823,6 +11696,8 @@ sparc_expand_builtin (tree exp, rtx target,
       else
        op[0] = target;
     }
+  else
+    op[0] = NULL_RTX;
 
   FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
@@ -10837,6 +11712,19 @@ sparc_expand_builtin (tree exp, rtx target,
       insn_op = &insn_data[icode].operand[idx];
       op[arg_count] = expand_normal (arg);
 
+      /* Some of the builtins require constant arguments.  We check
+        for this here.  */
+      if ((code >= SPARC_BUILTIN_FIRST_FPCMPSHL
+          && code <= SPARC_BUILTIN_LAST_FPCMPSHL
+          && arg_count == 3)
+         || (code >= SPARC_BUILTIN_FIRST_DICTUNPACK
+             && code <= SPARC_BUILTIN_LAST_DICTUNPACK
+             && arg_count == 2))
+       {
+         if (!check_constant_argument (icode, idx, op[arg_count]))
+           return const0_rtx;
+       }
+
       if (code == SPARC_BUILTIN_LDFSR || code == SPARC_BUILTIN_STFSR)
        {
          if (!address_operand (op[arg_count], SImode))
@@ -10901,7 +11789,7 @@ sparc_vis_mul8x16 (int e8, int e16)
    the result into the array N_ELTS, whose elements are of INNER_TYPE.  */
 
 static void
-sparc_handle_vis_mul8x16 (tree *n_elts, enum sparc_builtins fncode,
+sparc_handle_vis_mul8x16 (vec<tree> *n_elts, enum sparc_builtins fncode,
                          tree inner_type, tree cst0, tree cst1)
 {
   unsigned i, num = VECTOR_CST_NELTS (cst0);
@@ -10915,7 +11803,7 @@ sparc_handle_vis_mul8x16 (tree *n_elts, enum sparc_builtins fncode,
          int val
            = sparc_vis_mul8x16 (TREE_INT_CST_LOW (VECTOR_CST_ELT (cst0, i)),
                                 TREE_INT_CST_LOW (VECTOR_CST_ELT (cst1, i)));
-         n_elts[i] = build_int_cst (inner_type, val);
+         n_elts->quick_push (build_int_cst (inner_type, val));
        }
       break;
 
@@ -10927,7 +11815,7 @@ sparc_handle_vis_mul8x16 (tree *n_elts, enum sparc_builtins fncode,
          int val
            = sparc_vis_mul8x16 (TREE_INT_CST_LOW (VECTOR_CST_ELT (cst0, i)),
                                 scale);
-         n_elts[i] = build_int_cst (inner_type, val);
+         n_elts->quick_push (build_int_cst (inner_type, val));
        }
       break;
 
@@ -10939,7 +11827,7 @@ sparc_handle_vis_mul8x16 (tree *n_elts, enum sparc_builtins fncode,
          int val
            = sparc_vis_mul8x16 (TREE_INT_CST_LOW (VECTOR_CST_ELT (cst0, i)),
                                 scale);
-         n_elts[i] = build_int_cst (inner_type, val);
+         n_elts->quick_push (build_int_cst (inner_type, val));
        }
       break;
 
@@ -10958,7 +11846,8 @@ static tree
 sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
                    tree *args, bool ignore)
 {
-  enum sparc_builtins code = (enum sparc_builtins) DECL_FUNCTION_CODE (fndecl);
+  enum sparc_builtins code
+    = (enum sparc_builtins) DECL_MD_FUNCTION_CODE (fndecl);
   tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
   tree arg0, arg1, arg2;
 
@@ -10988,15 +11877,16 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
       if (TREE_CODE (arg0) == VECTOR_CST)
        {
          tree inner_type = TREE_TYPE (rtype);
-         tree *n_elts;
          unsigned i;
 
-         n_elts = XALLOCAVEC (tree, VECTOR_CST_NELTS (arg0));
+         tree_vector_builder n_elts (rtype, VECTOR_CST_NELTS (arg0), 1);
          for (i = 0; i < VECTOR_CST_NELTS (arg0); ++i)
-           n_elts[i] = build_int_cst (inner_type,
-                                      TREE_INT_CST_LOW
-                                        (VECTOR_CST_ELT (arg0, i)) << 4);
-         return build_vector (rtype, n_elts);
+           {
+             unsigned HOST_WIDE_INT val
+               = TREE_INT_CST_LOW (VECTOR_CST_ELT (arg0, i));
+             n_elts.quick_push (build_int_cst (inner_type, val << 4));
+           }
+         return n_elts.build ();
        }
       break;
 
@@ -11011,9 +11901,9 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
       if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
        {
          tree inner_type = TREE_TYPE (rtype);
-         tree *n_elts = XALLOCAVEC (tree, VECTOR_CST_NELTS (arg0));
-         sparc_handle_vis_mul8x16 (n_elts, code, inner_type, arg0, arg1);
-         return build_vector (rtype, n_elts);
+         tree_vector_builder n_elts (rtype, VECTOR_CST_NELTS (arg0), 1);
+         sparc_handle_vis_mul8x16 (&n_elts, code, inner_type, arg0, arg1);
+         return n_elts.build ();
        }
       break;
 
@@ -11025,15 +11915,15 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
 
       if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
        {
-         tree *n_elts = XALLOCAVEC (tree, 2 * VECTOR_CST_NELTS (arg0));
+         tree_vector_builder n_elts (rtype, 2 * VECTOR_CST_NELTS (arg0), 1);
          unsigned i;
          for (i = 0; i < VECTOR_CST_NELTS (arg0); ++i)
            {
-             n_elts[2*i] = VECTOR_CST_ELT (arg0, i);
-             n_elts[2*i+1] = VECTOR_CST_ELT (arg1, i);
+             n_elts.quick_push (VECTOR_CST_ELT (arg0, i));
+             n_elts.quick_push (VECTOR_CST_ELT (arg1, i));
            }
 
-         return build_vector (rtype, n_elts);
+         return n_elts.build ();
        }
       break;
 
@@ -11065,16 +11955,19 @@ sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
              tree e0 = VECTOR_CST_ELT (arg0, i);
              tree e1 = VECTOR_CST_ELT (arg1, i);
 
-             bool neg1_ovf, neg2_ovf, add1_ovf, add2_ovf;
+             wi::overflow_type neg1_ovf, neg2_ovf, add1_ovf, add2_ovf;
 
              tmp = wi::neg (wi::to_widest (e1), &neg1_ovf);
              tmp = wi::add (wi::to_widest (e0), tmp, SIGNED, &add1_ovf);
              if (wi::neg_p (tmp))
                tmp = wi::neg (tmp, &neg2_ovf);
              else
-               neg2_ovf = false;
+               neg2_ovf = wi::OVF_NONE;
              result = wi::add (result, tmp, SIGNED, &add2_ovf);
-             overflow |= neg1_ovf | neg2_ovf | add1_ovf | add2_ovf;
+             overflow |= ((neg1_ovf != wi::OVF_NONE)
+                          | (neg2_ovf != wi::OVF_NONE)
+                          | (add1_ovf != wi::OVF_NONE)
+                          | (add2_ovf != wi::OVF_NONE));
            }
 
          gcc_assert (!overflow);
@@ -11347,7 +12240,8 @@ sparc_register_move_cost (machine_mode mode ATTRIBUTE_UNUSED,
          || sparc_cpu == PROCESSOR_NIAGARA2
          || sparc_cpu == PROCESSOR_NIAGARA3
          || sparc_cpu == PROCESSOR_NIAGARA4
-         || sparc_cpu == PROCESSOR_NIAGARA7)
+         || sparc_cpu == PROCESSOR_NIAGARA7
+         || sparc_cpu == PROCESSOR_M8)
        return 12;
 
       return 6;
@@ -11397,6 +12291,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
                       HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
                       tree function)
 {
+  const char *fnname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (thunk_fndecl));
   rtx this_rtx, funexp;
   rtx_insn *insn;
   unsigned int int_arg_first;
@@ -11534,6 +12429,8 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
          spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
          start_sequence ();
          load_got_register ();  /* clobbers %o7 */
+         if (!TARGET_VXWORKS_RTP)
+           pic_offset_table_rtx = got_register_rtx;
          scratch = sparc_legitimize_pic_address (funexp, scratch);
          seq = get_insns ();
          end_sequence ();
@@ -11548,7 +12445,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
        }
       else  /* TARGET_ARCH64 */
         {
-         switch (sparc_cmodel)
+         switch (sparc_code_model)
            {
            case CM_MEDLOW:
            case CM_MEDMID:
@@ -11579,13 +12476,14 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   /* Run just enough of rest_of_compilation to get the insns emitted.
      There's not really enough bulk here to make other passes such as
-     instruction scheduling worth while.  Note that use_thunk calls
-     assemble_start_function and assemble_end_function.  */
+     instruction scheduling worth while.  */
   insn = get_insns ();
   shorten_branches (insn);
+  assemble_start_function (thunk_fndecl, fnname);
   final_start_function (insn, file, 1);
   final (insn, file, 1);
   final_end_function ();
+  assemble_end_function (thunk_fndecl, fnname);
 
   reload_completed = 0;
   epilogue_completed = 0;
@@ -11611,7 +12509,15 @@ sparc_init_machine_status (void)
 {
   return ggc_cleared_alloc<machine_function> ();
 }
+\f
+/* Implement the TARGET_ASAN_SHADOW_OFFSET hook.  */
 
+static unsigned HOST_WIDE_INT
+sparc_asan_shadow_offset (void)
+{
+  return TARGET_ARCH64 ? (HOST_WIDE_INT_1 << 43) : (HOST_WIDE_INT_1 << 29);
+}
+\f
 /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
@@ -11639,10 +12545,9 @@ static void
 sparc_file_end (void)
 {
   /* If we need to emit the special GOT helper function, do so now.  */
-  if (got_helper_rtx)
+  if (got_helper_needed)
     {
       const char *name = XSTR (got_helper_rtx, 0);
-      const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM];
 #ifdef DWARF2_UNWIND_INFO
       bool do_cfi;
 #endif
@@ -11679,17 +12584,22 @@ sparc_file_end (void)
 #ifdef DWARF2_UNWIND_INFO
       do_cfi = dwarf2out_do_cfi_asm ();
       if (do_cfi)
-       fprintf (asm_out_file, "\t.cfi_startproc\n");
+       output_asm_insn (".cfi_startproc", NULL);
 #endif
       if (flag_delayed_branch)
-       fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
-                reg_name, reg_name);
+       {
+         output_asm_insn ("jmp\t%%o7+8", NULL);
+         output_asm_insn (" add\t%%o7, %0, %0", &got_register_rtx);
+       }
       else
-       fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
-                reg_name, reg_name);
+       {
+         output_asm_insn ("add\t%%o7, %0, %0", &got_register_rtx);
+         output_asm_insn ("jmp\t%%o7+8", NULL);
+         output_asm_insn (" nop", NULL);
+       }
 #ifdef DWARF2_UNWIND_INFO
       if (do_cfi)
-       fprintf (asm_out_file, "\t.cfi_endproc\n");
+       output_asm_insn (".cfi_endproc", NULL);
 #endif
     }
 
@@ -11707,7 +12617,7 @@ sparc_file_end (void)
 static const char *
 sparc_mangle_type (const_tree type)
 {
-  if (!TARGET_64BIT
+  if (TARGET_ARCH32
       && TYPE_MAIN_VARIANT (type) == long_double_type_node
       && TARGET_LONG_DOUBLE_128)
     return "g";
@@ -11948,7 +12858,7 @@ sparc_expand_vec_perm_bmask (machine_mode vmode, rtx sel)
   sel = gen_lowpart (DImode, sel);
   switch (vmode)
     {
-    case V2SImode:
+    case E_V2SImode:
       /* inp = xxxxxxxAxxxxxxxB */
       t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (16),
                                 NULL_RTX, 1, OPTAB_DIRECT);
@@ -11967,7 +12877,7 @@ sparc_expand_vec_perm_bmask (machine_mode vmode, rtx sel)
       /* sel = { A*4, A*4+1, A*4+2, ... } */
       break;
 
-    case V4HImode:
+    case E_V4HImode:
       /* inp = xxxAxxxBxxxCxxxD */
       t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (8),
                                 NULL_RTX, 1, OPTAB_DIRECT);
@@ -12004,7 +12914,7 @@ sparc_expand_vec_perm_bmask (machine_mode vmode, rtx sel)
       /* sel = { A*2, A*2+1, B*2, B*2+1, ... } */
       break;
   
-    case V8QImode:
+    case E_V8QImode:
       /* input = xAxBxCxDxExFxGxH */
       sel = expand_simple_binop (DImode, AND, sel,
                                 GEN_INT ((HOST_WIDE_INT)0x0f0f0f0f << 32
@@ -12047,6 +12957,35 @@ sparc_expand_vec_perm_bmask (machine_mode vmode, rtx sel)
   emit_insn (gen_bmasksi_vis (gen_reg_rtx (SImode), sel, t_1));
 }
 
+/* Implement TARGET_VEC_PERM_CONST.  */
+
+static bool
+sparc_vectorize_vec_perm_const (machine_mode vmode, rtx target, rtx op0,
+                               rtx op1, const vec_perm_indices &sel)
+{
+  if (!TARGET_VIS2)
+    return false;
+
+  /* All permutes are supported.  */
+  if (!target)
+    return true;
+
+  /* Force target-independent code to convert constant permutations on other
+     modes down to V8QI.  Rely on this to avoid the complexity of the byte
+     order of the permutation.  */
+  if (vmode != V8QImode)
+    return false;
+
+  unsigned int i, mask;
+  for (i = mask = 0; i < 8; ++i)
+    mask |= (sel[i] & 0xf) << (28 - i*4);
+  rtx mask_rtx = force_reg (SImode, gen_int_mode (mask, SImode));
+
+  emit_insn (gen_bmasksi_vis (gen_reg_rtx (SImode), mask_rtx, const0_rtx));
+  emit_insn (gen_bshufflev8qi_vis (target, op0, op1));
+  return true;
+}
+
 /* Implement TARGET_FRAME_POINTER_REQUIRED.  */
 
 static bool
@@ -12066,8 +13005,9 @@ sparc_frame_pointer_required (void)
   if (TARGET_FLAT)
     return false;
 
-  /* Otherwise, the frame pointer is required if the function isn't leaf.  */
-  return !(crtl->is_leaf && only_leaf_regs_used ());
+  /* Otherwise, the frame pointer is required if the function isn't leaf, but
+     we cannot use sparc_leaf_function_p since it hasn't been computed yet.  */
+  return !(optimize > 0 && crtl->is_leaf && only_leaf_regs_used ());
 }
 
 /* The way this is structured, we can't eliminate SFP in favor of SP
@@ -12081,14 +13021,6 @@ sparc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
   return to == HARD_FRAME_POINTER_REGNUM || !sparc_frame_pointer_required ();
 }
 
-/* Return the hard frame pointer directly to bypass the stack bias.  */
-
-static rtx
-sparc_builtin_setjmp_frame_value (void)
-{
-  return hard_frame_pointer_rtx;
-}
-
 /* If !TARGET_FPU, then make the fp registers and fp cc regs fixed so that
    they won't be allocated.  */
 
@@ -12096,10 +13028,7 @@ 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;
-    }
+    fixed_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])
@@ -12149,6 +13078,40 @@ sparc_conditional_register_usage (void)
     global_regs[SPARC_GSR_REG] = 1;
 }
 
+/* Implement TARGET_USE_PSEUDO_PIC_REG.  */
+
+static bool
+sparc_use_pseudo_pic_reg (void)
+{
+  return !TARGET_VXWORKS_RTP && flag_pic;
+}
+
+/* Implement TARGET_INIT_PIC_REG.  */
+
+static void
+sparc_init_pic_reg (void)
+{
+  edge entry_edge;
+  rtx_insn *seq;
+
+  /* In PIC mode, we need to always initialize the PIC register if optimization
+     is enabled, because we are called from IRA and LRA may later force things
+     to the constant pool for optimization purposes.  */
+  if (!flag_pic || (!crtl->uses_pic_offset_table && !optimize))
+    return;
+
+  start_sequence ();
+  load_got_register ();
+  if (!TARGET_VXWORKS_RTP)
+    emit_move_insn (pic_offset_table_rtx, got_register_rtx);
+  seq = get_insns ();
+  end_sequence ();
+
+  entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  insert_insn_on_edge (seq, entry_edge);
+  commit_one_edge_insertion (entry_edge);
+}
+
 /* Implement TARGET_PREFERRED_RELOAD_CLASS:
 
    - We can't load constants into FP registers.
@@ -12199,6 +13162,14 @@ sparc_preferred_reload_class (rtx x, reg_class_t rclass)
   return rclass;
 }
 
+/* Return true if we use LRA instead of reload pass.  */
+
+static bool
+sparc_lra_p (void)
+{
+  return TARGET_LRA;
+}
+
 /* Output a wide multiply instruction in V8+ mode.  INSN is the instruction,
    OPERANDS are its operands and OPCODE is the mnemonic to be used.  */
 
@@ -12293,15 +13264,15 @@ vector_init_bshuffle (rtx target, rtx elt, machine_mode mode,
 
   switch (mode)
     {
-    case V2SImode:
+    case E_V2SImode:
       final_insn = gen_bshufflev2si_vis (target, t1, t1);
       bmask = 0x45674567;
       break;
-    case V4HImode:
+    case E_V4HImode:
       final_insn = gen_bshufflev4hi_vis (target, t1, t1);
       bmask = 0x67676767;
       break;
-    case V8QImode:
+    case E_V8QImode:
       final_insn = gen_bshufflev8qi_vis (target, t1, t1);
       bmask = 0x77777777;
       break;
@@ -12502,6 +13473,45 @@ sparc_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
   return NO_REGS;
 }
 
+/* Implement TARGET_SECONDARY_MEMORY_NEEDED.
+
+   On SPARC when not VIS3 it is not possible to directly move data
+   between GENERAL_REGS and FP_REGS.  */
+
+static bool
+sparc_secondary_memory_needed (machine_mode mode, reg_class_t class1,
+                              reg_class_t class2)
+{
+  return ((FP_REG_CLASS_P (class1) != FP_REG_CLASS_P (class2))
+         && (! TARGET_VIS3
+             || GET_MODE_SIZE (mode) > 8
+             || GET_MODE_SIZE (mode) < 4));
+}
+
+/* Implement TARGET_SECONDARY_MEMORY_NEEDED_MODE.
+
+   get_secondary_mem widens its argument to BITS_PER_WORD which loses on v9
+   because the movsi and movsf patterns don't handle r/f moves.
+   For v8 we copy the default definition.  */
+
+static machine_mode
+sparc_secondary_memory_needed_mode (machine_mode mode)
+{
+  if (TARGET_ARCH64)
+    {
+      if (GET_MODE_BITSIZE (mode) < 32)
+       return mode_for_size (32, GET_MODE_CLASS (mode), 0).require ();
+      return mode;
+    }
+  else
+    {
+      if (GET_MODE_BITSIZE (mode) < BITS_PER_WORD)
+       return mode_for_size (BITS_PER_WORD,
+                             GET_MODE_CLASS (mode), 0).require ();
+      return mode;
+    }
+}
+
 /* Emit code to conditionally move either OPERANDS[2] or OPERANDS[3] into
    OPERANDS[0] in MODE.  OPERANDS[1] is the operator of the condition.  */
 
@@ -12622,15 +13632,46 @@ sparc_regmode_natural_size (machine_mode mode)
   return size;
 }
 
-/* Return TRUE if it is a good idea to tie two pseudo registers
-   when one has mode MODE1 and one has mode MODE2.
-   If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
-   for any hard reg, then this must be FALSE for correct output.
+/* Implement TARGET_HARD_REGNO_NREGS.
+
+   On SPARC, ordinary registers hold 32 bits worth; this means both
+   integer and floating point registers.  On v9, integer regs hold 64
+   bits worth; floating point regs hold 32 bits worth (this includes the
+   new fp regs as even the odd ones are included in the hard register
+   count).  */
+
+static unsigned int
+sparc_hard_regno_nregs (unsigned int regno, machine_mode mode)
+{
+  if (regno == SPARC_GSR_REG)
+    return 1;
+  if (TARGET_ARCH64)
+    {
+      if (SPARC_INT_REG_P (regno) || regno == FRAME_POINTER_REGNUM)
+       return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
+      return CEIL (GET_MODE_SIZE (mode), 4);
+    }
+  return CEIL (GET_MODE_SIZE (mode), UNITS_PER_WORD);
+}
+
+/* Implement TARGET_HARD_REGNO_MODE_OK.
+
+   ??? Because of the funny way we pass parameters we should allow certain
+   ??? types of float/complex values to be in integer registers during
+   ??? RTL generation.  This only matters on arch32.  */
+
+static bool
+sparc_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
+{
+  return (hard_regno_mode_classes[regno] & sparc_mode_class[mode]) != 0;
+}
+
+/* Implement TARGET_MODES_TIEABLE_P.
 
    For V9 we have to deal with the fact that only the lower 32 floating
    point registers are 32-bit addressable.  */
 
-bool
+static bool
 sparc_modes_tieable_p (machine_mode mode1, machine_mode mode2)
 {
   enum mode_class mclass1, mclass2;
@@ -12670,7 +13711,7 @@ sparc_modes_tieable_p (machine_mode mode1, machine_mode mode2)
 
 /* Implement TARGET_CSTORE_MODE.  */
 
-static machine_mode
+static scalar_int_mode
 sparc_cstore_mode (enum insn_code icode ATTRIBUTE_UNUSED)
 {
   return (TARGET_ARCH64 ? DImode : SImode);
@@ -12775,4 +13816,36 @@ sparc_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
     = compound_expr (compound_expr (update_stfsr, update_ldfsr), update_call);
 }
 
+/* Implement TARGET_CAN_CHANGE_MODE_CLASS.  Borrowed from the PA port.
+
+   SImode loads to floating-point registers are not zero-extended.
+   The definition for LOAD_EXTEND_OP specifies that integer loads
+   narrower than BITS_PER_WORD will be zero-extended.  As a result,
+   we inhibit changes from SImode unless they are to a mode that is
+   identical in size.
+
+   Likewise for SFmode, since word-mode paradoxical subregs are
+   problematic on big-endian architectures.  */
+
+static bool
+sparc_can_change_mode_class (machine_mode from, machine_mode to,
+                            reg_class_t rclass)
+{
+  if (TARGET_ARCH64
+      && GET_MODE_SIZE (from) == 4
+      && GET_MODE_SIZE (to) != 4)
+    return !reg_classes_intersect_p (rclass, FP_REGS);
+  return true;
+}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.  */
+
+static HOST_WIDE_INT
+sparc_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+  if (TREE_CODE (exp) == STRING_CST)
+    return MAX (align, FASTEST_ALIGNMENT);
+  return align;
+}
+
 #include "gt-sparc.h"