OSDN Git Service

2008-04-03 Jan Hubicka <jh@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index ac1a434..54c81b1 100644 (file)
@@ -1,6 +1,7 @@
 /* Subroutines for insn-output.c for SPARC.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
    64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
    at Cygnus Support.
@@ -9,7 +10,7 @@ This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -18,9 +19,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -32,6 +32,7 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
+#include "insn-codes.h"
 #include "conditions.h"
 #include "output.h"
 #include "insn-attr.h"
@@ -48,6 +49,9 @@ Boston, MA 02111-1307, USA.  */
 #include "target-def.h"
 #include "cfglayout.h"
 #include "tree-gimple.h"
+#include "langhooks.h"
+#include "params.h"
+#include "df.h"
 
 /* Processor costs */
 static const
@@ -194,6 +198,54 @@ struct processor_costs ultrasparc3_costs = {
   0, /* shift penalty */
 };
 
+static const
+struct processor_costs niagara_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (9), /* float load */
+  COSTS_N_INSNS (8), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (8), /* fadd, fsub */
+  COSTS_N_INSNS (26), /* fcmp */
+  COSTS_N_INSNS (8), /* fmov, fmovr */
+  COSTS_N_INSNS (29), /* fmul */
+  COSTS_N_INSNS (54), /* fdivs */
+  COSTS_N_INSNS (83), /* fdivd */
+  COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */
+  COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */
+  COSTS_N_INSNS (11), /* imul */
+  COSTS_N_INSNS (11), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (72), /* idiv */
+  COSTS_N_INSNS (72), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs niagara2_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (3), /* float load */
+  COSTS_N_INSNS (6), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (6), /* fadd, fsub */
+  COSTS_N_INSNS (6), /* fcmp */
+  COSTS_N_INSNS (6), /* fmov, fmovr */
+  COSTS_N_INSNS (6), /* fmul */
+  COSTS_N_INSNS (19), /* fdivs */
+  COSTS_N_INSNS (33), /* fdivd */
+  COSTS_N_INSNS (19), /* fsqrts */
+  COSTS_N_INSNS (33), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (31), /* idiv, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (31), /* idivX, average of 12 - 41 cycle range */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
 const struct processor_costs *sparc_costs = &cypress_costs;
 
 #ifdef HAVE_AS_RELAX_OPTION
@@ -223,11 +275,14 @@ static HOST_WIDE_INT actual_fsize;
 static int num_gfregs;
 
 /* The alias set for prologue/epilogue register save/restore.  */
-static GTY(()) int sparc_sr_alias_set;
+static GTY(()) alias_set_type sparc_sr_alias_set;
+
+/* The alias set for the structure return value.  */
+static GTY(()) alias_set_type struct_value_alias_set;
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
-rtx sparc_compare_op0, sparc_compare_op1;
+rtx sparc_compare_op0, sparc_compare_op1, sparc_compare_emitted;
 
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
@@ -270,16 +325,31 @@ struct machine_function GTY(())
 {
   /* Some local-dynamic TLS symbol name.  */
   const char *some_ld_name;
+
+  /* True if the current function is leaf and uses only leaf regs,
+     so that the SPARC leaf function optimization can be applied.
+     Private version of current_function_uses_only_leaf_regs, see
+     sparc_expand_prologue for the rationale.  */
+  int leaf_function_p;
+
+  /* True if the data calculated by sparc_expand_prologue are valid.  */
+  bool prologue_data_valid_p;
 };
 
+#define sparc_leaf_function_p  cfun->machine->leaf_function_p
+#define sparc_prologue_data_valid_p  cfun->machine->prologue_data_valid_p
+
 /* Register we pretend to think the frame pointer is allocated to.
    Normally, this is %fp, but if we are in a leaf procedure, this
    is %sp+"something".  We record "something" separately as it may
    be too big for reg+constant addressing.  */
-
 static rtx frame_base_reg;
 static HOST_WIDE_INT frame_base_offset;
 
+/* 1 if the next opcode is to be specially indented.  */
+int sparc_indent_opcode = 0;
+
+static bool sparc_handle_option (size_t, const char *, int);
 static void sparc_init_modes (void);
 static void scan_record_type (tree, int *, int *, int *);
 static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
@@ -295,14 +365,14 @@ static rtx sparc_builtin_saveregs (void);
 static int epilogue_renumber (rtx *, int);
 static bool sparc_assemble_integer (rtx, unsigned int, int);
 static int set_extends (rtx);
-static void load_pic_register (void);
+static void emit_pic_helper (void);
+static void load_pic_register (bool);
 static int save_or_restore_regs (int, int, rtx, int, int);
-static void emit_save_regs (void);
-static void emit_restore_regs (void);
+static void emit_save_or_restore_regs (int);
 static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
 static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
 #ifdef OBJECT_FORMAT_ELF
-static void sparc_elf_asm_named_section (const char *, unsigned int);
+static void sparc_elf_asm_named_section (const char *, unsigned int, tree);
 #endif
 
 static int sparc_adjust_cost (rtx, rtx, rtx, int);
@@ -318,8 +388,16 @@ static void emit_hard_tfmode_operation (enum rtx_code, rtx *);
 
 static bool sparc_function_ok_for_sibcall (tree, tree);
 static void sparc_init_libfuncs (void);
+static void sparc_init_builtins (void);
+static void sparc_vis_init_builtins (void);
+static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static tree sparc_fold_builtin (tree, tree, bool);
+static int sparc_vis_mul8x16 (int, int);
+static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree);
 static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
                                   HOST_WIDE_INT, tree);
+static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
+                                      HOST_WIDE_INT, const_tree);
 static struct machine_function * sparc_init_machine_status (void);
 static bool sparc_cannot_force_const_mem (rtx);
 static rtx sparc_tls_get_addr (void);
@@ -327,21 +405,29 @@ static rtx sparc_tls_got (void);
 static const char *get_some_local_dynamic_name (void);
 static int get_some_local_dynamic_name_1 (rtx *, void *);
 static bool sparc_rtx_costs (rtx, int, int, int *);
-static bool sparc_promote_prototypes (tree);
+static bool sparc_promote_prototypes (const_tree);
 static rtx sparc_struct_value_rtx (tree, int);
-static bool sparc_return_in_memory (tree, tree);
+static bool sparc_return_in_memory (const_tree, const_tree);
 static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static void sparc_va_start (tree, rtx);
 static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool sparc_vector_mode_supported_p (enum machine_mode);
 static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
-                                    enum machine_mode, tree, bool);
+                                    enum machine_mode, const_tree, bool);
+static int sparc_arg_partial_bytes (CUMULATIVE_ARGS *,
+                                   enum machine_mode, tree, bool);
+static void sparc_dwarf_handle_frame_unspec (const char *, rtx, int);
+static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static void sparc_file_end (void);
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+static const char *sparc_mangle_type (const_tree);
+#endif
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
 const struct attribute_spec sparc_attribute_table[];
 #endif
 \f
 /* Option handling.  */
 
-/* Code model option as passed by user.  */
-const char *sparc_cmodel_string;
 /* Parsed value.  */
 enum cmodel sparc_cmodel;
 
@@ -358,7 +444,10 @@ struct sparc_cpu_select sparc_select[] =
 
 /* CPU type.  This is set from TARGET_CPU_DEFAULT and -m{cpu,tune}=xxx.  */
 enum processor_type sparc_cpu;
-\f
+
+/* Whether\fan FPU option was specified.  */
+static bool fpu_option_set = false;
+
 /* Initialize the GCC target structure.  */
 
 /* The sparc default is to use .half rather than .short for aligned
@@ -400,18 +489,26 @@ enum processor_type sparc_cpu;
 
 #undef TARGET_INIT_LIBFUNCS
 #define TARGET_INIT_LIBFUNCS sparc_init_libfuncs
+#undef TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS sparc_init_builtins
 
-#ifdef HAVE_AS_TLS
+#undef TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN sparc_expand_builtin
+#undef TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN sparc_fold_builtin
+
+#if TARGET_TLS
 #undef TARGET_HAVE_TLS
 #define TARGET_HAVE_TLS true
 #endif
+
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
 
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
 
 #undef TARGET_RTX_COSTS
 #define TARGET_RTX_COSTS sparc_rtx_costs
@@ -422,13 +519,13 @@ enum processor_type sparc_cpu;
    no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
    test for this value.  */
 #undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
 
 /* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
    no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
    test for this value.  */
 #undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
 
 #undef TARGET_PROMOTE_PROTOTYPES
 #define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
@@ -441,17 +538,24 @@ enum processor_type sparc_cpu;
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes
 
 #undef TARGET_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_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
 
-#undef TARGET_LATE_RTL_PROLOGUE_EPILOGUE
-#define TARGET_LATE_RTL_PROLOGUE_EPILOGUE true
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p
+
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC sparc_dwarf_handle_frame_unspec
 
 #ifdef SUBTARGET_INSERT_ATTRIBUTES
 #undef TARGET_INSERT_ATTRIBUTES
@@ -463,8 +567,54 @@ enum processor_type sparc_cpu;
 #define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
 #endif
 
+#undef TARGET_RELAXED_ORDERING
+#define TARGET_RELAXED_ORDERING SPARC_RELAXED_ORDERING
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION sparc_handle_option
+
+#if TARGET_GNU_TLS
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
+#endif
+
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END sparc_file_end
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE sparc_mangle_type
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
-\f
+
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+sparc_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
+    {
+    case OPT_mfpu:
+    case OPT_mhard_float:
+    case OPT_msoft_float:
+      fpu_option_set = true;
+      break;
+
+    case OPT_mcpu_:
+      sparc_select[1].string = arg;
+      break;
+
+    case OPT_mtune_:
+      sparc_select[2].string = arg;
+      break;
+    }
+
+  return true;
+}
+
 /* Validate and override various options, and do some machine dependent
    initialization.  */
 
@@ -499,6 +649,8 @@ sparc_override_options (void)
     { TARGET_CPU_v9, "v9" },
     { TARGET_CPU_ultrasparc, "ultrasparc" },
     { TARGET_CPU_ultrasparc3, "ultrasparc3" },
+    { TARGET_CPU_niagara, "niagara" },
+    { TARGET_CPU_niagara2, "niagara2" },
     { 0, 0 }
   };
   const struct cpu_default *def;
@@ -534,6 +686,9 @@ sparc_override_options (void)
     /* TI ultrasparc III */
     /* ??? Check if %y issue still holds true in ultra3.  */
     { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+    /* UltraSPARC T1 */
+    { "niagara", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
+    { "niagara2", PROCESSOR_NIAGARA, MASK_ISA, MASK_V9},
     { 0, 0, 0, 0 }
   };
   const struct cpu_table *cpu;
@@ -578,14 +733,13 @@ sparc_override_options (void)
        error ("-mcmodel= is not supported on 32 bit systems");
     }
 
-  fpu = TARGET_FPU; /* save current -mfpu status */
+  fpu = target_flags & MASK_FPU; /* save current -mfpu status */
 
   /* Set the default CPU.  */
   for (def = &cpu_default[0]; def->name; ++def)
     if (def->cpu == TARGET_CPU_DEFAULT)
       break;
-  if (! def->name)
-    abort ();
+  gcc_assert (def->name);
   sparc_select[0].string = def->name;
 
   for (sel = &sparc_select[0]; sel->name; ++sel)
@@ -612,13 +766,9 @@ sparc_override_options (void)
     }
 
   /* If -mfpu or -mno-fpu was explicitly used, don't override with
-     the processor default.  Clear MASK_FPU_SET to avoid confusing
-     the reverse mapping from switch values to names.  */
-  if (TARGET_FPU_SET)
-    {
-      target_flags = (target_flags & ~MASK_FPU) | fpu;
-      target_flags &= ~MASK_FPU_SET;
-    }
+     the processor default.  */
+  if (fpu_option_set)
+    target_flags = (target_flags & ~MASK_FPU) | fpu;
 
   /* Don't allow -mvis if FPU is disabled.  */
   if (! TARGET_FPU)
@@ -648,7 +798,9 @@ sparc_override_options (void)
   /* Supply a default value for align_functions.  */
   if (align_functions == 0
       && (sparc_cpu == PROCESSOR_ULTRASPARC
-         || sparc_cpu == PROCESSOR_ULTRASPARC3))
+         || sparc_cpu == PROCESSOR_ULTRASPARC3
+         || sparc_cpu == PROCESSOR_NIAGARA
+         || sparc_cpu == PROCESSOR_NIAGARA2))
     align_functions = 32;
 
   /* Validate PCC_STRUCT_RETURN.  */
@@ -662,8 +814,9 @@ sparc_override_options (void)
   /* Do various machine dependent initializations.  */
   sparc_init_modes ();
 
-  /* Acquire a unique set number for our register saves and restores.  */
+  /* Acquire unique alias sets for our private stuff.  */
   sparc_sr_alias_set = new_alias_set ();
+  struct_value_alias_set = new_alias_set ();
 
   /* Set up function hooks.  */
   init_machine_status = sparc_init_machine_status;
@@ -696,7 +849,34 @@ sparc_override_options (void)
     case PROCESSOR_ULTRASPARC3:
       sparc_costs = &ultrasparc3_costs;
       break;
+    case PROCESSOR_NIAGARA:
+      sparc_costs = &niagara_costs;
+      break;
+    case PROCESSOR_NIAGARA2:
+      sparc_costs = &niagara2_costs;
+      break;
     };
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+    target_flags |= MASK_LONG_DOUBLE_128;
+#endif
+
+  if (!PARAM_SET_P (PARAM_SIMULTANEOUS_PREFETCHES))
+    set_param_value ("simultaneous-prefetches",
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 2
+                     : (sparc_cpu == PROCESSOR_ULTRASPARC3
+                        ? 8 : 3)));
+  if (!PARAM_SET_P (PARAM_L1_CACHE_LINE_SIZE))
+    set_param_value ("l1-cache-line-size", 
+                    ((sparc_cpu == PROCESSOR_ULTRASPARC
+                      || sparc_cpu == PROCESSOR_ULTRASPARC3
+                      || sparc_cpu == PROCESSOR_NIAGARA
+                      || sparc_cpu == PROCESSOR_NIAGARA2)
+                     ? 64 : 32));
 }
 \f
 #ifdef SUBTARGET_ATTRIBUTE_TABLE
@@ -721,58 +901,6 @@ v9_regcmp_p (enum rtx_code code)
          || code == LE || code == GT);
 }
 
-\f
-/* Operand constraints.  */
-
-/* Return nonzero only if OP is a register of mode MODE,
-   or const0_rtx.  */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-  if (op == const0_rtx)
-    return 1;
-  if (GET_MODE (op) == VOIDmode && GET_CODE (op) == CONST_DOUBLE
-      && CONST_DOUBLE_HIGH (op) == 0
-      && CONST_DOUBLE_LOW (op) == 0)
-    return 1;
-  if (fp_zero_operand (op, mode))
-    return 1;
-  return 0;
-}
-
-/* Return nonzero only if OP is const1_rtx.  */
-
-int
-const1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return op == const1_rtx;
-}
-
-/* Nonzero if OP is a floating point value with value 0.0.  */
-
-int
-fp_zero_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
-    return 0;
-  return op == CONST0_RTX (mode);
-}
-
-/* Nonzero if OP is a register operand in floating point register.  */
-
-int
-fp_register_operand (rtx op, enum machine_mode mode)
-{
-  if (! register_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return GET_CODE (op) == REG && SPARC_FP_REG_P (REGNO (op));
-}
-
 /* Nonzero if OP is a floating point constant which can
    be loaded into an integer register using a single
    sethi instruction.  */
@@ -786,12 +914,8 @@ fp_sethi_p (rtx op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (SPARC_SETHI_P (i))
-       return 1;
+      return !SPARC_SIMM13_P (i) && SPARC_SETHI_P (i);
     }
 
   return 0;
@@ -810,12 +934,8 @@ fp_mov_p (rtx op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (SPARC_SIMM13_P (i))
-       return 1;
+      return SPARC_SIMM13_P (i);
     }
 
   return 0;
@@ -837,771 +957,171 @@ fp_high_losum_p (rtx op)
       long i;
 
       REAL_VALUE_FROM_CONST_DOUBLE (r, op);
-      if (REAL_VALUES_EQUAL (r, dconst0) &&
-         ! REAL_VALUE_MINUS_ZERO (r))
-       return 0;
       REAL_VALUE_TO_TARGET_SINGLE (r, i);
-      if (! SPARC_SETHI_P (i)
-          && ! SPARC_SIMM13_P (i))
-       return 1;
+      return !SPARC_SIMM13_P (i) && !SPARC_SETHI_P (i);
     }
 
   return 0;
 }
 
-/* Nonzero if OP is an integer register.  */
-
-int
-intreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (register_operand (op, SImode)
-         || (TARGET_ARCH64 && register_operand (op, DImode)));
-}
-
-/* Nonzero if OP is a floating point condition code register.  */
-
-int
-fcc_reg_operand (rtx op, enum machine_mode mode)
-{
-  /* This can happen when recog is called from combine.  Op may be a MEM.
-     Fail instead of calling abort in this case.  */
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  if (mode == VOIDmode
-      && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
-    return 0;
+/* Expand a move instruction.  Return true if all work is done.  */
 
-#if 0  /* ??? ==> 1 when %fcc0-3 are pseudos first.  See gen_compare_reg().  */
-  if (reg_renumber == 0)
-    return REGNO (op) >= FIRST_PSEUDO_REGISTER;
-  return REGNO_OK_FOR_CCFP_P (REGNO (op));
-#else
-  return (unsigned) REGNO (op) - SPARC_FIRST_V9_FCC_REG < 4;
-#endif
-}
-
-/* Nonzero if OP is a floating point condition code fcc0 register.  */
-
-int
-fcc0_reg_operand (rtx op, enum machine_mode mode)
-{
-  /* This can happen when recog is called from combine.  Op may be a MEM.
-     Fail instead of calling abort in this case.  */
-  if (GET_CODE (op) != REG)
-    return 0;
-
-  if (mode != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  if (mode == VOIDmode
-      && (GET_MODE (op) != CCFPmode && GET_MODE (op) != CCFPEmode))
-    return 0;
-
-  return REGNO (op) == SPARC_FCC_REG;
-}
-
-/* Nonzero if OP is an integer or floating point condition code register.  */
-
-int
-icc_or_fcc_reg_operand (rtx op, enum machine_mode mode)
+bool
+sparc_expand_move (enum machine_mode mode, rtx *operands)
 {
-  if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
+  /* Handle sets of MEM first.  */
+  if (GET_CODE (operands[0]) == MEM)
     {
-      if (mode != VOIDmode && mode != GET_MODE (op))
-       return 0;
-      if (mode == VOIDmode
-         && GET_MODE (op) != CCmode && GET_MODE (op) != CCXmode)
-       return 0;
-      return 1;
-    }
-
-  return fcc_reg_operand (op, mode);
-}
-
-/* Call insn on SPARC can take a PC-relative constant address, or any regular
-   memory address.  */
-
-int
-call_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != MEM)
-    abort ();
-  op = XEXP (op, 0);
-  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
-
-int
-call_operand_address (rtx op, enum machine_mode mode)
-{
-  return (symbolic_operand (op, mode) || memory_address_p (Pmode, op));
-}
-
-/* If OP is a SYMBOL_REF of a thread-local symbol, return its TLS mode,
-   otherwise return 0.  */
-
-int
-tls_symbolic_operand (rtx op)
-{
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
-  return SYMBOL_REF_TLS_MODEL (op);
-}
-
-int
-tgd_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return tls_symbolic_operand (op) == TLS_MODEL_GLOBAL_DYNAMIC;
-}
-
-int
-tld_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_DYNAMIC;
-}
-
-int
-tie_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return tls_symbolic_operand (op) == TLS_MODEL_INITIAL_EXEC;
-}
-
-int
-tle_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return tls_symbolic_operand (op) == TLS_MODEL_LOCAL_EXEC;
-}
-
-/* Returns 1 if OP is either a symbol reference or a sum of a symbol
-   reference and a constant.  */
-
-int
-symbolic_operand (register rtx op, enum machine_mode mode)
-{
-  enum machine_mode omode = GET_MODE (op);
+      /* 0 is a register (or a pair of registers) on SPARC.  */
+      if (register_or_zero_operand (operands[1], mode))
+       return false;
 
-  if (omode != mode && omode != VOIDmode && mode != VOIDmode)
-    return 0;
+      if (!reload_in_progress)
+       {
+         operands[0] = validize_mem (operands[0]);
+         operands[1] = force_reg (mode, operands[1]);
+       }
+    }
 
-  switch (GET_CODE (op))
+  /* Fixup TLS cases.  */
+  if (TARGET_HAVE_TLS
+      && CONSTANT_P (operands[1])
+      && GET_CODE (operands[1]) != HIGH
+      && sparc_tls_referenced_p (operands [1]))
     {
-    case SYMBOL_REF:
-      return !SYMBOL_REF_TLS_MODEL (op);
+      rtx sym = operands[1];
+      rtx addend = NULL;
 
-    case LABEL_REF:
-      return 1;
+      if (GET_CODE (sym) == CONST && GET_CODE (XEXP (sym, 0)) == PLUS)
+       {
+         addend = XEXP (XEXP (sym, 0), 1);
+         sym = XEXP (XEXP (sym, 0), 0);
+       }
 
-    case CONST:
-      op = XEXP (op, 0);
-      return (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-               && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
-              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
-             && GET_CODE (XEXP (op, 1)) == CONST_INT);
+      gcc_assert (SPARC_SYMBOL_REF_TLS_P (sym));
 
-    default:
-      return 0;
+      sym = legitimize_tls_address (sym);
+      if (addend)
+       {
+         sym = gen_rtx_PLUS (mode, sym, addend);
+         sym = force_operand (sym, operands[0]);
+       }
+      operands[1] = sym;
     }
-}
-
-/* Return truth value of statement that OP is a symbolic memory
-   operand of mode MODE.  */
-
-int
-symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) != MEM)
-    return 0;
-  op = XEXP (op, 0);
-  return ((GET_CODE (op) == SYMBOL_REF && !SYMBOL_REF_TLS_MODEL (op))
-         || GET_CODE (op) == CONST || GET_CODE (op) == HIGH
-         || GET_CODE (op) == LABEL_REF);
-}
-
-/* Return truth value of statement that OP is a LABEL_REF of mode MODE.  */
-
-int
-label_ref_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != LABEL_REF)
-    return 0;
-  if (GET_MODE (op) != mode)
-    return 0;
-  return 1;
-}
-
-/* Return 1 if the operand is an argument used in generating pic references
-   in either the medium/low or medium/anywhere code models of sparc64.  */
-
-int
-sp64_medium_pic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  /* Check for (const (minus (symbol_ref:GOT)
-                             (const (minus (label) (pc))))).  */
-  if (GET_CODE (op) != CONST)
-    return 0;
-  op = XEXP (op, 0);
-  if (GET_CODE (op) != MINUS)
-    return 0;
-  if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
-    return 0;
-  /* ??? Ensure symbol is GOT.  */
-  if (GET_CODE (XEXP (op, 1)) != CONST)
-    return 0;
-  if (GET_CODE (XEXP (XEXP (op, 1), 0)) != MINUS)
-    return 0;
-  return 1;
-}
+  /* Fixup PIC cases.  */
+  if (flag_pic && CONSTANT_P (operands[1]))
+    {
+      if (pic_address_needs_scratch (operands[1]))
+       operands[1] = legitimize_pic_address (operands[1], mode, 0);
+
+      /* VxWorks does not impose a fixed gap between segments; the run-time
+        gap can be different from the object-file gap.  We therefore can't
+        assume X - _GLOBAL_OFFSET_TABLE_ is a link-time constant unless we
+        are absolutely sure that X is in the same segment as the GOT.
+        Unfortunately, the flexibility of linker scripts means that we
+        can't be sure of that in general, so assume that _G_O_T_-relative
+        accesses are never valid on VxWorks.  */
+      if (GET_CODE (operands[1]) == LABEL_REF && !TARGET_VXWORKS_RTP)
+       {
+         if (mode == SImode)
+           {
+             emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
 
-/* Return 1 if the operand is a data segment reference.  This includes
-   the readonly data segment, or in other words anything but the text segment.
-   This is needed in the medium/anywhere code model on v9.  These values
-   are accessed with EMBMEDANY_BASE_REG.  */
+         if (mode == DImode)
+           {
+             gcc_assert (TARGET_ARCH64);
+             emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
+             return true;
+           }
+       }
 
-int
-data_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF :
-      return ! SYMBOL_REF_FUNCTION_P (op);
-    case PLUS :
-      /* Assume canonical format of symbol + constant.
-        Fall through.  */
-    case CONST :
-      return data_segment_operand (XEXP (op, 0), VOIDmode);
-    default :
-      return 0;
+      if (symbolic_operand (operands[1], mode))
+       {
+         operands[1] = legitimize_pic_address (operands[1],
+                                               mode,
+                                               (reload_in_progress ?
+                                                operands[0] :
+                                                NULL_RTX));
+         return false;
+       }
     }
-}
-
-/* Return 1 if the operand is a text segment reference.
-   This is needed in the medium/anywhere code model on v9.  */
 
-int
-text_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
+  /* If we are trying to toss an integer constant into FP registers,
+     or loading a FP or vector constant, force it into memory.  */
+  if (CONSTANT_P (operands[1])
+      && REG_P (operands[0])
+      && (SPARC_FP_REG_P (REGNO (operands[0]))
+         || SCALAR_FLOAT_MODE_P (mode)
+         || VECTOR_MODE_P (mode)))
     {
-    case LABEL_REF :
-      return 1;
-    case SYMBOL_REF :
-      return SYMBOL_REF_FUNCTION_P (op);
-    case PLUS :
-      /* Assume canonical format of symbol + constant.
-        Fall through.  */
-    case CONST :
-      return text_segment_operand (XEXP (op, 0), VOIDmode);
-    default :
-      return 0;
-    }
-}
-
-/* Return 1 if the operand is either a register or a memory operand that is
-   not symbolic.  */
-
-int
-reg_or_nonsymb_mem_operand (register rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-
-  if (memory_operand (op, mode) && ! symbolic_memory_operand (op, mode))
-    return 1;
-
-  return 0;
-}
-
-int
-splittable_symbolic_memory_operand (rtx op,
-                                   enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (! symbolic_operand (XEXP (op, 0), Pmode))
-    return 0;
-  return 1;
-}
-
-int
-splittable_immediate_memory_operand (rtx op,
-                                    enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (! immediate_operand (XEXP (op, 0), Pmode))
-    return 0;
-  return 1;
-}
-
-/* Return truth value of whether OP is EQ or NE.  */
-
-int
-eq_or_neq (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
-}
-
-/* Return 1 if this is a comparison operator, but not an EQ, NE, GEU,
-   or LTU for non-floating-point.  We handle those specially.  */
-
-int
-normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code;
-
-  if (!COMPARISON_P (op))
-    return 0;
+      /* emit_group_store will send such bogosity to us when it is
+         not storing directly into memory.  So fix this up to avoid
+         crashes in output_constant_pool.  */
+      if (operands [1] == const0_rtx)
+       operands[1] = CONST0_RTX (mode);
 
-  if (GET_MODE (XEXP (op, 0)) == CCFPmode
-      || GET_MODE (XEXP (op, 0)) == CCFPEmode)
-    return 1;
-
-  code = GET_CODE (op);
-  return (code != NE && code != EQ && code != GEU && code != LTU);
-}
-
-/* Return 1 if this is a comparison operator.  This allows the use of
-   MATCH_OPERATOR to recognize all the branch insns.  */
-
-int
-noov_compare_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code;
-
-  if (!COMPARISON_P (op))
-    return 0;
-
-  code = GET_CODE (op);
-  if (GET_MODE (XEXP (op, 0)) == CC_NOOVmode
-      || GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
-    /* These are the only branches which work with CC_NOOVmode.  */
-    return (code == EQ || code == NE || code == GE || code == LT);
-  return 1;
-}
-
-/* Return 1 if this is a 64-bit comparison operator.  This allows the use of
-   MATCH_OPERATOR to recognize all the branch insns.  */
-
-int
-noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code;
-
-  if (! TARGET_V9)
-    return 0;
-
-  if (!COMPARISON_P (op))
-    return 0;
-
-  code = GET_CODE (op);
-  if (GET_MODE (XEXP (op, 0)) == CCX_NOOVmode)
-    /* These are the only branches which work with CCX_NOOVmode.  */
-    return (code == EQ || code == NE || code == GE || code == LT);
-  return (GET_MODE (XEXP (op, 0)) == CCXmode);
-}
-
-/* Nonzero if OP is a comparison operator suitable for use in v9
-   conditional move or branch on register contents instructions.  */
-
-int
-v9_regcmp_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code;
-
-  if (!COMPARISON_P (op))
-    return 0;
-
-  code = GET_CODE (op);
-  return v9_regcmp_p (code);
-}
-
-/* Return 1 if this is a SIGN_EXTEND or ZERO_EXTEND operation.  */
-
-int
-extend_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
-}
-
-/* Return nonzero if OP is an operator of mode MODE which can set
-   the condition codes explicitly.  We do not include PLUS and MINUS
-   because these require CC_NOOVmode, which we handle explicitly.  */
-
-int
-cc_arithop (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == AND
-      || GET_CODE (op) == IOR
-      || GET_CODE (op) == XOR)
-    return 1;
-
-  return 0;
-}
-
-/* Return nonzero if OP is an operator of mode MODE which can bitwise
-   complement its second operand and set the condition codes explicitly.  */
-
-int
-cc_arithopn (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  /* XOR is not here because combine canonicalizes (xor (not ...) ...)
-     and (xor ... (not ...)) to (not (xor ...)).  */
-  return (GET_CODE (op) == AND
-         || GET_CODE (op) == IOR);
-}
-\f
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 13 bit immediate field.  This is an acceptable SImode operand for
-   most 3 address instructions.  */
-
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  return SMALL_INT32 (op);
-}
-
-/* Return true if OP is a constant 4096  */
-
-int
-arith_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  else
-    return INTVAL (op) == 4096;
-}
-
-/* Return true if OP is suitable as second operand for add/sub */
-
-int
-arith_add_operand (rtx op, enum machine_mode mode)
-{
-  return arith_operand (op, mode) || arith_4096_operand (op, mode);
-}
-
-/* Return true if OP is a CONST_INT or a CONST_DOUBLE which can fit in the
-   immediate field of OR and XOR instructions.  Used for 64-bit
-   constant formation patterns.  */
-int
-const64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return ((GET_CODE (op) == CONST_INT
-          && SPARC_SIMM13_P (INTVAL (op)))
-#if HOST_BITS_PER_WIDE_INT != 64
-         || (GET_CODE (op) == CONST_DOUBLE
-             && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
-             && (CONST_DOUBLE_HIGH (op) ==
-                 ((CONST_DOUBLE_LOW (op) & 0x80000000) != 0 ?
-                  (HOST_WIDE_INT)-1 : 0)))
-#endif
-         );
-}
-
-/* The same, but only for sethi instructions.  */
-int
-const64_high_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT
-          && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
-          && SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
-          )
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && (CONST_DOUBLE_LOW (op) & ~(HOST_WIDE_INT)0x3ff) != 0
-             && SPARC_SETHI_P (CONST_DOUBLE_LOW (op))));
-}
-
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 11 bit immediate field.  This is an acceptable SImode operand for
-   the movcc instructions.  */
-
-int
-arith11_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
-}
-
-/* Return true if OP is a register, or is a CONST_INT that can fit in a
-   signed 10 bit immediate field.  This is an acceptable SImode operand for
-   the movrcc instructions.  */
-
-int
-arith10_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
-}
-
-/* Return true if OP is a register, is a CONST_INT that fits in a 13 bit
-   immediate field, or is a CONST_DOUBLE whose both parts fit in a 13 bit
-   immediate field.
-   ARCH64: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
-   can fit in a 13 bit immediate field.  This is an acceptable DImode operand
-   for most 3 address instructions.  */
-
-int
-arith_double_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && SMALL_INT (op))
-         || (! TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_HIGH (op) + 0x1000) < 0x2000)
-         || (TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x1000) < 0x2000
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x1000) == 0x1000)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
-}
-
-/* Return true if OP is a constant 4096 for DImode on ARCH64 */
-
-int
-arith_double_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (TARGET_ARCH64 &&
-         ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
-          (GET_CODE (op) == CONST_DOUBLE &&
-           CONST_DOUBLE_LOW (op) == 4096 &&
-           CONST_DOUBLE_HIGH (op) == 0)));
-}
-
-/* Return true if OP is suitable as second operand for add/sub in DImode */
-
-int
-arith_double_add_operand (rtx op, enum machine_mode mode)
-{
-  return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
-   can fit in an 11 bit immediate field.  This is an acceptable DImode
-   operand for the movcc instructions.  */
-/* ??? Replace with arith11_operand?  */
-
-int
-arith11_double_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (CONST_DOUBLE_LOW (op) + 0x400) < 0x800
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x400) == 0x400)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x400) == 0)))
-         || (GET_CODE (op) == CONST_INT
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x400) < 0x800));
-}
-
-/* Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
-   can fit in an 10 bit immediate field.  This is an acceptable DImode
-   operand for the movrcc instructions.  */
-/* ??? Replace with arith10_operand?  */
-
-int
-arith10_double_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned) (CONST_DOUBLE_LOW (op) + 0x200) < 0x400
-             && ((CONST_DOUBLE_HIGH (op) == -1
-                  && (CONST_DOUBLE_LOW (op) & 0x200) == 0x200)
-                 || (CONST_DOUBLE_HIGH (op) == 0
-                     && (CONST_DOUBLE_LOW (op) & 0x200) == 0)))
-         || (GET_CODE (op) == CONST_INT
-             && (GET_MODE (op) == mode || GET_MODE (op) == VOIDmode)
-             && (unsigned HOST_WIDE_INT) (INTVAL (op) + 0x200) < 0x400));
-}
-
-/* Return truth value of whether OP is an integer which fits the
-   range constraining immediate operands in most three-address insns,
-   which have a 13 bit immediate field.  */
-
-int
-small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
-}
-
-int
-small_int_or_double (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return ((GET_CODE (op) == CONST_INT && SMALL_INT (op))
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))));
-}
-
-/* Recognize operand values for the umul instruction.  That instruction sign
-   extends immediate values just like all other sparc instructions, but
-   interprets the extended result as an unsigned number.  */
-
-int
-uns_small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-#if HOST_BITS_PER_WIDE_INT > 32
-  /* All allowed constants will fit a CONST_INT.  */
-  return (GET_CODE (op) == CONST_INT
-         && ((INTVAL (op) >= 0 && INTVAL (op) < 0x1000)
-             || (INTVAL (op) >= 0xFFFFF000
-                  && INTVAL (op) <= 0xFFFFFFFF)));
-#else
-  return ((GET_CODE (op) == CONST_INT && (unsigned) INTVAL (op) < 0x1000)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0
-             && (unsigned) CONST_DOUBLE_LOW (op) - 0xFFFFF000 < 0x1000));
-#endif
-}
-
-int
-uns_arith_operand (rtx op, enum machine_mode mode)
-{
-  return register_operand (op, mode) || uns_small_int (op, mode);
-}
-
-/* Return truth value of statement that OP is a call-clobbered register.  */
-int
-clobbered_register (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
-}
-
-/* Return 1 if OP is a valid operand for the source of a move insn.  */
-
-int
-input_operand (rtx op, enum machine_mode mode)
-{
-  /* If both modes are non-void they must be the same.  */
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  /* Allow any one instruction integer constant, and all CONST_INT
-     variants when we are working in DImode and !arch64.  */
-  if (GET_MODE_CLASS (mode) == MODE_INT
-      && ((GET_CODE (op) == CONST_INT
-          && (SPARC_SETHI_P (INTVAL (op) & GET_MODE_MASK (mode))
-              || SPARC_SIMM13_P (INTVAL (op))
-              || (mode == DImode
-                  && ! TARGET_ARCH64)))
-         || (TARGET_ARCH64
-             && GET_CODE (op) == CONST_DOUBLE
-             && ((CONST_DOUBLE_HIGH (op) == 0
-                  && SPARC_SETHI_P (CONST_DOUBLE_LOW (op)))
-                 ||
-#if HOST_BITS_PER_WIDE_INT == 64
-                 (CONST_DOUBLE_HIGH (op) == 0
-                  && SPARC_SIMM13_P (CONST_DOUBLE_LOW (op)))
-#else
-                 (SPARC_SIMM13_P (CONST_DOUBLE_LOW (op))
-                  && (((CONST_DOUBLE_LOW (op) & 0x80000000) == 0
-                       && CONST_DOUBLE_HIGH (op) == 0)
-                      || (CONST_DOUBLE_HIGH (op) == -1
-                          && CONST_DOUBLE_LOW (op) & 0x80000000) != 0))
-#endif
-                 ))))
-    return 1;
-
-  /* If !arch64 and this is a DImode const, allow it so that
-     the splits can be generated.  */
-  if (! TARGET_ARCH64
-      && mode == DImode
-      && GET_CODE (op) == CONST_DOUBLE)
-    return 1;
+      /* We can clear FP registers if TARGET_VIS, and always other regs.  */
+      if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG)
+         && const_zero_operand (operands[1], mode))
+       return false;
 
-  if (register_operand (op, mode))
-    return 1;
+      if (REGNO (operands[0]) < SPARC_FIRST_FP_REG
+         /* We are able to build any SF constant in integer registers
+            with at most 2 instructions.  */
+         && (mode == SFmode
+             /* And any DF constant in integer registers.  */
+             || (mode == DFmode
+                 && (reload_completed || reload_in_progress))))
+       return false;
 
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT
-      && GET_CODE (op) == CONST_DOUBLE)
-    return 1;
+      operands[1] = force_const_mem (mode, operands[1]);
+      if (!reload_in_progress)
+       operands[1] = validize_mem (operands[1]);
+      return false;
+    }
 
-  /* If this is a SUBREG, look inside so that we handle
-     paradoxical ones.  */
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
+  /* Accept non-constants and valid constants unmodified.  */
+  if (!CONSTANT_P (operands[1])
+      || GET_CODE (operands[1]) == HIGH
+      || input_operand (operands[1], mode))
+    return false;
 
-  /* Check for valid MEM forms.  */
-  if (GET_CODE (op) == MEM)
+  switch (mode)
     {
-      rtx inside = XEXP (op, 0);
+    case QImode:
+      /* All QImode constants require only one insn, so proceed.  */
+      break;
 
-      if (GET_CODE (inside) == LO_SUM)
-       {
-         /* We can't allow these because all of the splits
-            (eventually as they trickle down into DFmode
-            splits) require offsettable memory references.  */
-         if (! TARGET_V9
-             && GET_MODE (op) == TFmode)
-           return 0;
+    case HImode:
+    case SImode:
+      sparc_emit_set_const32 (operands[0], operands[1]);
+      return true;
 
-         return (register_operand (XEXP (inside, 0), Pmode)
-                 && CONSTANT_P (XEXP (inside, 1)));
-       }
-      return memory_address_p (mode, inside);
+    case DImode:
+      /* input_operand should have filtered out 32-bit mode.  */
+      sparc_emit_set_const64 (operands[0], operands[1]);
+      return true;
+    
+    default:
+      gcc_unreachable ();
     }
 
-  return 0;
+  return false;
 }
 
-/* Return 1 if OP is valid for the lhs of a compare insn.  */
+/* Load OP1, a 32-bit constant, into OP0, a register.
+   We know it can't be done in one insn when we get
+   here, the move expander guarantees this.  */
 
-int
-compare_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == ZERO_EXTRACT)
-    return (register_operand (XEXP (op, 0), mode)
-           && small_int_or_double (XEXP (op, 1), mode)
-           && small_int_or_double (XEXP (op, 2), mode)
-           /* This matches cmp_zero_extract.  */
-           && ((mode == SImode
-                && ((GET_CODE (XEXP (op, 2)) == CONST_INT
-                     && INTVAL (XEXP (op, 2)) > 19)
-                    || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
-                        && CONST_DOUBLE_LOW (XEXP (op, 2)) > 19)))
-               /* This matches cmp_zero_extract_sp64.  */
-               || (mode == DImode
-                   && TARGET_ARCH64
-                   && ((GET_CODE (XEXP (op, 2)) == CONST_INT
-                        && INTVAL (XEXP (op, 2)) > 51)
-                       || (GET_CODE (XEXP (op, 2)) == CONST_DOUBLE
-                           && CONST_DOUBLE_LOW (XEXP (op, 2)) > 51)))));
-  else
-    return register_operand (op, mode);
-}
-
-\f
-/* We know it can't be done in one insn when we get here,
-   the movsi expander guarantees this.  */
 void
 sparc_emit_set_const32 (rtx op0, rtx op1)
-{
-  enum machine_mode mode = GET_MODE (op0);
-  rtx temp;
-
-  if (GET_CODE (op1) == CONST_INT)
-    {
-      HOST_WIDE_INT value = INTVAL (op1);
-
-      if (SPARC_SETHI_P (value & GET_MODE_MASK (mode))
-         || SPARC_SIMM13_P (value))
-       abort ();
-    }
+{
+  enum machine_mode mode = GET_MODE (op0);
+  rtx temp;
 
-  /* Full 2-insn decomposition is needed.  */
   if (reload_in_progress || reload_completed)
     temp = op0;
   else
@@ -1609,20 +1129,15 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
 
   if (GET_CODE (op1) == CONST_INT)
     {
+      gcc_assert (!small_int_operand (op1, mode)
+                 && !const_high_operand (op1, mode));
+
       /* Emit them as real moves instead of a HIGH/LO_SUM,
         this way CSE can see everything and reuse intermediate
         values if it wants.  */
-      if (TARGET_ARCH64
-         && HOST_BITS_PER_WIDE_INT != 64
-         && (INTVAL (op1) & 0x80000000) != 0)
-       emit_insn (gen_rtx_SET
-                  (VOIDmode, temp,
-                   immed_double_const (INTVAL (op1) & ~(HOST_WIDE_INT)0x3ff,
-                                       0, DImode)));
-      else
-       emit_insn (gen_rtx_SET (VOIDmode, temp,
-                               GEN_INT (INTVAL (op1)
-                                        & ~(HOST_WIDE_INT)0x3ff)));
+      emit_insn (gen_rtx_SET (VOIDmode, temp,
+                             GEN_INT (INTVAL (op1)
+                               & ~(HOST_WIDE_INT)0x3ff)));
 
       emit_insn (gen_rtx_SET (VOIDmode,
                              op0,
@@ -1636,17 +1151,16 @@ sparc_emit_set_const32 (rtx op0, rtx op1)
                              gen_rtx_HIGH (mode, op1)));
       emit_insn (gen_rtx_SET (VOIDmode,
                              op0, gen_rtx_LO_SUM (mode, temp, op1)));
-
     }
 }
 
-\f
 /* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
-   If TEMP is non-zero, we are forbidden to use any other scratch
+   If TEMP is nonzero, we are forbidden to use any other scratch
    registers.  Otherwise, we are allowed to generate them as needed.
 
    Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
    or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns).  */
+
 void
 sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
@@ -1737,10 +1251,8 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
             it TImode).  Pick the other one to use as our scratch.  */
          if (rtx_equal_p (temp, op0))
            {
-             if (ti_temp)
-               temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
-             else
-               abort();
+             gcc_assert (ti_temp);
+             temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
            }
          temp1 = op0;
          temp2 = temp;  /* op0 is _not_ allowed, see above.  */
@@ -1811,10 +1323,8 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
                 it TImode).  Pick the other one to use as our scratch.  */
              if (rtx_equal_p (temp, op0))
                {
-                 if (ti_temp)
-                   temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
-                 else
-                   abort();
+                 gcc_assert (ti_temp);
+                 temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
                }
              temp1 = op0;
              temp2 = temp;  /* op0 is _not_ allowed, see above.  */
@@ -1843,56 +1353,52 @@ sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
       break;
 
     default:
-      abort();
+      gcc_unreachable ();
     }
 }
 
+#if HOST_BITS_PER_WIDE_INT == 32
+void
+sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
+{
+  gcc_unreachable ();
+}
+#else
 /* These avoid problems when cross compiling.  If we do not
    go through all this hair then the optimizer will see
    invalid REG_EQUAL notes or in some cases none at all.  */
-static void sparc_emit_set_safe_HIGH64 (rtx, HOST_WIDE_INT);
+static rtx gen_safe_HIGH64 (rtx, HOST_WIDE_INT);
 static rtx gen_safe_SET64 (rtx, HOST_WIDE_INT);
 static rtx gen_safe_OR64 (rtx, HOST_WIDE_INT);
 static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
 
-#if HOST_BITS_PER_WIDE_INT == 64
-#define GEN_HIGHINT64(__x)             GEN_INT ((__x) & ~(HOST_WIDE_INT)0x3ff)
-#define GEN_INT64(__x)                 GEN_INT (__x)
-#else
-#define GEN_HIGHINT64(__x) \
-       immed_double_const ((__x) & ~(HOST_WIDE_INT)0x3ff, 0, DImode)
-#define GEN_INT64(__x) \
-       immed_double_const ((__x) & 0xffffffff, \
-                           ((__x) & 0x80000000 ? -1 : 0), DImode)
-#endif
-
 /* The optimizer is not to assume anything about exactly
    which bits are set for a HIGH, they are unspecified.
    Unfortunately this leads to many missed optimizations
    during CSE.  We mask out the non-HIGH bits, and matches
    a plain movdi, to alleviate this problem.  */
-static void
-sparc_emit_set_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
+static rtx
+gen_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
 {
-  emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val)));
+  return gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff));
 }
 
 static rtx
 gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
 {
-  return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
+  return gen_rtx_SET (VOIDmode, dest, GEN_INT (val));
 }
 
 static rtx
 gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
 {
-  return gen_rtx_IOR (DImode, src, GEN_INT64 (val));
+  return gen_rtx_IOR (DImode, src, GEN_INT (val));
 }
 
 static rtx
 gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
 {
-  return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
+  return gen_rtx_XOR (DImode, src, GEN_INT (val));
 }
 
 /* Worker routines for 64-bit constant formation on arch64.
@@ -1917,7 +1423,7 @@ sparc_emit_set_const64_quick1 (rtx op0, rtx temp,
   else
     high_bits = low_bits;
 
-  sparc_emit_set_safe_HIGH64 (temp, high_bits);
+  emit_insn (gen_safe_HIGH64 (temp, high_bits));
   if (!is_neg)
     {
       emit_insn (gen_rtx_SET (VOIDmode, op0,
@@ -1956,7 +1462,7 @@ sparc_emit_set_const64_quick2 (rtx op0, rtx temp,
 
   if ((high_bits & 0xfffffc00) != 0)
     {
-      sparc_emit_set_safe_HIGH64 (temp, high_bits);
+      emit_insn (gen_safe_HIGH64 (temp, high_bits));
       if ((high_bits & ~0xfffffc00) != 0)
        emit_insn (gen_rtx_SET (VOIDmode, op0,
                                gen_safe_OR64 (temp, (high_bits & 0x3ff))));
@@ -2000,7 +1506,7 @@ sparc_emit_set_const64_longway (rtx op0, rtx temp,
 
   if ((high_bits & 0xfffffc00) != 0)
     {
-      sparc_emit_set_safe_HIGH64 (temp, high_bits);
+      emit_insn (gen_safe_HIGH64 (temp, high_bits));
       if ((high_bits & ~0xfffffc00) != 0)
        emit_insn (gen_rtx_SET (VOIDmode,
                                sub_temp,
@@ -2024,7 +1530,7 @@ sparc_emit_set_const64_longway (rtx op0, rtx temp,
                              gen_rtx_ASHIFT (DImode, sub_temp,
                                              GEN_INT (32))));
 
-      sparc_emit_set_safe_HIGH64 (temp2, low_bits);
+      emit_insn (gen_safe_HIGH64 (temp2, low_bits));
       if ((low_bits & ~0xfffffc00) != 0)
        {
          emit_insn (gen_rtx_SET (VOIDmode, temp3,
@@ -2131,9 +1637,7 @@ analyze_64bit_constant (unsigned HOST_WIDE_INT high_bits,
     }
   /* If there are no bits set this should have gone out
      as one instruction!  */
-  if (lowest_bit_set == -1
-      || highest_bit_set == -1)
-    abort ();
+  gcc_assert (lowest_bit_set != -1 && highest_bit_set != -1);
   all_bits_between_are_set = 1;
   for (i = lowest_bit_set; i <= highest_bit_set; i++)
     {
@@ -2203,8 +1707,7 @@ create_simple_focus_bits (unsigned HOST_WIDE_INT high_bits,
       lo = 0;
       hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
     }
-  if (hi & lo)
-    abort ();
+  gcc_assert (! (hi & lo));
   return (hi | lo);
 }
 
@@ -2221,22 +1724,14 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
   rtx temp = 0;
 
   /* Sanity check that we know what we are working with.  */
-  if (! TARGET_ARCH64)
-    abort ();
-
-  if (GET_CODE (op0) != SUBREG)
-    {
-      if (GET_CODE (op0) != REG
-         || (REGNO (op0) >= SPARC_FIRST_FP_REG
-             && REGNO (op0) <= SPARC_LAST_V9_FP_REG))
-       abort ();
-    }
+  gcc_assert (TARGET_ARCH64
+             && (GET_CODE (op0) == SUBREG
+                 || (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0)))));
 
   if (reload_in_progress || reload_completed)
     temp = op0;
 
-  if (GET_CODE (op1) != CONST_DOUBLE
-      && GET_CODE (op1) != CONST_INT)
+  if (GET_CODE (op1) != CONST_INT)
     {
       sparc_emit_set_symbolic_const64 (op0, op1, temp);
       return;
@@ -2245,28 +1740,8 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
   if (! temp)
     temp = gen_reg_rtx (DImode);
 
-  if (GET_CODE (op1) == CONST_DOUBLE)
-    {
-#if HOST_BITS_PER_WIDE_INT == 64
-      high_bits = (CONST_DOUBLE_LOW (op1) >> 32) & 0xffffffff;
-      low_bits  = CONST_DOUBLE_LOW (op1) & 0xffffffff;
-#else
-      high_bits = CONST_DOUBLE_HIGH (op1);
-      low_bits = CONST_DOUBLE_LOW (op1);
-#endif
-    }
-  else
-    {
-#if HOST_BITS_PER_WIDE_INT == 64
-      high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
-      low_bits = (INTVAL (op1) & 0xffffffff);
-#else
-      high_bits = ((INTVAL (op1) < 0) ?
-                  0xffffffff :
-                  0x00000000);
-      low_bits = INTVAL (op1);
-#endif
-    }
+  high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
+  low_bits = (INTVAL (op1) & 0xffffffff);
 
   /* low_bits  bits 0  --> 31
      high_bits bits 32 --> 63  */
@@ -2305,8 +1780,8 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
       else if (lowest_bit_set == 0)
        shift = -(63 - highest_bit_set);
 
-      if (! SPARC_SIMM13_P (the_const))
-       abort ();
+      gcc_assert (SPARC_SIMM13_P (the_const));
+      gcc_assert (shift != 0);
 
       emit_insn (gen_safe_SET64 (temp, the_const));
       if (shift > 0)
@@ -2321,8 +1796,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
                                gen_rtx_LSHIFTRT (DImode,
                                                  temp,
                                                  GEN_INT (-shift))));
-      else
-       abort ();
       return;
     }
 
@@ -2338,10 +1811,10 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
        create_simple_focus_bits (high_bits, low_bits,
                                  lowest_bit_set, 10);
 
-      if (! SPARC_SETHI_P (focus_bits))
-        abort ();
+      gcc_assert (SPARC_SETHI_P (focus_bits));
+      gcc_assert (lowest_bit_set != 10);
 
-      sparc_emit_set_safe_HIGH64 (temp, focus_bits);
+      emit_insn (gen_safe_HIGH64 (temp, focus_bits));
 
       /* If lowest_bit_set == 10 then a sethi alone could have done it.  */
       if (lowest_bit_set < 10)
@@ -2354,8 +1827,6 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
                                op0,
                                gen_rtx_ASHIFT (DImode, temp,
                                                GEN_INT (lowest_bit_set - 10))));
-      else
-       abort ();
       return;
     }
 
@@ -2398,26 +1869,20 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
          || (((~high_bits) & 0xffffffff) == 0xffffffff
              && ((~low_bits) & 0x80000000) != 0))
        {
-         int fast_int = (~low_bits & 0xffffffff);
+         unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff);
 
          if ((SPARC_SETHI_P (fast_int)
               && (~high_bits & 0xffffffff) == 0)
              || SPARC_SIMM13_P (fast_int))
            emit_insn (gen_safe_SET64 (temp, fast_int));
          else
-           sparc_emit_set_const64 (temp, GEN_INT64 (fast_int));
+           sparc_emit_set_const64 (temp, GEN_INT (fast_int));
        }
       else
        {
          rtx negated_const;
-#if HOST_BITS_PER_WIDE_INT == 64
          negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
                                   (((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
-#else
-         negated_const = immed_double_const ((~low_bits) & 0xfffffc00,
-                                             (~high_bits) & 0xffffffff,
-                                             DImode);
-#endif
          sparc_emit_set_const64 (temp, negated_const);
        }
 
@@ -2453,9 +1918,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
                                  lowest_bit_set, 0);
 
       /* We can't get here in this state.  */
-      if (highest_bit_set < 32
-         || lowest_bit_set >= 32)
-       abort ();
+      gcc_assert (highest_bit_set >= 32 && lowest_bit_set < 32);
 
       /* So what we know is that the set bits straddle the
         middle of the 64-bit word.  */
@@ -2484,6 +1947,7 @@ sparc_emit_set_const64 (rtx op0, rtx op1)
 #endif
   sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
 }
+#endif /* HOST_BITS_PER_WIDE_INT == 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,
@@ -2517,7 +1981,7 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
          return CCFPEmode;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
   else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
@@ -2541,11 +2005,20 @@ select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
    return the rtx for the cc reg in the proper mode.  */
 
 rtx
-gen_compare_reg (enum rtx_code code, rtx x, rtx y)
+gen_compare_reg (enum rtx_code code)
 {
+  rtx x = sparc_compare_op0;
+  rtx y = sparc_compare_op1;
   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
   rtx cc_reg;
 
+  if (sparc_compare_emitted != NULL_RTX)
+    {
+      cc_reg = sparc_compare_emitted;
+      sparc_compare_emitted = NULL_RTX;
+      return cc_reg;
+    }
+
   /* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
      fcc regs (cse can't tell they're really call clobbered regs and will
      remove a duplicate comparison even if there is an intervening function
@@ -2624,22 +2097,20 @@ gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 int
 gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
 {
-  rtx temp, op0, op1;
-
   if (! TARGET_ARCH64
       && (GET_MODE (sparc_compare_op0) == DImode
          || GET_MODE (operands[0]) == DImode))
     return 0;
 
-  op0 = sparc_compare_op0;
-  op1 = sparc_compare_op1;
-
   /* Try to use the movrCC insns.  */
   if (TARGET_ARCH64
-      && GET_MODE_CLASS (GET_MODE (op0)) == MODE_INT
-      && op1 == const0_rtx
+      && GET_MODE_CLASS (GET_MODE (sparc_compare_op0)) == MODE_INT
+      && sparc_compare_op1 == const0_rtx
       && v9_regcmp_p (compare_code))
     {
+      rtx op0 = sparc_compare_op0;
+      rtx temp;
+
       /* Special case for op0 != 0.  This can be done with one instruction if
         operands[0] == sparc_compare_op0.  */
 
@@ -2682,7 +2153,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
     }
   else
     {
-      operands[1] = gen_compare_reg (compare_code, op0, op1);
+      operands[1] = gen_compare_reg (compare_code);
 
       switch (GET_MODE (operands[1]))
        {
@@ -2692,7 +2163,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
          case CCFPmode :
            break;
          default :
-           abort ();
+           gcc_unreachable ();
        }
       emit_insn (gen_rtx_SET (VOIDmode, operands[0], const0_rtx));
       emit_insn (gen_rtx_SET (VOIDmode, operands[0],
@@ -2712,6 +2183,7 @@ gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
 void
 emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
 {
+  gcc_assert (sparc_compare_emitted == NULL_RTX);
   emit_jump_insn (gen_rtx_SET (VOIDmode,
                           pc_rtx,
                           gen_rtx_IF_THEN_ELSE (VOIDmode,
@@ -2746,8 +2218,7 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
   int i;
 
   /* We only expect to be called for conversions, unary, and binary ops.  */
-  if (nargs < 2 || nargs > 3)
-    abort ();
+  gcc_assert (nargs == 2 || nargs == 3);
 
   for (i = 0; i < nargs; ++i)
     {
@@ -2810,8 +2281,7 @@ emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
     {
       rtx ret;
 
-      if (nargs != 2)
-       abort ();
+      gcc_assert (nargs == 2);
 
       ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
                                     GET_MODE (operands[0]), 1,
@@ -2844,7 +2314,7 @@ emit_soft_tfmode_binop (enum rtx_code code, rtx *operands)
       func = "_Qp_div";
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   emit_soft_tfmode_libcall (func, 3, operands);
@@ -2855,14 +2325,8 @@ emit_soft_tfmode_unop (enum rtx_code code, rtx *operands)
 {
   const char *func;
 
-  switch (code)
-    {
-    case SQRT:
-      func = "_Qp_sqrt";
-      break;
-    default:
-      abort ();
-    }
+  gcc_assert (code == SQRT);
+  func = "_Qp_sqrt";
 
   emit_soft_tfmode_libcall (func, 2, operands);
 }
@@ -2884,7 +2348,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_dtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2898,7 +2362,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_qtod";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2912,7 +2376,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_xtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2926,7 +2390,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_uxtoq";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2940,7 +2404,7 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_qtox";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
@@ -2954,12 +2418,12 @@ emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
          func = "_Qp_qtoux";
          break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   emit_soft_tfmode_libcall (func, 2, operands);
@@ -3048,26 +2512,34 @@ empty_delay_slot (rtx insn)
 int
 tls_call_delay (rtx trial)
 {
-  rtx pat, unspec;
+  rtx pat;
 
   /* Binutils allows
-     call __tls_get_addr, %tgd_call (foo)
-      add %l7, %o0, %o0, %tgd_add (foo)
+       call __tls_get_addr, %tgd_call (foo)
+        add %l7, %o0, %o0, %tgd_add (foo)
      while Sun as/ld does not.  */
   if (TARGET_GNU_TLS || !TARGET_TLS)
     return 1;
 
   pat = PATTERN (trial);
-  if (GET_CODE (pat) != SET || GET_CODE (SET_DEST (pat)) != PLUS)
-    return 1;
 
-  unspec = XEXP (SET_DEST (pat), 1);
-  if (GET_CODE (unspec) != UNSPEC
-      || (XINT (unspec, 1) != UNSPEC_TLSGD
-         && XINT (unspec, 1) != UNSPEC_TLSLDM))
-    return 1;
+  /* We must reject tgd_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
+     and tldm_add{32|64}, i.e.
+       (set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
+     for Sun as/ld.  */
+  if (GET_CODE (pat) == SET
+      && GET_CODE (SET_SRC (pat)) == PLUS)
+    {
+      rtx unspec = XEXP (SET_SRC (pat), 1);
 
-  return 0;
+      if (GET_CODE (unspec) == UNSPEC
+         && (XINT (unspec, 1) == UNSPEC_TLSGD
+             || XINT (unspec, 1) == UNSPEC_TLSLDM))
+       return 0;
+    }
+
+  return 1;
 }
 
 /* Return nonzero if TRIAL, an insn, can be combined with a 'restore'
@@ -3152,7 +2624,6 @@ eligible_for_restore_insn (rtx trial, bool return_p)
 int
 eligible_for_return_delay (rtx trial)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@@ -3172,7 +2643,7 @@ eligible_for_return_delay (rtx trial)
     return 0;
 
   /* In the case of a true leaf function, anything can go into the slot.  */
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     return get_attr_in_uncond_branch_delay (trial)
           == IN_UNCOND_BRANCH_DELAY_TRUE;
 
@@ -3202,7 +2673,6 @@ eligible_for_return_delay (rtx trial)
 int
 eligible_for_sibcall_delay (rtx trial)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
   rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
@@ -3213,7 +2683,7 @@ eligible_for_sibcall_delay (rtx trial)
 
   pat = PATTERN (trial);
 
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
@@ -3298,6 +2768,7 @@ sparc_cannot_force_const_mem (rtx x)
     {
     case CONST_INT:
     case CONST_DOUBLE:
+    case CONST_VECTOR:
       /* Accept all non-symbolic constants.  */
       return false;
 
@@ -3322,17 +2793,16 @@ sparc_cannot_force_const_mem (rtx x)
     case UNSPEC:
       return true;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 \f
-/* The table we use to reference PIC data.  */
+/* PIC support.  */
+static GTY(()) char pic_helper_symbol_name[256];
+static GTY(()) rtx pic_helper_symbol;
+static GTY(()) bool pic_helper_emitted_p = false;
 static GTY(()) rtx global_offset_table;
 
-/* The function we use to get at it.  */
-static GTY(()) rtx add_pc_to_pic_symbol;
-static GTY(()) char add_pc_to_pic_symbol_name[256];
-
 /* Ensure that we are not using patterns that are not OK with PIC.  */
 
 int
@@ -3341,14 +2811,13 @@ check_pic (int i)
   switch (flag_pic)
     {
     case 1:
-      if (GET_CODE (recog_data.operand[i]) == SYMBOL_REF
-         || (GET_CODE (recog_data.operand[i]) == CONST
-             && ! (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
-                   && (XEXP (XEXP (recog_data.operand[i], 0), 0)
-                       == global_offset_table)
-                   && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
-                       == CONST))))
-       abort ();
+      gcc_assert (GET_CODE (recog_data.operand[i]) != SYMBOL_REF
+                 && (GET_CODE (recog_data.operand[i]) != CONST
+                 || (GET_CODE (XEXP (recog_data.operand[i], 0)) == MINUS
+                     && (XEXP (XEXP (recog_data.operand[i], 0), 0)
+                         == global_offset_table)
+                     && (GET_CODE (XEXP (XEXP (recog_data.operand[i], 0), 1))
+                         == CONST))));
     case 2:
     default:
       return 1;
@@ -3393,7 +2862,7 @@ legitimate_constant_p (rtx x)
       /* Offsets of TLS symbols are never valid.
         Discourage CSE from creating them.  */
       if (GET_CODE (inner) == PLUS
-         && tls_symbolic_operand (XEXP (inner, 0)))
+         && SPARC_SYMBOL_REF_TLS_P (XEXP (inner, 0)))
        return false;
       break;
 
@@ -3404,10 +2873,17 @@ legitimate_constant_p (rtx x)
       /* Floating point constants are generally not ok.
         The only exception is 0.0 in VIS.  */
       if (TARGET_VIS
-         && (GET_MODE (x) == SFmode
-             || GET_MODE (x) == DFmode
-             || GET_MODE (x) == TFmode)
-         && fp_zero_operand (x, GET_MODE (x)))
+         && SCALAR_FLOAT_MODE_P (GET_MODE (x))
+         && const_zero_operand (x, GET_MODE (x)))
+       return true;
+
+      return false;
+
+    case CONST_VECTOR:
+      /* Vector constants are generally not ok.
+        The only exception is 0 in VIS.  */
+      if (TARGET_VIS
+         && const_zero_operand (x, GET_MODE (x)))
        return true;
 
       return false;
@@ -3453,10 +2929,10 @@ legitimate_pic_operand_p (rtx x)
 {
   if (pic_address_needs_scratch (x))
     return false;
-  if (tls_symbolic_operand (x)
+  if (SPARC_SYMBOL_REF_TLS_P (x)
       || (GET_CODE (x) == CONST
          && GET_CODE (XEXP (x, 0)) == PLUS
-         && tls_symbolic_operand (XEXP (XEXP (x, 0), 0))))
+         && SPARC_SYMBOL_REF_TLS_P (XEXP (XEXP (x, 0), 0))))
     return false;
   return true;
 }
@@ -3467,7 +2943,7 @@ legitimate_pic_operand_p (rtx x)
 int
 legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
 {
-  rtx rs1 = NULL, rs2 = NULL, imm1 = NULL, imm2;
+  rtx rs1 = NULL, rs2 = NULL, imm1 = NULL;
 
   if (REG_P (addr) || GET_CODE (addr) == SUBREG)
     rs1 = addr;
@@ -3494,7 +2970,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
           && GET_CODE (rs2) != SUBREG
           && GET_CODE (rs2) != LO_SUM
           && GET_CODE (rs2) != MEM
-          && !tls_symbolic_operand (rs2)
+          && ! SPARC_SYMBOL_REF_TLS_P (rs2)
           && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
           && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
          || ((REG_P (rs1)
@@ -3507,15 +2983,14 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
       else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG)
               && (REG_P (rs2) || GET_CODE (rs2) == SUBREG))
        {
-         /* We prohibit REG + REG for TFmode when there are no instructions
-            which accept REG+REG instructions.  We do this because REG+REG
-            is not an offsetable address.  If we get the situation in reload
+         /* We prohibit REG + REG for TFmode when there are no quad move insns
+            and we consequently need to split.  We do this because REG+REG
+            is not an offsettable address.  If we get the situation in reload
             where source and destination of a movtf pattern are both MEMs with
             REG+REG address, then only one of them gets converted to an
-            offsetable address.  */
+            offsettable address.  */
          if (mode == TFmode
-             && !(TARGET_FPU && TARGET_ARCH64 && TARGET_V9
-                  && TARGET_HARD_QUAD))
+             && ! (TARGET_FPU && TARGET_ARCH64 && TARGET_HARD_QUAD))
            return 0;
 
          /* We prohibit REG + REG on ARCH32 if not optimizing for
@@ -3532,11 +3007,10 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
               && ! TARGET_CM_MEDMID
               && RTX_OK_FOR_OLO10_P (rs2))
        {
-         imm2 = rs2;
          rs2 = NULL;
          imm1 = XEXP (rs1, 1);
          rs1 = XEXP (rs1, 0);
-         if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+         if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
            return 0;
        }
     }
@@ -3545,12 +3019,12 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
       rs1 = XEXP (addr, 0);
       imm1 = XEXP (addr, 1);
 
-      if (! CONSTANT_P (imm1) || tls_symbolic_operand (rs1))
+      if (! CONSTANT_P (imm1) || SPARC_SYMBOL_REF_TLS_P (rs1))
        return 0;
 
-      /* We can't allow TFmode, because an offset greater than or equal to the
-         alignment (8) may cause the LO_SUM to overflow if !v9.  */
-      if (mode == TFmode && !TARGET_V9)
+      /* We can't allow TFmode in 32-bit mode, because an offset greater
+        than the alignment (8) may cause the LO_SUM to overflow.  */
+      if (mode == TFmode && TARGET_ARCH32)
        return 0;
     }
   else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
@@ -3594,6 +3068,7 @@ legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
 /* Construct the SYMBOL_REF for the tls_get_offset function.  */
 
 static GTY(()) rtx sparc_tls_symbol;
+
 static rtx
 sparc_tls_get_addr (void)
 {
@@ -3620,6 +3095,24 @@ sparc_tls_got (void)
   return temp;
 }
 
+/* Return 1 if *X is a thread-local symbol.  */
+
+static int
+sparc_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  return SPARC_SYMBOL_REF_TLS_P (*x);
+}
+
+/* Return 1 if X contains a thread-local symbol.  */
+
+bool
+sparc_tls_referenced_p (rtx x)
+{
+  if (!TARGET_HAVE_TLS)
+    return false;
+
+  return for_each_rtx (&x, &sparc_tls_symbol_ref_1, 0);
+}
 
 /* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
    this (thread-local) address.  */
@@ -3629,8 +3122,7 @@ legitimize_tls_address (rtx addr)
 {
   rtx temp1, temp2, temp3, ret, o0, got, insn;
 
-  if (no_new_pseudos)
-    abort ();
+  gcc_assert (can_create_pseudo_p ());
 
   if (GET_CODE (addr) == SYMBOL_REF)
     switch (SYMBOL_REF_TLS_MODEL (addr))
@@ -3746,11 +3238,11 @@ legitimize_tls_address (rtx addr)
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
       }
 
   else
-    abort ();  /* for now ... */
+    gcc_unreachable ();  /* for now ... */
 
   return ret;
 }
@@ -3765,17 +3257,17 @@ rtx
 legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
                        rtx reg)
 {
-  if (GET_CODE (orig) == SYMBOL_REF)
+  if (GET_CODE (orig) == SYMBOL_REF
+      /* See the comment in sparc_expand_move.  */
+      || (TARGET_VXWORKS_RTP && GET_CODE (orig) == LABEL_REF))
     {
       rtx pic_ref, address;
       rtx insn;
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
-           abort ();
-         else
-           reg = gen_reg_rtx (Pmode);
+         gcc_assert (! reload_in_progress && ! reload_completed);
+         reg = gen_reg_rtx (Pmode);
        }
 
       if (flag_pic == 2)
@@ -3790,15 +3282,15 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
             won't get confused into thinking that these two instructions
             are loading in the true address of the symbol.  If in the
             future a PIC rtx exists, that should be used instead.  */
-         if (Pmode == SImode)
+         if (TARGET_ARCH64)
            {
-             emit_insn (gen_movsi_high_pic (temp_reg, orig));
-             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movdi_high_pic (temp_reg, orig));
+             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          else
            {
-             emit_insn (gen_movdi_high_pic (temp_reg, orig));
-             emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
+             emit_insn (gen_movsi_high_pic (temp_reg, orig));
+             emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
            }
          address = temp_reg;
        }
@@ -3812,8 +3304,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
       insn = emit_move_insn (reg, pic_ref);
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
-                                 REG_NOTES (insn));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
       return reg;
     }
   else if (GET_CODE (orig) == CONST)
@@ -3826,20 +3317,14 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
-           abort ();
-         else
-           reg = gen_reg_rtx (Pmode);
+         gcc_assert (! reload_in_progress && ! reload_completed);
+         reg = gen_reg_rtx (Pmode);
        }
 
-      if (GET_CODE (XEXP (orig, 0)) == PLUS)
-       {
-         base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
-         offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
-                                        base == reg ? 0 : reg);
-       }
-      else
-       abort ();
+      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+      offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+                                      base == reg ? 0 : reg);
 
       if (GET_CODE (offset) == CONST_INT)
        {
@@ -3849,7 +3334,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
            offset = force_reg (Pmode, offset);
          else
            /* If we reach here, then something is seriously wrong.  */
-           abort ();
+           gcc_unreachable ();
        }
       return gen_rtx_PLUS (Pmode, base, offset);
     }
@@ -3891,7 +3376,7 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
   if (x != orig_x && legitimate_address_p (mode, x, FALSE))
     return x;
 
-  if (tls_symbolic_operand (x))
+  if (SPARC_SYMBOL_REF_TLS_P (x))
     x = legitimize_tls_address (x);
   else if (flag_pic)
     x = legitimize_pic_address (x, mode, 0);
@@ -3908,42 +3393,64 @@ legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
   return x;
 }
 
-/* Emit the special PIC prologue.  */
+/* Emit the special PIC helper function.  */
+
+static void
+emit_pic_helper (void)
+{
+  const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
+  int align;
+
+  switch_to_section (text_section);
+
+  align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  if (align > 0)
+    ASM_OUTPUT_ALIGN (asm_out_file, align);
+  ASM_OUTPUT_LABEL (asm_out_file, pic_helper_symbol_name);
+  if (flag_delayed_branch)
+    fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
+           pic_name, pic_name);
+  else
+    fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
+           pic_name, pic_name);
+
+  pic_helper_emitted_p = true;
+}
+
+/* Emit code to load the PIC register.  */
 
 static void
-load_pic_register (void)
+load_pic_register (bool delay_pic_helper)
 {
   int orig_flag_pic = flag_pic;
 
-  /* If we haven't emitted the special helper function, do so now.  */
-  if (add_pc_to_pic_symbol_name[0] == 0)
+  if (TARGET_VXWORKS_RTP)
     {
-      const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
-      int align;
-
-      ASM_GENERATE_INTERNAL_LABEL (add_pc_to_pic_symbol_name, "LADDPC", 0);
-      text_section ();
+      emit_insn (gen_vxworks_load_got ());
+      emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
+      return;
+    }
 
-      align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-      if (align > 0)
-       ASM_OUTPUT_ALIGN (asm_out_file, align);
-      ASM_OUTPUT_LABEL (asm_out_file, add_pc_to_pic_symbol_name);
-      if (flag_delayed_branch)
-       fprintf (asm_out_file, "\tjmp %%o7+8\n\t add\t%%o7, %s, %s\n",
-                pic_name, pic_name);
-      else
-       fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp %%o7+8\n\t nop\n",
-                pic_name, pic_name);
+  /* If we haven't initialized the special PIC symbols, do so now.  */
+  if (!pic_helper_symbol_name[0])
+    {
+      ASM_GENERATE_INTERNAL_LABEL (pic_helper_symbol_name, "LADDPC", 0);
+      pic_helper_symbol = gen_rtx_SYMBOL_REF (Pmode, pic_helper_symbol_name);
+      global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
     }
 
-  /* Initialize every time through, since we can't easily
-     know this to be permanent.  */
-  global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
-  add_pc_to_pic_symbol = gen_rtx_SYMBOL_REF (Pmode, add_pc_to_pic_symbol_name);
+  /* If we haven't emitted the special PIC helper function, do so now unless
+     we are requested to delay it.  */
+  if (!delay_pic_helper && !pic_helper_emitted_p)
+    emit_pic_helper ();
 
   flag_pic = 0;
-  emit_insn (gen_load_pcrel_sym (pic_offset_table_rtx, global_offset_table,
-                                add_pc_to_pic_symbol));
+  if (TARGET_ARCH64)
+    emit_insn (gen_load_pcrel_symdi (pic_offset_table_rtx, global_offset_table,
+                                    pic_helper_symbol));
+  else
+    emit_insn (gen_load_pcrel_symsi (pic_offset_table_rtx, global_offset_table,
+                                    pic_helper_symbol));
   flag_pic = orig_flag_pic;
 
   /* Need to emit this whether or not we obey regdecls,
@@ -3952,6 +3459,29 @@ load_pic_register (void)
      since we may not fall out the bottom.  */
   emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx));
 }
+
+/* Emit a call instruction with the pattern given by PAT.  ADDR is the
+   address of the call target.  */
+
+void
+sparc_emit_call_insn (rtx pat, rtx addr)
+{
+  rtx insn;
+
+  insn = emit_call_insn (pat);
+
+  /* The PIC register is live on entry to VxWorks PIC PLT entries.  */
+  if (TARGET_VXWORKS_RTP
+      && flag_pic
+      && GET_CODE (addr) == SYMBOL_REF
+      && (SYMBOL_REF_DECL (addr)
+         ? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
+         : !SYMBOL_REF_LOCAL_P (addr)))
+    {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
+      current_function_uses_pic_offset_table = 1;
+    }
+}
 \f
 /* Return 1 if RTX is a MEM which is known to be aligned to at
    least a DESIRED byte boundary.  */
@@ -3965,6 +3495,13 @@ mem_min_alignment (rtx mem, int desired)
   if (GET_CODE (mem) != MEM)
     return 0;
 
+  /* Obviously...  */
+  if (!TARGET_UNALIGNED_DOUBLES
+      && MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
+    return 1;
+
+  /* ??? The rest of the function predates MEM_ALIGN so
+     there is probably a bit of redundancy.  */
   addr = XEXP (mem, 0);
   base = offset = NULL_RTX;
   if (GET_CODE (addr) == PLUS)
@@ -4033,7 +3570,7 @@ mem_min_alignment (rtx mem, int desired)
    hard register number, and one indexed by mode.  */
 
 /* The purpose of sparc_mode_class is to shrink the range of modes so that
-   they all fit (as bit numbers) in a 32 bit word (again).  Each real mode is
+   they all fit (as bit numbers) in a 32-bit word (again).  Each real mode is
    mapped into one sparc_mode_class mode.  */
 
 enum sparc_mode_class {
@@ -4172,6 +3709,12 @@ sparc_init_modes (void)
          else 
            sparc_mode_class[i] = 0;
          break;
+       case MODE_VECTOR_INT:
+         if (GET_MODE_SIZE (i) <= 4)
+           sparc_mode_class[i] = 1 << (int)SF_MODE;
+         else if (GET_MODE_SIZE (i) == 8)
+           sparc_mode_class[i] = 1 << (int)DF_MODE;
+         break;
        case MODE_FLOAT:
        case MODE_COMPLEX_FLOAT:
          if (GET_MODE_SIZE (i) <= 4)
@@ -4234,20 +3777,20 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
   if (TARGET_ARCH64)
     {
       for (i = 0; i < 8; i++)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          n_regs += 2;
     }
   else
     {
       for (i = 0; i < 8; i += 2)
-       if ((regs_ever_live[i] && ! call_used_regs[i])
-           || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+       if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+           || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
          n_regs += 2;
     }
 
   for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
-    if ((regs_ever_live[i] && ! call_used_regs[i])
-       || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
+    if ((df_regs_ever_live_p (i) && ! call_used_regs[i])
+       || (df_regs_ever_live_p (i+1) && ! call_used_regs[i+1]))
       n_regs += 2;
 
   /* Set up values for use in prologue and epilogue.  */
@@ -4268,10 +3811,9 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 
   /* Make sure nothing can clobber our register windows.
      If a SAVE must be done, or there is a stack-local variable,
-     the register window area must be allocated.
-     ??? For v8 we apparently need an additional 8 bytes of reserved space.  */
+     the register window area must be allocated.  */
   if (! leaf_function_p || size > 0)
-    actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
+    actual_fsize += FIRST_PARM_OFFSET (current_function_decl);
 
   return SPARC_STACK_ALIGN (actual_fsize);
 }
@@ -4291,11 +3833,14 @@ sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
      .register being printed for them already.  */
   for (i = 2; i < 8; i++)
     {
-      if (regs_ever_live [i]
+      if (df_regs_ever_live_p (i)
          && ! sparc_hard_reg_printed [i])
        {
          sparc_hard_reg_printed [i] = 1;
-         fprintf (file, "\t.register\t%%g%d, #scratch\n", i);
+         /* %g7 is used as TLS base register, use #ignore
+            for it instead of #scratch.  */
+         fprintf (file, "\t.register\t%%g%d, #%s\n", i,
+                  i == 7 ? "ignore" : "scratch");
        }
       if (i == 3) i = 5;
     }
@@ -4319,7 +3864,7 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
     {
       for (i = low; i < high; i++)
        {
-         if (regs_ever_live[i] && ! call_used_regs[i])
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
            {
              mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
              set_mem_alias_set (mem, sparc_sr_alias_set);
@@ -4338,8 +3883,8 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
     {
       for (i = low; i < high; i += 2)
        {
-         bool reg0 = regs_ever_live[i] && ! call_used_regs[i];
-         bool reg1 = regs_ever_live[i+1] && ! call_used_regs[i+1];
+         bool reg0 = df_regs_ever_live_p (i) && ! call_used_regs[i];
+         bool reg1 = df_regs_ever_live_p (i+1) && ! call_used_regs[i+1];
          enum machine_mode mode;
          int regno;
 
@@ -4383,14 +3928,14 @@ save_or_restore_regs (int low, int high, rtx base, int offset, int action)
 /* Emit code to save call-saved registers.  */
 
 static void
-emit_save_regs (void)
+emit_save_or_restore_regs (int action)
 {
   HOST_WIDE_INT offset;
   rtx base;
 
   offset = frame_base_offset - apparent_fsize;
 
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+  if (offset < -4096 || offset + num_gfregs * 4 > 4095)
     {
       /* ??? This might be optimized a little as %g1 might already have a
         value close enough that a single add insn will do.  */
@@ -4408,56 +3953,43 @@ emit_save_regs (void)
   else
     base = frame_base_reg;
 
-  offset = save_or_restore_regs (0, 8, base, offset, SORR_SAVE);
-  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_SAVE);
+  offset = save_or_restore_regs (0, 8, base, offset, action);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, action);
 }
 
-/* Emit code to restore call-saved registers.  */
+/* Generate a save_register_window insn.  */
 
-static void
-emit_restore_regs (void)
+static rtx
+gen_save_register_window (rtx increment)
 {
-  HOST_WIDE_INT offset;
-  rtx base;
-
-  offset = frame_base_offset - apparent_fsize;
-
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
-    {
-      base = gen_rtx_REG (Pmode, 1);
-      emit_move_insn (base, GEN_INT (offset));
-      emit_insn (gen_rtx_SET (VOIDmode,
-                             base,
-                             gen_rtx_PLUS (Pmode, frame_base_reg, base)));
-      offset = 0;
-    }
+  if (TARGET_ARCH64)
+    return gen_save_register_windowdi (increment);
   else
-    base = frame_base_reg;
-
-  offset = save_or_restore_regs (0, 8, base, offset, SORR_RESTORE);
-  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_RESTORE);
+    return gen_save_register_windowsi (increment);
 }
 
-/* Emit an increment for the stack pointer.  */
+/* Generate an increment for the stack pointer.  */
 
-static void
-emit_stack_pointer_increment (rtx increment)
+static rtx
+gen_stack_pointer_inc (rtx increment)
 {
-  if (TARGET_ARCH64)
-    emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
-  else
-    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, increment));
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_PLUS (Pmode,
+                                   stack_pointer_rtx,
+                                   increment));
 }
 
-/* Emit a decrement for the stack pointer.  */
+/* Generate a decrement for the stack pointer.  */
 
-static void
-emit_stack_pointer_decrement (rtx decrement)
+static rtx
+gen_stack_pointer_dec (rtx decrement)
 {
-  if (TARGET_ARCH64)
-    emit_insn (gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
-  else
-    emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, decrement));
+  return gen_rtx_SET (VOIDmode,
+                     stack_pointer_rtx,
+                     gen_rtx_MINUS (Pmode,
+                                    stack_pointer_rtx,
+                                    decrement));
 }
 
 /* Expand the function prologue.  The prologue is responsible for reserving
@@ -4467,13 +3999,43 @@ emit_stack_pointer_decrement (rtx decrement)
 void
 sparc_expand_prologue (void)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
+  rtx insn;
+  int i;
+
+  /* Compute a snapshot of current_function_uses_only_leaf_regs.  Relying
+     on the final value of the flag means deferring the prologue/epilogue
+     expansion until just before the second scheduling pass, which is too
+     late to emit multiple epilogues or return insns.
+
+     Of course we are making the assumption that the value of the flag
+     will not change between now and its final value.  Of the three parts
+     of the formula, only the last one can reasonably vary.  Let's take a
+     closer look, after assuming that the first two ones are set to true
+     (otherwise the last value is effectively silenced).
+
+     If only_leaf_regs_used returns false, the global predicate will also
+     be false so the actual frame size calculated below will be positive.
+     As a consequence, the save_register_window insn will be emitted in
+     the instruction stream; now this insn explicitly references %fp
+     which is not a leaf register so only_leaf_regs_used will always
+     return false subsequently.
+
+     If only_leaf_regs_used returns true, we hope that the subsequent
+     optimization passes won't cause non-leaf registers to pop up.  For
+     example, the regrename pass has special provisions to not rename to
+     non-leaf registers in a leaf function.  */
+  sparc_leaf_function_p
+    = optimize > 0 && leaf_function_p () && only_leaf_regs_used ();
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
-  actual_fsize = sparc_compute_frame_size (get_frame_size(), leaf_function_p);
+  actual_fsize
+    = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
 
-  if (leaf_function_p)
+  /* Advertise that the data calculated just above are now valid.  */
+  sparc_prologue_data_valid_p = true;
+
+  if (sparc_leaf_function_p)
     {
       frame_base_reg = stack_pointer_rtx;
       frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
@@ -4486,86 +4048,71 @@ sparc_expand_prologue (void)
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (leaf_function_p)
+  else if (sparc_leaf_function_p)
     {
       if (actual_fsize <= 4096)
-       emit_stack_pointer_increment (GEN_INT (- actual_fsize));
+       insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-actual_fsize)));
       else if (actual_fsize <= 8192)
        {
-         emit_stack_pointer_increment (GEN_INT (-4096));
-         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
+         insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
+         /* %sp is still the CFA register.  */
+         RTX_FRAME_RELATED_P (insn) = 1;
+         insn
+           = emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
        }
       else
        {
          rtx reg = gen_rtx_REG (Pmode, 1);
          emit_move_insn (reg, GEN_INT (-actual_fsize));
-         emit_stack_pointer_increment (reg);
+         insn = emit_insn (gen_stack_pointer_inc (reg));
+         REG_NOTES (insn) =
+           gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                              gen_stack_pointer_inc (GEN_INT (-actual_fsize)),
+                              REG_NOTES (insn));
        }
+
+      RTX_FRAME_RELATED_P (insn) = 1;
     }
   else
     {
       if (actual_fsize <= 4096)
-        emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
+       insn = emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
       else if (actual_fsize <= 8192)
        {
-         emit_insn (gen_save_register_window (GEN_INT (-4096)));
-         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
+         insn = emit_insn (gen_save_register_window (GEN_INT (-4096)));
+         /* %sp is not the CFA register anymore.  */
+         emit_insn (gen_stack_pointer_inc (GEN_INT (4096-actual_fsize)));
        }
       else
        {
          rtx reg = gen_rtx_REG (Pmode, 1);
          emit_move_insn (reg, GEN_INT (-actual_fsize));
-         emit_insn (gen_save_register_window (reg));
+         insn = emit_insn (gen_save_register_window (reg));
        }
+
+      RTX_FRAME_RELATED_P (insn) = 1;
+      for (i=0; i < XVECLEN (PATTERN (insn), 0); i++)
+        RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, i)) = 1;
     }
 
-  /* Call-saved registers are saved just above the outgoing argument area.  */
   if (num_gfregs)
-    emit_save_regs ();
+    emit_save_or_restore_regs (SORR_SAVE);
 
   /* Load the PIC register if needed.  */
   if (flag_pic && current_function_uses_pic_offset_table)
-    load_pic_register ();
+    load_pic_register (false);
 }
  
 /* This function generates the assembly code for function entry, which boils
-   down to emitting the necessary .register directives.  It also informs the
-   DWARF-2 back-end on the layout of the frame.
-
-   ??? Historical cruft: "On SPARC, move-double insns between fpu and cpu need
-   an 8-byte block of memory.  If any fpu reg is used in the function, we
-   allocate such a block here, at the bottom of the frame, just in case it's
-   needed."  Could this explain the -8 in emit_restore_regs?  */
+   down to emitting the necessary .register directives.  */
 
 static void
 sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
+  /* Check that the assumption we made in sparc_expand_prologue is valid.  */
+  gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs);
 
   sparc_output_scratch_registers (file);
-
-  if (dwarf2out_do_frame () && actual_fsize)
-    {
-      char *label = dwarf2out_cfi_label ();
-
-      /* The canonical frame address refers to the top of the frame.  */
-      dwarf2out_def_cfa (label,
-                        leaf_function_p
-                        ? STACK_POINTER_REGNUM
-                        : HARD_FRAME_POINTER_REGNUM,
-                        frame_base_offset);
-
-      if (! leaf_function_p)
-       {
-         /* Note the register window save.  This tells the unwinder that
-            it needs to restore the window registers from the previous
-            frame's window save area at 0(cfa).  */
-         dwarf2out_window_save (label);
-
-         /* The return address (-8) is now in %i7.  */
-         dwarf2out_return_reg (label, 31);
-       }
-    }
 }
 
 /* Expand the function epilogue, either normal or part of a sibcall.
@@ -4574,30 +4121,38 @@ sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 void
 sparc_expand_epilogue (void)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
-
   if (num_gfregs)
-    emit_restore_regs ();
+    emit_save_or_restore_regs (SORR_RESTORE);
 
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (leaf_function_p)
+  else if (sparc_leaf_function_p)
     {
       if (actual_fsize <= 4096)
-       emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
+       emit_insn (gen_stack_pointer_dec (GEN_INT (- actual_fsize)));
       else if (actual_fsize <= 8192)
        {
-         emit_stack_pointer_decrement (GEN_INT (-4096));
-         emit_stack_pointer_decrement (GEN_INT (4096 - actual_fsize));
+         emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
+         emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - actual_fsize)));
        }
       else
        {
          rtx reg = gen_rtx_REG (Pmode, 1);
          emit_move_insn (reg, GEN_INT (-actual_fsize));
-         emit_stack_pointer_decrement (reg);
+         emit_insn (gen_stack_pointer_dec (reg));
        }
     }
 }
+
+/* Return true if it is appropriate to emit `return' instructions in the
+   body of a function.  */
+
+bool
+sparc_can_use_return_insn_p (void)
+{
+  return sparc_prologue_data_valid_p
+        && (actual_fsize == 0 || !sparc_leaf_function_p);
+}
   
 /* This function generates the assembly code for function exit.  */
   
@@ -4607,7 +4162,7 @@ sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
   /* If code does not drop into the epilogue, we have to still output
      a dummy nop for the sake of sane backtraces.  Otherwise, if the
      last two instructions of a function were "call foo; dslot;" this
-     can make the return PC of foo (ie. address of call instruction
+     can make the return PC of foo (i.e. address of call instruction
      plus 8) point to the first instruction in the next function.  */
 
   rtx insn, last_real_insn;
@@ -4639,8 +4194,7 @@ output_restore (rtx pat)
       return;
     }
 
-  if (GET_CODE (pat) != SET)
-    abort ();
+  gcc_assert (GET_CODE (pat) == SET);
 
   operands[0] = SET_DEST (pat);
   pat = SET_SRC (pat);
@@ -4659,8 +4213,7 @@ output_restore (rtx pat)
        break;
       case ASHIFT:
        operands[1] = XEXP (pat, 0);
-       if (XEXP (pat, 1) != const1_rtx)
-         abort();
+       gcc_assert (XEXP (pat, 1) == const1_rtx);
        output_asm_insn (" restore %r1, %r1, %Y0", operands);
        break;
       default:
@@ -4675,44 +4228,16 @@ output_restore (rtx pat)
 const char *
 output_return (rtx insn)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
-  bool delay_slot_filled_p = dbr_sequence_length () > 0;
-  /* True if the caller has placed an "unimp" insn immediately after the call.
-     This insn is used in the 32-bit ABI when calling a function that returns
-     a non zero-sized structure. The 64-bit ABI doesn't have it.  Be careful
-     to have this test be the same as that used on the call.  */
-  bool sparc_skip_caller_unimp
-    = ! TARGET_ARCH64
-      && current_function_returns_struct
-      && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
-         == INTEGER_CST)
-      && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl)));
-
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window, which frees us from dealing with the convoluted
         semantics of restore/return.  We simply output the jump to the
-        return address and the insn in the delay slot, which usually is
-        the substraction restoring the stack pointer %sp.  */
+        return address and the insn in the delay slot (if any).  */
 
-      if (current_function_calls_eh_return)
-       abort ();
-
-      fprintf (asm_out_file, "\tjmp\t%%o7+%d\n", sparc_skip_caller_unimp ? 12 : 8);
-
-      if (delay_slot_filled_p)
-       {
-         rtx delay = NEXT_INSN (insn);
-         if (! delay)
-           abort ();
+      gcc_assert (! current_function_calls_eh_return);
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
-       }
-      else
-       fputs ("\t nop\n", asm_out_file);
+      return "jmp\t%%o7+%)%#";
     }
   else
     {
@@ -4725,8 +4250,7 @@ output_return (rtx insn)
        {
          /* If the function uses __builtin_eh_return, the eh_return
             machinery occupies the delay slot.  */
-         if (delay_slot_filled_p || sparc_skip_caller_unimp)
-           abort ();
+         gcc_assert (! final_sequence);
 
          if (! flag_delayed_branch)
            fputs ("\tadd\t%fp, %g1, %fp\n", asm_out_file);
@@ -4741,45 +4265,37 @@ output_return (rtx insn)
          else
            fputs ("\t nop\n", asm_out_file);
        }
-      else if (delay_slot_filled_p)
+      else if (final_sequence)
        {
          rtx delay, pat;
 
          delay = NEXT_INSN (insn);
-         if (! delay)
-           abort ();
+         gcc_assert (delay);
 
          pat = PATTERN (delay);
 
          if (TARGET_V9 && ! epilogue_renumber (&pat, 1))
            {
              epilogue_renumber (&pat, 0);
-             fprintf (asm_out_file, "\treturn\t%%i7+%d\n",
-                      sparc_skip_caller_unimp ? 12 : 8);
-             final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
+             return "return\t%%i7+%)%#";
            }
          else
            {
-             fprintf (asm_out_file, "\tjmp\t%%i7+%d\n",
-                      sparc_skip_caller_unimp ? 12 : 8);
+             output_asm_insn ("jmp\t%%i7+%)", NULL);
              output_restore (pat);
+             PATTERN (delay) = gen_blockage ();
+             INSN_CODE (delay) = -1;
            }
-
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
        }
       else
         {
          /* The delay slot is empty.  */
          if (TARGET_V9)
-           fprintf (asm_out_file, "\treturn\t%%i7+%d\n\t nop\n",
-                    sparc_skip_caller_unimp ? 12 : 8);
+           return "return\t%%i7+%)\n\t nop";
          else if (flag_delayed_branch)
-           fprintf (asm_out_file, "\tjmp\t%%i7+%d\n\t restore\n",
-                    sparc_skip_caller_unimp ? 12 : 8);
+           return "jmp\t%%i7+%)\n\t restore";
          else
-           fprintf (asm_out_file, "\trestore\n\tjmp\t%%o7+%d\n\t nop\n",
-                    sparc_skip_caller_unimp ? 12 : 8);
+           return "restore\n\tjmp\t%%o7+%)\n\t nop";
        }
     }
 
@@ -4791,45 +4307,28 @@ output_return (rtx insn)
 const char *
 output_sibcall (rtx insn, rtx call_operand)
 {
-  int leaf_function_p = current_function_uses_only_leaf_regs;
-  bool delay_slot_filled_p = dbr_sequence_length () > 0;
   rtx operands[1];
 
-  if (! flag_delayed_branch)
-    abort();
+  gcc_assert (flag_delayed_branch);
 
   operands[0] = call_operand;
 
-  if (leaf_function_p)
+  if (sparc_leaf_function_p)
     {
       /* This is a leaf function so we don't have to bother restoring the
         register window.  We simply output the jump to the function and
         the insn in the delay slot (if any).  */
 
-      if (LEAF_SIBCALL_SLOT_RESERVED_P && delay_slot_filled_p)
-       abort();
+      gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
 
-      if (delay_slot_filled_p)
-       {
-         rtx delay = NEXT_INSN (insn);
-         if (! delay)
-           abort ();
-
-         output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
-         output_asm_insn ("jmp\t%%g1 + %%lo(%a0)", operands);
-         final_scan_insn (delay, asm_out_file, 1, 0, 1, NULL);
-
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
-       }
+      if (final_sequence)
+       output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#",
+                        operands);
       else
-       {
-         /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
-            it into branch if possible.  */
-         output_asm_insn ("or\t%%o7, %%g0, %%g1", operands);
-         output_asm_insn ("call\t%a0, 0", operands);
-         output_asm_insn (" or\t%%g1, %%g0, %%o7", operands);
-       }
+       /* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
+          it into branch if possible.  */
+       output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7",
+                        operands);
     }
   else
     {
@@ -4839,11 +4338,10 @@ output_sibcall (rtx insn, rtx call_operand)
 
       output_asm_insn ("call\t%a0, 0", operands);
 
-      if (delay_slot_filled_p)
+      if (final_sequence)
        {
          rtx delay = NEXT_INSN (insn);
-         if (! delay)
-           abort ();
+         gcc_assert (delay);
 
          output_restore (PATTERN (delay));
 
@@ -4931,8 +4429,7 @@ output_sibcall (rtx insn, rtx call_operand)
       _Complex double            16        memory         FP reg.
       _Complex long double       32        memory         FP reg.
 
-      vector float             <=32        memory         FP reg.
-      vector float              >32        memory         memory
+      vector float              any        memory         memory
 
       aggregate                 any        memory         memory
 
@@ -4977,8 +4474,8 @@ implemented by the Sun compiler.
 Note #2: integral vector types follow the scalar floating-point types
 conventions to match what is implemented by the Sun VIS SDK.
 
-Note #3: floating-point vector types follow the complex floating-point
-types conventions.  */
+Note #3: floating-point vector types follow the aggregate types 
+conventions.  */
 
 
 /* Maximum number of int regs for args.  */
@@ -5007,7 +4504,7 @@ init_cumulative_args (struct sparc_args *cum, tree fntype,
    When a prototype says `char' or `short', really pass an `int'.  */
 
 static bool
-sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+sparc_promote_prototypes (const_tree fntype ATTRIBUTE_UNUSED)
 {
   return TARGET_ARCH32 ? true : false;
 }
@@ -5040,7 +4537,9 @@ scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
        {
          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
            scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0);
-         else if (FLOAT_TYPE_P (TREE_TYPE (field)) && TARGET_FPU)
+         else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+                  || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+                 && TARGET_FPU)
            *fpregs_p = 1;
          else
            *intregs_p = 1;
@@ -5075,6 +4574,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
                 ? SPARC_INCOMING_INT_ARG_FIRST
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno = cum->words;
+  enum mode_class mclass;
   int regno;
 
   *ppadding = 0;
@@ -5090,16 +4590,39 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
 
   /* For SPARC64, objects requiring 16-byte alignment get it.  */
   if (TARGET_ARCH64
-      && GET_MODE_ALIGNMENT (mode) >= 2 * BITS_PER_WORD
+      && (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
       && (slotno & 1) != 0)
     slotno++, *ppadding = 1;
 
-  switch (GET_MODE_CLASS (mode))
+  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 (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
+       {
+         /* The SPARC port defines no floating-point vector modes.  */
+         gcc_assert (mode == BLKmode);
+       }
+      else
+       {
+         /* Integral 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
+            the Sun VIS SDK.  */
+         mclass = MODE_FLOAT;
+       }
+    }
+
+  switch (mclass)
     {
     case MODE_FLOAT:
     case MODE_COMPLEX_FLOAT:
-    case MODE_VECTOR_INT:
-    case MODE_VECTOR_FLOAT:
       if (TARGET_ARCH64 && TARGET_FPU && named)
        {
          if (slotno >= SPARC_FP_ARG_MAX)
@@ -5125,28 +4648,26 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
        /* MODE is VOIDmode when generating the actual call.  */
        return -1;
 
-      if (mode != BLKmode)
-       abort ();
+      gcc_assert (mode == BLKmode);
 
-      /* For SPARC64, objects requiring 16-byte alignment get it.  */
-      if (TARGET_ARCH64
-         && type
-         && TYPE_ALIGN (type) >= 2 * BITS_PER_WORD
-         && (slotno & 1) != 0)
-       slotno++, *ppadding = 1;
-
-      if (TARGET_ARCH32 || (type && TREE_CODE (type) == UNION_TYPE))
+      if (TARGET_ARCH32
+         || !type
+         || (TREE_CODE (type) != VECTOR_TYPE
+             && TREE_CODE (type) != RECORD_TYPE))
        {
          if (slotno >= SPARC_INT_ARG_MAX)
            return -1;
          regno = regbase + slotno;
        }
-      else  /* TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE */
+      else  /* TARGET_ARCH64 && type */
        {
          int intregs_p = 0, fpregs_p = 0, packed_p = 0;
 
          /* First see what kinds of registers we would need.  */
-         scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
+         if (TREE_CODE (type) == VECTOR_TYPE)
+           fpregs_p = 1;
+         else
+           scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
 
          /* The ABI obviously doesn't specify how packed structures
             are passed.  These are defined to be passed in int regs
@@ -5172,7 +4693,7 @@ function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
       break;
 
     default :
-      abort ();
+      gcc_unreachable ();
     }
 
   *pregno = regno;
@@ -5195,17 +4716,17 @@ struct function_arg_record_value_parms
 static void function_arg_record_value_3
  (HOST_WIDE_INT, struct function_arg_record_value_parms *);
 static void function_arg_record_value_2
- (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
+ (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static void function_arg_record_value_1
- (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static rtx function_arg_record_value (tree, enum machine_mode, int, int, int);
-static rtx function_arg_union_value (int, enum machine_mode, int);
+ (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
+static rtx function_arg_record_value (const_tree, enum machine_mode, int, int, int);
+static rtx function_arg_union_value (int, enum machine_mode, int, int);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
    recursively and determine how many registers will be required.  */
 
 static void
-function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
+function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
                             struct function_arg_record_value_parms *parms,
                             bool packed_p)
 {
@@ -5235,9 +4756,14 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
        {
          HOST_WIDE_INT bitpos = startbitpos;
 
-         if (DECL_SIZE (field) != 0
-             && host_integerp (bit_position (field), 1))
-           bitpos += int_bit_position (field);
+         if (DECL_SIZE (field) != 0)
+           {
+             if (integer_zerop (DECL_SIZE (field)))
+               continue;
+
+             if (host_integerp (bit_position (field), 1))
+               bitpos += int_bit_position (field);
+           }
 
          /* ??? FIXME: else assume zero offset.  */
 
@@ -5277,8 +4803,12 @@ function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
 
              /* There's no need to check this_slotno < SPARC_FP_ARG MAX.
                 If it wasn't true we wouldn't be here.  */
-             parms->nregs += 1;
-             if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+                 && DECL_MODE (field) == BLKmode)
+               parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+               parms->nregs += 2;
+             else
                parms->nregs += 1;
            }
          else
@@ -5324,8 +4854,8 @@ function_arg_record_value_3 (HOST_WIDE_INT bitpos,
      at the moment but may wish to revisit.  */
 
   if (intoffset % BITS_PER_WORD != 0)
-    mode = mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
-                         MODE_INT, 0);
+    mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
+                                  MODE_INT);
   else
     mode = word_mode;
 
@@ -5352,7 +4882,7 @@ function_arg_record_value_3 (HOST_WIDE_INT bitpos,
    to make that happen.  */
 
 static void
-function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
+function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
                             struct function_arg_record_value_parms *parms,
                             bool packed_p)
 {
@@ -5374,9 +4904,14 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
        {
          HOST_WIDE_INT bitpos = startbitpos;
 
-         if (DECL_SIZE (field) != 0
-             && host_integerp (bit_position (field), 1))
-           bitpos += int_bit_position (field);
+         if (DECL_SIZE (field) != 0)
+           {
+             if (integer_zerop (DECL_SIZE (field)))
+               continue;
+
+             if (host_integerp (bit_position (field), 1))
+               bitpos += int_bit_position (field);
+           }
 
          /* ??? FIXME: else assume zero offset.  */
 
@@ -5392,34 +4927,41 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
                   && ! packed_p)
            {
              int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
-             int regno;
+             int regno, nregs, pos;
              enum machine_mode mode = DECL_MODE (field);
              rtx reg;
 
              function_arg_record_value_3 (bitpos, parms);
-             switch (mode)
-               {
-               case SCmode: mode = SFmode; break;
-               case DCmode: mode = DFmode; break;
-               case TCmode: mode = TFmode; break;
-               default: break;
+
+             if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
+                 && mode == BLKmode)
+               {
+                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+                 nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
                }
+             else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+               {
+                 mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+                 nregs = 2;
+               }
+             else
+               nregs = 1;
+
              regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
              if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
                regno++;
              reg = gen_rtx_REG (mode, regno);
+             pos = bitpos / BITS_PER_UNIT;
              XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
-               = gen_rtx_EXPR_LIST (VOIDmode, reg,
-                          GEN_INT (bitpos / BITS_PER_UNIT));
+               = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
              parms->nregs += 1;
-             if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+             while (--nregs > 0)
                {
                  regno += GET_MODE_SIZE (mode) / 4;
                  reg = gen_rtx_REG (mode, regno);
+                 pos += GET_MODE_SIZE (mode);
                  XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
-                   = gen_rtx_EXPR_LIST (VOIDmode, reg,
-                       GEN_INT ((bitpos + GET_MODE_BITSIZE (mode))
-                                / BITS_PER_UNIT));
+                   = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
                  parms->nregs += 1;
                }
            }
@@ -5447,7 +4989,7 @@ function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
    REGBASE is the regno of the base register for the parameter array.  */
    
 static rtx
-function_arg_record_value (tree type, enum machine_mode mode,
+function_arg_record_value (const_tree type, enum machine_mode mode,
                           int slotno, int named, int regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
@@ -5508,15 +5050,14 @@ function_arg_record_value (tree type, enum machine_mode mode,
       if (nregs + slotno > SPARC_INT_ARG_MAX)
        nregs = SPARC_INT_ARG_MAX - slotno;
     }
-  if (nregs == 0)
-    abort ();
+  gcc_assert (nregs != 0);
 
   parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
 
   /* If at least one field must be passed on the stack, generate
      (parallel [(expr_list (nil) ...) ...]) so that all fields will
      also be passed on the stack.  We can't do much better because the
-     semantics of FUNCTION_ARG_PARTIAL_NREGS doesn't handle the case
+     semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
      of structures for which the fields passed exclusively in registers
      are not at the beginning of the structure.  */
   if (parms.stack)
@@ -5529,8 +5070,7 @@ function_arg_record_value (tree type, enum machine_mode mode,
   function_arg_record_value_2 (type, 0, &parms, false);
   function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
 
-  if (parms.nregs != nregs)
-    abort ();
+  gcc_assert (parms.nregs == nregs);
 
   return parms.ret;
 }
@@ -5545,19 +5085,60 @@ function_arg_record_value (tree type, enum machine_mode mode,
    REGNO is the hard register the union will be passed in.  */
 
 static rtx
-function_arg_union_value (int size, enum machine_mode mode, int regno)
+function_arg_union_value (int size, enum machine_mode mode, int slotno,
+                         int regno)
 {
   int nwords = ROUND_ADVANCE (size), i;
   rtx regs;
 
-  /* Unions are passed left-justified.  */
+  /* See comment in previous function for empty structures.  */
+  if (nwords == 0)
+    return gen_rtx_REG (mode, regno);
+
+  if (slotno == SPARC_INT_ARG_MAX - 1)
+    nwords = 1;
+
   regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
 
   for (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));
+    {
+      /* 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++;
+    }
+
+  return regs;
+}
+
+/* Used by function_arg and function_value to implement the conventions
+   for passing and returning large (BLKmode) vectors.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
+
+   SIZE is the size in bytes of the vector.
+   BASE_MODE is the argument's base machine mode.
+   REGNO is the FP hard register the vector will be passed in.  */
+
+static rtx
+function_arg_vector_value (int size, enum machine_mode base_mode, int regno)
+{
+  unsigned short base_mode_size = GET_MODE_SIZE (base_mode);
+  int nregs = size / base_mode_size, i;
+  rtx regs;
+
+  regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
+
+  for (i = 0; i < nregs; i++)
+    {
+      XVECEXP (regs, 0, i)
+       = gen_rtx_EXPR_LIST (VOIDmode,
+                            gen_rtx_REG (base_mode, regno),
+                            GEN_INT (base_mode_size * i));
+      regno += base_mode_size / 4;
+    }
 
   return regs;
 }
@@ -5585,50 +5166,59 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
                 ? SPARC_INCOMING_INT_ARG_FIRST
                 : SPARC_OUTGOING_INT_ARG_FIRST);
   int slotno, regno, padding;
-  rtx reg;
+  enum mode_class mclass = GET_MODE_CLASS (mode);
 
   slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
                                &regno, &padding);
-
   if (slotno == -1)
     return 0;
 
-  if (TARGET_ARCH32)
+  /* Vector types deserve special treatment because they are polymorphic wrt
+     their mode, depending upon whether VIS instructions are enabled.  */
+  if (type && TREE_CODE (type) == VECTOR_TYPE)
     {
-      reg = gen_rtx_REG (mode, regno);
-      return reg;
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert ((TARGET_ARCH32 && size <= 8)
+                 || (TARGET_ARCH64 && size <= 16));
+
+      if (mode == BLKmode)
+       return function_arg_vector_value (size,
+                                         TYPE_MODE (TREE_TYPE (type)),
+                                         SPARC_FP_ARG_FIRST + 2*slotno);
+      else
+       mclass = MODE_FLOAT;
     }
-    
+
+  if (TARGET_ARCH32)
+    return gen_rtx_REG (mode, regno);
+
+  /* Structures up to 16 bytes in size are passed in arg slots on the stack
+     and are promoted to registers if possible.  */
   if (type && TREE_CODE (type) == RECORD_TYPE)
     {
-      /* Structures up to 16 bytes in size are passed in arg slots on the
-        stack and are promoted to registers where possible.  */
-
-      if (int_size_in_bytes (type) > 16)
-       abort (); /* shouldn't get here */
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
 
       return function_arg_record_value (type, mode, slotno, named, regbase);
     }
+
+  /* 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);
+      gcc_assert (size <= 16);
 
-      if (size > 16)
-       abort (); /* shouldn't get here */
-
-      return function_arg_union_value (size, mode, regno);
+      return function_arg_union_value (size, mode, slotno, regno);
     }
+
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
      in two places, either fp regs and int regs or fp regs and memory.  */
-  else if ((GET_MODE_CLASS (mode) == MODE_FLOAT
-           || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-           || GET_MODE_CLASS (mode) == MODE_VECTOR_INT
-           || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
-      && SPARC_FP_REG_P (regno))
+  else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+          && SPARC_FP_REG_P (regno))
     {
-      reg = gen_rtx_REG (mode, regno);
+      rtx reg = gen_rtx_REG (mode, regno);
       if (cum->prototype_p || cum->libcall_p)
        {
          /* "* 2" because fp reg numbers are recorded in 4 byte
@@ -5689,18 +5279,22 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
            }
        }
     }
-  else
+
+  /* All other aggregate types are passed in an integer register in a mode
+     corresponding to the size of the type.  */
+  else if (type && AGGREGATE_TYPE_P (type))
     {
-      /* Scalar or complex int.  */
-      reg = gen_rtx_REG (mode, regno);
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      gcc_assert (size <= 16);
+
+      mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
     }
 
-  return reg;
+  return gen_rtx_REG (mode, regno);
 }
 
-/* Handle the FUNCTION_ARG_PARTIAL_NREGS macro.
-   For an arg passed partly in registers and partly in memory,
-   this is the number of registers used.
+/* For an arg passed partly in registers and partly in memory,
+   this is the number of bytes of registers used.
    For args passed entirely in registers or entirely in memory, zero.
 
    Any arg that starts in the first 6 regs but won't entirely fit in them
@@ -5709,9 +5303,9 @@ function_arg (const struct sparc_args *cum, enum machine_mode mode,
    values that begin in the last fp reg [where "last fp reg" varies with the
    mode] will be split between that reg and memory.  */
 
-int
-function_arg_partial_nregs (const struct sparc_args *cum,
-                           enum machine_mode mode, tree type, int named)
+static int
+sparc_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                        tree type, bool named)
 {
   int slotno, regno, padding;
 
@@ -5727,13 +5321,13 @@ function_arg_partial_nregs (const struct sparc_args *cum,
                     ? ROUND_ADVANCE (int_size_in_bytes (type))
                     : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
          > SPARC_INT_ARG_MAX)
-       return SPARC_INT_ARG_MAX - slotno;
+       return (SPARC_INT_ARG_MAX - slotno) * 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 1 if the argument is partially passed in registers.  */
+        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))
        {
@@ -5741,7 +5335,7 @@ function_arg_partial_nregs (const struct sparc_args *cum,
 
          if (size > UNITS_PER_WORD
              && slotno == SPARC_INT_ARG_MAX - 1)
-           return 1;
+           return UNITS_PER_WORD;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
               || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
@@ -5750,51 +5344,68 @@ function_arg_partial_nregs (const struct sparc_args *cum,
          /* The complex types are passed as packed types.  */
          if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
              && slotno == SPARC_INT_ARG_MAX - 1)
-           return 1;
+           return UNITS_PER_WORD;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
        {
          if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
              > SPARC_FP_ARG_MAX)
-           return 1;
+           return UNITS_PER_WORD;
        }
     }
 
   return 0;
 }
 
-/* Return true if the argument should be passed by reference.
-   !v9: The SPARC ABI stipulates passing struct arguments (of any size) and
-   quad-precision floats by invisible reference.
-   v9: Aggregates greater than 16 bytes are passed by reference.
-   For Pascal, also pass arrays by reference.  */
+/* Handle the TARGET_PASS_BY_REFERENCE target hook.
+   Specify whether to pass the argument by reference.  */
 
 static bool
 sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
-                        enum machine_mode mode, tree type,
+                        enum machine_mode mode, const_tree type,
                         bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
-    {
-      return ((type && AGGREGATE_TYPE_P (type))
-             /* Extended ABI (as implemented by the Sun compiler) says
-                that all complex floats are passed in memory.  */
-             || mode == SCmode
-             /* Enforce the 2-word cap for passing arguments in registers.
-                This affects CDImode, TFmode, DCmode, TCmode and large
-                vector modes.  */
-             || GET_MODE_SIZE (mode) > 8);
-    }
+    /* 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
-    {
-      return ((type && TREE_CODE (type) == ARRAY_TYPE)
-             || (type
-                 && AGGREGATE_TYPE_P (type)
-                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
-             /* Enforce the 2-word cap for passing arguments in registers.
-                This affects CTImode, TCmode and large vector modes.  */
-             || GET_MODE_SIZE (mode) > 16);
-    }
+    /* 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);
 }
 
 /* Handle the FUNCTION_ARG_ADVANCE macro.
@@ -5848,7 +5459,7 @@ function_arg_advance (struct sparc_args *cum, enum machine_mode mode,
    argument slot.  */
 
 enum direction
-function_arg_padding (enum machine_mode mode, tree type)
+function_arg_padding (enum machine_mode mode, const_tree type)
 {
   if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
     return upward;
@@ -5861,51 +5472,106 @@ function_arg_padding (enum machine_mode mode, tree type)
    Specify whether to return the return value in memory.  */
 
 static bool
-sparc_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+sparc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
-    /* Original SPARC 32-bit ABI says that quad-precision floats
-       and all structures are returned in memory.  Extended ABI
-       (as implemented by the Sun compiler) says that all complex
-       floats are returned in registers (8 FP registers at most
-       for '_Complex long double').  Return all complex integers
-       in registers (4 at most for '_Complex long long').  */
+    /* 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.
+
+       Extended ABI (as implemented by the Sun compiler) says that
+       all complex floats are returned in registers (8 FP registers
+       at most for '_Complex long double').  Return all complex integers
+       in registers (4 at most for '_Complex long long').
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are returned like floats of the same size, that is in
+       registers up to 8 bytes and in memory otherwise.  Return all
+       vector floats in memory like structure and unions; note that
+       they always have BLKmode like the latter.  */
     return (TYPE_MODE (type) == BLKmode
            || TYPE_MODE (type) == TFmode
-           /* Integral vector types follow the scalar FP types conventions.  */
-           || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_INT
-               && GET_MODE_SIZE (TYPE_MODE (type)) > 8)
-           /* FP vector types follow the complex FP types conventions.  */
-           || (GET_MODE_CLASS (TYPE_MODE (type)) == MODE_VECTOR_FLOAT
-               && GET_MODE_SIZE (TYPE_MODE (type)) > 32));
+           || (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 32 bytes are returned in registers.  Extended
-       ABI (as implemented by the Sun compiler) says that all complex
-       floats are returned in registers (8 FP registers at most
-       for '_Complex long double').  Return all complex integers
-       in registers (4 at most for '_Complex TItype').  */
+       smaller than 32 bytes are returned in registers, as well as
+       all other base types.
+       
+       Extended ABI (as implemented by the Sun compiler) says that all
+       complex floats are returned in registers (8 FP registers at most
+       for '_Complex long double').  Return all complex integers in
+       registers (4 at most for '_Complex TItype').
+
+       Vector ABI (as implemented by the Sun VIS SDK) says that vector
+       integers are returned like floats of the same size, that is in
+       registers.  Return all vector floats like structure and unions;
+       note that they always have BLKmode like the latter.  */
     return ((TYPE_MODE (type) == BLKmode
-            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)
-           || GET_MODE_SIZE (TYPE_MODE (type)) > 32);
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32));
 }
 
 /* Handle the TARGET_STRUCT_VALUE target hook.
    Return where to find the structure return value address.  */
 
 static rtx
-sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
+sparc_struct_value_rtx (tree fndecl, int incoming)
 {
   if (TARGET_ARCH64)
     return 0;
   else
     {
+      rtx mem;
+
       if (incoming)
-       return gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
-                                                 STRUCT_VALUE_OFFSET));
+       mem = gen_rtx_MEM (Pmode, plus_constant (frame_pointer_rtx,
+                                                STRUCT_VALUE_OFFSET));
       else
-       return gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
-                                                 STRUCT_VALUE_OFFSET));
+       mem = gen_rtx_MEM (Pmode, plus_constant (stack_pointer_rtx,
+                                                STRUCT_VALUE_OFFSET));
+
+      /* Only follow the SPARC ABI for fixed-size structure returns. 
+         Variable size structure returns are handled per the normal 
+         procedures in GCC. This is enabled by -mstd-struct-return */
+      if (incoming == 2 
+         && sparc_std_struct_return
+         && TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
+         && TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
+       {
+         /* We must check and adjust the return address, as it is
+            optional as to whether the return object is really
+            provided.  */
+         rtx ret_rtx = gen_rtx_REG (Pmode, 31);
+         rtx scratch = gen_reg_rtx (SImode);
+         rtx endlab = gen_label_rtx (); 
+
+         /* Calculate the return object size */
+         tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
+         rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
+         /* Construct a temporary return value */
+         rtx temp_val = assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
+
+         /* Implement SPARC 32-bit psABI callee returns struck checking
+            requirements: 
+           
+             Fetch the instruction where we will return to and see if
+            it's an unimp instruction (the most significant 10 bits
+            will be zero).  */
+         emit_move_insn (scratch, gen_rtx_MEM (SImode,
+                                               plus_constant (ret_rtx, 8)));
+         /* Assume the size is valid and pre-adjust */
+         emit_insn (gen_add3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode, 0, endlab);
+         emit_insn (gen_sub3_insn (ret_rtx, ret_rtx, GEN_INT (4)));
+         /* Assign stack temp: 
+            Write the address of the memory pointed to by temp_val into
+            the memory pointed to by mem */
+         emit_move_insn (mem, XEXP (temp_val, 0));
+         emit_label (endlab);
+       }
+
+      set_mem_alias_set (mem, struct_value_alias_set);
+      return mem;
     }
 }
 
@@ -5914,45 +5580,65 @@ sparc_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, int incoming)
    except that up to 32 bytes may be returned in registers.  */
 
 rtx
-function_value (tree type, enum machine_mode mode, int incoming_p)
+function_value (const_tree type, enum machine_mode mode, int incoming_p)
 {
   /* Beware that the two values are swapped here wrt function_arg.  */
   int regbase = (incoming_p
                 ? SPARC_OUTGOING_INT_ARG_FIRST
                 : SPARC_INCOMING_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,
+                                         TYPE_MODE (TREE_TYPE (type)),
+                                         SPARC_FP_ARG_FIRST);
+      else
+       mclass = MODE_FLOAT;
+    }
+
   if (TARGET_ARCH64 && type)
     {
+      /* Structures up to 32 bytes in size are returned in registers.  */
       if (TREE_CODE (type) == RECORD_TYPE)
        {
-         /* Structures up to 32 bytes in size are passed in registers,
-            promoted to fp registers where possible.  */
-
-         if (int_size_in_bytes (type) > 32)
-           abort (); /* shouldn't get here */
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+
+      /* Unions up to 32 bytes in size are returned in integer registers.  */
       else if (TREE_CODE (type) == UNION_TYPE)
        {
          HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
-         if (size > 32)
-           abort (); /* shouldn't get here */
-
-         return function_arg_union_value (size, mode, regbase);
+         return function_arg_union_value (size, mode, 0, regbase);
        }
+
+      /* Objects that require it are returned in FP registers.  */
+      else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
+       ;
+
+      /* All other aggregate types are returned in an integer register in a
+        mode corresponding to the size of the type.  */
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
             in a mode corresponding to the size of the type.  */
-         HOST_WIDE_INT bytes = int_size_in_bytes (type);
-
-         if (bytes > 32)
-           abort (); /* shouldn't get here */
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+         gcc_assert (size <= 32);
 
-         mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
+         mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
 
          /* ??? We probably should have made the same ABI change in
             3.4.0 as the one we made for unions.   The latter was
@@ -5964,14 +5650,17 @@ function_value (tree type, enum machine_mode mode, int incoming_p)
             try to be unduly clever, and simply follow the ABI
             for unions in that case.  */
          if (mode == BLKmode)
-           return function_arg_union_value (bytes, mode, regbase);
+           return function_arg_union_value (size, mode, 0, regbase);
+         else
+           mclass = MODE_INT;
        }
-      else if (GET_MODE_CLASS (mode) == MODE_INT
-              && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+
+      /* This must match PROMOTE_FUNCTION_MODE.  */
+      else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
        mode = word_mode;
     }
 
-  if (TARGET_FPU && (FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode)))
+  if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
     regno = SPARC_FP_ARG_FIRST;
   else
     regno = regbase;
@@ -6010,7 +5699,7 @@ sparc_builtin_saveregs (void)
 
 /* Implement `va_start' for stdarg.  */
 
-void
+static void
 sparc_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
@@ -6027,7 +5716,7 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   bool indirect;
   tree ptrtype = build_pointer_type (type);
 
-  if (pass_by_reference (NULL, TYPE_MODE (type), type, 0))
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
     {
       indirect = true;
       size = rsize = UNITS_PER_WORD;
@@ -6047,7 +5736,7 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
            align = 2 * UNITS_PER_WORD;
 
          /* SPARC-V9 ABI states that structures up to 16 bytes in size
-            are given whole slots as needed.  */
+            are left-justified in their slots.  */
          if (AGGREGATE_TYPE_P (type))
            {
              if (size == 0)
@@ -6061,23 +5750,25 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   incr = valist;
   if (align)
     {
-      incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
-                          ssize_int (align - 1)));
-      incr = fold (build2 (BIT_AND_EXPR, ptr_type_node, incr,
-                          ssize_int (-align)));
+      incr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                         size_int (align - 1));
+      incr = fold_convert (sizetype, incr);
+      incr = fold_build2 (BIT_AND_EXPR, sizetype, incr,
+                         size_int (-align));
+      incr = fold_convert (ptr_type_node, incr);
     }
 
   gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
   addr = incr;
 
   if (BYTES_BIG_ENDIAN && size < rsize)
-    addr = fold (build2 (PLUS_EXPR, ptr_type_node, incr,
-                        ssize_int (rsize - size)));
+    addr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr,
+                       size_int (rsize - size));
 
   if (indirect)
     {
       addr = fold_convert (build_pointer_type (ptrtype), addr);
-      addr = build_fold_indirect_ref (addr);
+      addr = build_va_arg_indirect_ref (addr);
     }
   /* If the address isn't aligned properly for the type,
      we may need to copy to a temporary.  
@@ -6089,12 +5780,10 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
       tree tmp = create_tmp_var (type, "va_arg_tmp");
       tree dest_addr = build_fold_addr_expr (tmp);
 
-      tree copy = build_function_call_expr
-       (implicit_built_in_decls[BUILT_IN_MEMCPY],
-        tree_cons (NULL_TREE, dest_addr,
-                   tree_cons (NULL_TREE, addr,
-                              tree_cons (NULL_TREE, size_int (rsize),
-                                         NULL_TREE))));
+      tree copy = build_call_expr (implicit_built_in_decls[BUILT_IN_MEMCPY], 3,
+                                  dest_addr,
+                                  addr,
+                                  size_int (rsize));
 
       gimplify_and_add (copy, pre_p);
       addr = dest_addr;
@@ -6102,11 +5791,20 @@ sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   else
     addr = fold_convert (ptrtype, addr);
 
-  incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
-  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+  incr = fold_build2 (POINTER_PLUS_EXPR, ptr_type_node, incr, size_int (rsize));
+  incr = build2 (GIMPLE_MODIFY_STMT, ptr_type_node, valist, incr);
   gimplify_and_add (incr, post_p);
 
-  return build_fold_indirect_ref (addr);
+  return build_va_arg_indirect_ref (addr);
+}
+\f
+/* Implement the TARGET_VECTOR_MODE_SUPPORTED_P target hook.
+   Specify whether the vector mode is supported by the hardware.  */
+
+static bool
+sparc_vector_mode_supported_p (enum machine_mode mode)
+{
+  return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false;
 }
 \f
 /* Return the string to output an unconditional branch to LABEL, which is
@@ -6118,51 +5816,29 @@ const char *
 output_ubranch (rtx dest, int label, rtx insn)
 {
   static char string[64];
-  bool noop = false;
+  bool v9_form = false;
   char *p;
 
-  /* TurboSPARC is reported to have problems with
-     with
-       foo: b,a foo
-     i.e. an empty loop with the annul bit set.  The workaround is to use 
-        foo: b foo; nop
-     instead.  */
-
-  if (! TARGET_V9 && flag_delayed_branch
-      && (INSN_ADDRESSES (INSN_UID (dest))
-         == INSN_ADDRESSES (INSN_UID (insn))))
+  if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
     {
-      strcpy (string, "b\t");
-      noop = true;
+      int delta = (INSN_ADDRESSES (INSN_UID (dest))
+                  - INSN_ADDRESSES (INSN_UID (insn)));
+      /* Leave some instructions for "slop".  */
+      if (delta >= -260000 && delta < 260000)
+       v9_form = true;
     }
-  else
-    {
-      bool v9_form = false;
-
-      if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
-       {
-         int delta = (INSN_ADDRESSES (INSN_UID (dest))
-                      - INSN_ADDRESSES (INSN_UID (insn)));
-         /* Leave some instructions for "slop".  */
-         if (delta >= -260000 && delta < 260000)
-           v9_form = true;
-       }
 
-      if (v9_form)
-       strcpy (string, "ba%*,pt\t%%xcc, ");
-      else
-       strcpy (string, "b%*\t");
-    }
+  if (v9_form)
+    strcpy (string, "ba%*,pt\t%%xcc, ");
+  else
+    strcpy (string, "b%*\t");
 
   p = strchr (string, '\0');
   *p++ = '%';
   *p++ = 'l';
   *p++ = '0' + label;
   *p++ = '%';
-  if (noop)
-    *p++ = '#';
-  else
-    *p++ = '(';
+  *p++ = '(';
   *p = '\0';
 
   return string;
@@ -6177,13 +5853,11 @@ output_ubranch (rtx dest, int label, rtx insn)
 
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
-   ANNUL is nonzero if we should generate an annulling branch.
-
-   NOOP is nonzero if we have to follow this branch by a noop.  */
+   ANNUL is nonzero if we should generate an annulling branch.  */
 
 const char *
 output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
-               int noop, rtx insn)
+               rtx insn)
 {
   static char string[64];
   enum rtx_code code = GET_CODE (op);
@@ -6274,7 +5948,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       /* ??? !v9: FP branches cannot be preceded by another floating point
@@ -6329,7 +6003,7 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
       strcpy (string, branch);
     }
@@ -6366,17 +6040,14 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
          labelno = v9_fcc_labelno;
          if (v8)
            {
-             if (REGNO (cc_reg) == SPARC_FCC_REG)
-               labelno = "";
-             else
-               abort ();
+             gcc_assert (REGNO (cc_reg) == SPARC_FCC_REG);
+             labelno = "";
            }
        }
       else if (mode == CCXmode || mode == CCX_NOOVmode)
        {
          labelno = "%%xcc, ";
-         if (v8)
-           abort ();
+         gcc_assert (! v8);
        }
       else
        {
@@ -6406,18 +6077,18 @@ output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
   if (far)
     {
       strcpy (p, ".+12\n\t nop\n\tb\t");
-      if (annul || noop)
+      /* Skip the next insn if requested or
+        if we know that it will be a nop.  */
+      if (annul || ! final_sequence)
         p[3] = '6';
       p += 14;
     }
   *p++ = '%';
   *p++ = 'l';
-  /* Set the char indicating the number of the operand containing the
-     label_ref.  */
   *p++ = label + '0';
+  *p++ = '%';
+  *p++ = '#';
   *p = '\0';
-  if (noop)
-    strcpy (p, "\n\t nop");
 
   return string;
 }
@@ -6472,8 +6143,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
       break;
 
     default:
-      abort();
-      break;
+      gcc_unreachable ();
     }
 
   if (TARGET_ARCH64)
@@ -6481,7 +6151,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
       if (GET_CODE (x) != MEM)
        {
          slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot0, x));
+         emit_move_insn (slot0, x);
        }
       else
        slot0 = x;
@@ -6489,7 +6159,7 @@ sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
       if (GET_CODE (y) != MEM)
        {
          slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
-         emit_insn (gen_rtx_SET (VOIDmode, slot1, y));
+         emit_move_insn (slot1, y);
        }
       else
        slot1 = y;
@@ -6644,13 +6314,11 @@ sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
 
    REVERSED is nonzero if we should reverse the sense of the comparison.
 
-   ANNUL is nonzero if we should generate an annulling branch.
-
-   NOOP is nonzero if we have to follow this branch by a noop.  */
+   ANNUL is nonzero if we should generate an annulling branch.  */
 
 const char *
 output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
-                int annul, int noop, rtx insn)
+                int annul, rtx insn)
 {
   static char string[64];
   enum rtx_code code = GET_CODE (op);
@@ -6687,8 +6355,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
     code = reverse_condition (code);
 
   /* Only 64 bit versions of these instructions exist.  */
-  if (mode != DImode)
-    abort ();
+  gcc_assert (mode == DImode);
 
   /* Start by writing the branch condition.  */
 
@@ -6719,7 +6386,7 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   p = strchr (string, '\0');
@@ -6759,7 +6426,9 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
        }
 
       strcpy (p, ".+12\n\t nop\n\t");
-      if (annul || noop)
+      /* Skip the next insn if requested or
+        if we know that it will be a nop.  */
+      if (annul || ! final_sequence)
         p[3] = '6';
       p += 12;
       if (veryfar)
@@ -6776,11 +6445,10 @@ output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
   *p++ = '%';
   *p++ = 'l';
   *p++ = '0' + label;
+  *p++ = '%';
+  *p++ = '#';
   *p = '\0';
 
-  if (noop)
-    strcpy (p, "\n\t nop");
-
   return string;
 }
 
@@ -6878,7 +6546,7 @@ order_regs_for_local_alloc (void)
 {
   static int last_order_nonleaf = 1;
 
-  if (regs_ever_live[15] != last_order_nonleaf)
+  if (df_regs_ever_live_p (15) != last_order_nonleaf)
     {
       last_order_nonleaf = !last_order_nonleaf;
       memcpy ((char *) reg_alloc_order,
@@ -6894,8 +6562,7 @@ int
 sparc_splitdi_legitimate (rtx reg, rtx mem)
 {
   /* Punt if we are here by mistake.  */
-  if (! reload_completed)
-    abort ();
+  gcc_assert (reload_completed);
 
   /* We must have an offsettable memory reference.  */
   if (! offsettable_memref_p (mem))
@@ -7077,43 +6744,60 @@ print_operand (FILE *file, rtx x, int code)
   switch (code)
     {
     case '#':
-      /* Output a 'nop' if there's nothing for the delay slot.  */
-      if (dbr_sequence_length () == 0)
+      /* Output an insn in a delay slot.  */
+      if (final_sequence)
+        sparc_indent_opcode = 1;
+      else
        fputs ("\n\t nop", file);
       return;
     case '*':
       /* Output an annul flag if there's nothing for the delay slot and we
-        are optimizing.  This is always used with '(' below.  */
-      /* Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
-        this is a dbx bug.  So, we only do this when optimizing.  */
-      /* On UltraSPARC, a branch in a delay slot causes a pipeline flush.
+        are optimizing.  This is always used with '(' below.
+         Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
+        this is a dbx bug.  So, we only do this when optimizing.
+         On UltraSPARC, a branch in a delay slot causes a pipeline flush.
         Always emit a nop in case the next instruction is a branch.  */
-      if (dbr_sequence_length () == 0
-         && (optimize && (int)sparc_cpu < PROCESSOR_V9))
+      if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9))
        fputs (",a", file);
       return;
     case '(':
       /* Output a 'nop' if there's nothing for the delay slot and we are
         not optimizing.  This is always used with '*' above.  */
-      if (dbr_sequence_length () == 0
-         && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
+      if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
        fputs ("\n\t nop", file);
+      else if (final_sequence)
+        sparc_indent_opcode = 1;
+      return;
+    case ')':
+      /* Output the right displacement from the saved PC on function return.
+        The caller may have placed an "unimp" insn immediately after the call
+        so we have to account for it.  This insn is used in the 32-bit ABI
+        when calling a function that returns a non zero-sized structure. The
+        64-bit ABI doesn't have it.  Be careful to have this test be the same
+        as that used on the call. The exception here is that when 
+        sparc_std_struct_return is enabled, the psABI is followed exactly
+        and the adjustment is made by the code in sparc_struct_value_rtx. 
+        The call emitted is the same when sparc_std_struct_return is 
+        present. */
+     if (! TARGET_ARCH64
+        && current_function_returns_struct
+        && ! sparc_std_struct_return
+        && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
+            == INTEGER_CST)
+        && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
+       fputs ("12", file);
+      else
+        fputc ('8', file);
       return;
     case '_':
       /* Output the Embedded Medium/Anywhere code model base register.  */
       fputs (EMBMEDANY_BASE_REG, file);
       return;
-    case '@':
-      /* Print out what we are using as the frame pointer.  This might
-        be %fp, or might be %sp+offset.  */
-      /* ??? What if offset is too big? Perhaps the caller knows it isn't? */
-      fprintf (file, "%s+"HOST_WIDE_INT_PRINT_DEC,
-              reg_names[REGNO (frame_base_reg)], frame_base_offset);
-      return;
     case '&':
       /* Print some local dynamic TLS name.  */
       assemble_name (file, get_some_local_dynamic_name ());
       return;
+
     case 'Y':
       /* Adjust the operand to take into account a RESTORE operation.  */
       if (GET_CODE (x) == CONST_INT)
@@ -7167,7 +6851,7 @@ print_operand (FILE *file, rtx x, int code)
          else if (GET_MODE (x) == CCXmode)
            fputs ("%xcc", file);
          else
-           abort ();
+           gcc_unreachable ();
        }
       else
        /* %fccN register */
@@ -7513,15 +7197,12 @@ sparc_type_code (register tree type)
          return (qualifiers | 7);      /* Who knows? */
 
        case VECTOR_TYPE:
-       case CHAR_TYPE:         /* GNU Pascal CHAR type.  Not used in C.  */
-       case BOOLEAN_TYPE:      /* GNU Fortran BOOLEAN type.  */
-       case FILE_TYPE:         /* GNU Pascal FILE type.  */
-       case SET_TYPE:          /* GNU Pascal SET type.  */
+       case BOOLEAN_TYPE:      /* Boolean truth value type.  */
        case LANG_TYPE:         /* ? */
          return qualifiers;
   
        default:
-         abort ();             /* Not a type! */
+         gcc_unreachable ();           /* Not a type! */
         }
     }
 
@@ -7589,7 +7270,9 @@ sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
      aligned on a 16 byte boundary so one flush clears it all.  */
   emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode, tramp))));
   if (sparc_cpu != PROCESSOR_ULTRASPARC
-      && sparc_cpu != PROCESSOR_ULTRASPARC3)
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
     emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
                                                     plus_constant (tramp, 8)))));
 
@@ -7631,7 +7314,9 @@ sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
   emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
 
   if (sparc_cpu != PROCESSOR_ULTRASPARC
-      && sparc_cpu != PROCESSOR_ULTRASPARC3)
+      && sparc_cpu != PROCESSOR_ULTRASPARC3
+      && sparc_cpu != PROCESSOR_NIAGARA
+      && sparc_cpu != PROCESSOR_NIAGARA2)
     emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
 
   /* Call __enable_execute_stack after writing onto the stack to make sure
@@ -7811,6 +7496,9 @@ sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
 static int
 sparc_use_sched_lookahead (void)
 {
+  if (sparc_cpu == PROCESSOR_NIAGARA
+      || sparc_cpu == PROCESSOR_NIAGARA2)
+    return 0;
   if (sparc_cpu == PROCESSOR_ULTRASPARC
       || sparc_cpu == PROCESSOR_ULTRASPARC3)
     return 4;
@@ -7826,6 +7514,8 @@ sparc_issue_rate (void)
 {
   switch (sparc_cpu)
     {
+    case PROCESSOR_NIAGARA:
+    case PROCESSOR_NIAGARA2:
     default:
       return 1;
     case PROCESSOR_V9:
@@ -7991,7 +7681,7 @@ sparc_output_deferred_case_vectors (void)
     return;
 
   /* Align to cache line in the function's code section.  */
-  function_section (current_function_decl);
+  switch_to_section (current_function_section ());
 
   align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
   if (align > 0)
@@ -8018,14 +7708,13 @@ sparc_check_64 (rtx x, rtx insn)
   int set_once = 0;
   rtx y = x;
 
-  if (GET_CODE (x) != REG)
-    abort ();
+  gcc_assert (GET_CODE (x) == REG);
 
   if (GET_MODE (x) == DImode)
     y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
 
   if (flag_expensive_optimizations
-      && REG_N_SETS (REGNO (y)) == 1)
+      && df && DF_REG_DEF_COUNT (REGNO (y)) == 1)
     set_once = 1;
 
   if (insn == 0)
@@ -8120,13 +7809,14 @@ sparc_profile_hook (int labelno)
 \f
 #ifdef OBJECT_FORMAT_ELF
 static void
-sparc_elf_asm_named_section (const char *name, unsigned int flags)
+sparc_elf_asm_named_section (const char *name, unsigned int flags,
+                            tree decl)
 {
   if (flags & SECTION_MERGE)
     {
       /* entsize cannot be expressed in this section attributes
         encoding style.  */
-      default_elf_asm_named_section (name, flags);
+      default_elf_asm_named_section (name, flags, decl);
       return;
     }
 
@@ -8164,13 +7854,19 @@ sparc_elf_asm_named_section (const char *name, unsigned int flags)
    the sibling call right?  Well, in the C++ case we can end up passing
    the pointer to the struct return area to a constructor (which returns
    void) and then nothing else happens.  Such a sibling call would look
-   valid without the added check here.  */
+   valid without the added check here.
+
+   VxWorks PIC PLT entries require the global pointer to be initialized
+   on entry.  We therefore can't emit sibling calls to them.  */
 static bool
 sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   return (decl
          && flag_delayed_branch
-         && (TARGET_ARCH64 || ! current_function_returns_struct));
+         && (TARGET_ARCH64 || ! current_function_returns_struct)
+         && !(TARGET_VXWORKS_RTP
+              && flag_pic
+              && !targetm.binds_local_p (decl)));
 }
 \f
 /* libfunc renaming.  */
@@ -8221,12 +7917,14 @@ sparc_init_libfuncs (void)
       set_conv_libfunc (sfix_optab,   SImode, TFmode, "_Q_qtoi");
       set_conv_libfunc (ufix_optab,   SImode, TFmode, "_Q_qtou");
       set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq");
+      set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq");
 
       if (DITF_CONVERSION_LIBFUNCS)
        {
          set_conv_libfunc (sfix_optab,   DImode, TFmode, "_Q_qtoll");
          set_conv_libfunc (ufix_optab,   DImode, TFmode, "_Q_qtoull");
          set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
+         set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq");
        }
 
       if (SUN_CONVERSION_LIBFUNCS)
@@ -8270,6 +7968,361 @@ sparc_init_libfuncs (void)
   gofast_maybe_init_libfuncs ();
 }
 \f
+#define def_builtin(NAME, CODE, TYPE) \
+  add_builtin_function((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, \
+                       NULL_TREE)
+
+/* Implement the TARGET_INIT_BUILTINS target hook.
+   Create builtin functions for special SPARC instructions.  */
+
+static void
+sparc_init_builtins (void)
+{
+  if (TARGET_VIS)
+    sparc_vis_init_builtins ();
+}
+
+/* Create builtin functions for VIS 1.0 instructions.  */
+
+static void
+sparc_vis_init_builtins (void)
+{
+  tree v4qi = build_vector_type (unsigned_intQI_type_node, 4);
+  tree v8qi = build_vector_type (unsigned_intQI_type_node, 8);
+  tree v4hi = build_vector_type (intHI_type_node, 4);
+  tree v2hi = build_vector_type (intHI_type_node, 2);
+  tree v2si = build_vector_type (intSI_type_node, 2);
+
+  tree v4qi_ftype_v4hi = build_function_type_list (v4qi, v4hi, 0);
+  tree v8qi_ftype_v2si_v8qi = build_function_type_list (v8qi, v2si, v8qi, 0);
+  tree v2hi_ftype_v2si = build_function_type_list (v2hi, v2si, 0);
+  tree v4hi_ftype_v4qi = build_function_type_list (v4hi, v4qi, 0);
+  tree v8qi_ftype_v4qi_v4qi = build_function_type_list (v8qi, v4qi, v4qi, 0);
+  tree v4hi_ftype_v4qi_v4hi = build_function_type_list (v4hi, v4qi, v4hi, 0);
+  tree v4hi_ftype_v4qi_v2hi = build_function_type_list (v4hi, v4qi, v2hi, 0);
+  tree v2si_ftype_v4qi_v2hi = build_function_type_list (v2si, v4qi, v2hi, 0);
+  tree v4hi_ftype_v8qi_v4hi = build_function_type_list (v4hi, v8qi, v4hi, 0);
+  tree v4hi_ftype_v4hi_v4hi = build_function_type_list (v4hi, v4hi, v4hi, 0);
+  tree v2si_ftype_v2si_v2si = build_function_type_list (v2si, v2si, v2si, 0);
+  tree v8qi_ftype_v8qi_v8qi = build_function_type_list (v8qi, v8qi, v8qi, 0);
+  tree di_ftype_v8qi_v8qi_di = build_function_type_list (intDI_type_node,
+                                                        v8qi, v8qi,
+                                                        intDI_type_node, 0);
+  tree di_ftype_di_di = build_function_type_list (intDI_type_node,
+                                                 intDI_type_node,
+                                                 intDI_type_node, 0);
+  tree ptr_ftype_ptr_si = build_function_type_list (ptr_type_node,
+                                                   ptr_type_node,
+                                                   intSI_type_node, 0);
+  tree ptr_ftype_ptr_di = build_function_type_list (ptr_type_node,
+                                                   ptr_type_node,
+                                                   intDI_type_node, 0);
+
+  /* Packing and expanding vectors.  */
+  def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis, v4qi_ftype_v4hi);
+  def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis,
+              v8qi_ftype_v2si_v8qi);
+  def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis,
+              v2hi_ftype_v2si);
+  def_builtin ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis, v4hi_ftype_v4qi);
+  def_builtin ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis,
+              v8qi_ftype_v4qi_v4qi);
+
+  /* Multiplications.  */
+  def_builtin ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis,
+              v4hi_ftype_v4qi_v4hi);
+  def_builtin ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis,
+              v4hi_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis,
+              v4hi_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis,
+              v4hi_ftype_v8qi_v4hi);
+  def_builtin ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis,
+              v4hi_ftype_v8qi_v4hi);
+  def_builtin ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis,
+              v2si_ftype_v4qi_v2hi);
+  def_builtin ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis,
+              v2si_ftype_v4qi_v2hi);
+
+  /* Data aligning.  */
+  def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis,
+              v4hi_ftype_v4hi_v4hi);
+  def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis,
+              v8qi_ftype_v8qi_v8qi);
+  def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis,
+              v2si_ftype_v2si_v2si);
+  def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatadi_vis,
+               di_ftype_di_di);
+  if (TARGET_ARCH64)
+    def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
+                ptr_ftype_ptr_di);
+  else
+    def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis,
+                ptr_ftype_ptr_si);
+
+  /* Pixel distance.  */
+  def_builtin ("__builtin_vis_pdist", CODE_FOR_pdist_vis,
+              di_ftype_v8qi_v8qi_di);
+}
+
+/* Handle TARGET_EXPAND_BUILTIN target hook.
+   Expand builtin functions for sparc intrinsics.  */
+
+static rtx
+sparc_expand_builtin (tree exp, rtx target,
+                     rtx subtarget ATTRIBUTE_UNUSED,
+                     enum machine_mode tmode ATTRIBUTE_UNUSED,
+                     int ignore ATTRIBUTE_UNUSED)
+{
+  tree arg;
+  call_expr_arg_iterator iter;
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
+  unsigned int icode = DECL_FUNCTION_CODE (fndecl);
+  rtx pat, op[4];
+  enum machine_mode mode[4];
+  int arg_count = 0;
+
+  mode[0] = insn_data[icode].operand[0].mode;
+  if (!target
+      || GET_MODE (target) != mode[0]
+      || ! (*insn_data[icode].operand[0].predicate) (target, mode[0]))
+    op[0] = gen_reg_rtx (mode[0]);
+  else
+    op[0] = target;
+
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
+    {
+      arg_count++;
+      mode[arg_count] = insn_data[icode].operand[arg_count].mode;
+      op[arg_count] = expand_normal (arg);
+
+      if (! (*insn_data[icode].operand[arg_count].predicate) (op[arg_count],
+                                                             mode[arg_count]))
+       op[arg_count] = copy_to_mode_reg (mode[arg_count], op[arg_count]);
+    }
+
+  switch (arg_count)
+    {
+    case 1:
+      pat = GEN_FCN (icode) (op[0], op[1]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2]);
+      break;
+    case 3:
+      pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (!pat)
+    return NULL_RTX;
+
+  emit_insn (pat);
+
+  return op[0];
+}
+
+static int
+sparc_vis_mul8x16 (int e8, int e16)
+{
+  return (e8 * e16 + 128) / 256;
+}
+
+/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified
+   by FNCODE.  All of the elements in ELTS0 and ELTS1 lists must be integer
+   constants.  A tree list with the results of the multiplications is returned,
+   and each element in the list is of INNER_TYPE.  */
+
+static tree
+sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
+{
+  tree n_elts = NULL_TREE;
+  int scale;
+
+  switch (fncode)
+    {
+    case CODE_FOR_fmul8x16_vis:
+      for (; elts0 && elts1;
+          elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                TREE_INT_CST_LOW (TREE_VALUE (elts1)));
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
+
+    case CODE_FOR_fmul8x16au_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
+
+    case CODE_FOR_fmul8x16al_vis:
+      scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1)));
+
+      for (; elts0; elts0 = TREE_CHAIN (elts0))
+       {
+         int val
+           = sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+                                scale);
+         n_elts = tree_cons (NULL_TREE,
+                             build_int_cst (inner_type, val),
+                             n_elts);
+       }
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return nreverse (n_elts);
+
+}
+/* Handle TARGET_FOLD_BUILTIN target hook.
+   Fold builtin functions for SPARC intrinsics.  If IGNORE is true the
+   result of the function call is ignored.  NULL_TREE is returned if the
+   function could not be folded.  */
+
+static tree
+sparc_fold_builtin (tree fndecl, tree arglist, bool ignore)
+{
+  tree arg0, arg1, arg2;
+  tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
+
+  if (ignore
+      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrsi_vis
+      && DECL_FUNCTION_CODE (fndecl) != CODE_FOR_alignaddrdi_vis)
+    return fold_convert (rtype, integer_zero_node);
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case CODE_FOR_fexpand_vis:
+      arg0 = TREE_VALUE (arglist);
+      STRIP_NOPS (arg0);
+
+      if (TREE_CODE (arg0) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts = TREE_VECTOR_CST_ELTS (arg0);
+         tree n_elts = NULL_TREE;
+
+         for (; elts; elts = TREE_CHAIN (elts))
+           {
+             unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4;
+             n_elts = tree_cons (NULL_TREE,
+                                 build_int_cst (inner_type, val),
+                                 n_elts);
+           }
+         return build_vector (rtype, nreverse (n_elts));
+       }
+      break;
+
+    case CODE_FOR_fmul8x16_vis:
+    case CODE_FOR_fmul8x16au_vis:
+    case CODE_FOR_fmul8x16al_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree inner_type = TREE_TYPE (rtype);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = sparc_handle_vis_mul8x16 (DECL_FUNCTION_CODE (fndecl),
+                                                 inner_type, elts0, elts1);
+
+         return build_vector (rtype, n_elts);
+       }
+      break;
+
+    case CODE_FOR_fpmerge_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+
+      if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
+       {
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+         tree n_elts = NULL_TREE;
+
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts);
+             n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts);
+           }
+
+         return build_vector (rtype, nreverse (n_elts));
+       }
+      break;
+
+    case CODE_FOR_pdist_vis:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      STRIP_NOPS (arg0);
+      STRIP_NOPS (arg1);
+      STRIP_NOPS (arg2);
+
+      if (TREE_CODE (arg0) == VECTOR_CST
+         && TREE_CODE (arg1) == VECTOR_CST
+         && TREE_CODE (arg2) == INTEGER_CST)
+       {
+         int overflow = 0;
+         unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2);
+         HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2);
+         tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
+         tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
+
+         for (; elts0 && elts1;
+              elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
+           {
+             unsigned HOST_WIDE_INT
+               low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)),
+               low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
+             HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0));
+             HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1));
+
+             unsigned HOST_WIDE_INT l;
+             HOST_WIDE_INT h;
+
+             overflow |= neg_double (low1, high1, &l, &h);
+             overflow |= add_double (low0, high0, l, h, &l, &h);
+             if (h < 0)
+               overflow |= neg_double (l, h, &l, &h);
+
+             overflow |= add_double (low, high, l, h, &low, &high);
+           }
+
+         gcc_assert (overflow == 0);
+
+         return build_int_cst_wide (rtype, low, high);
+       }
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+\f
 int
 sparc_extra_constraint_check (rtx op, int c, int strict)
 {
@@ -8303,6 +8356,9 @@ sparc_extra_constraint_check (rtx op, int c, int strict)
     case 'T':
       break;
 
+    case 'Y':
+      return const_zero_operand (op, GET_MODE (op));
+
     default:
       return 0;
     }
@@ -8360,12 +8416,12 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
       return true;
 
     case CONST_DOUBLE:
-      if (GET_MODE (x) == DImode
-         && ((XINT (x, 3) == 0
-              && (unsigned HOST_WIDE_INT) XINT (x, 2) < 0x1000)
-             || (XINT (x, 3) == -1
-                 && XINT (x, 2) < 0
-                 && XINT (x, 2) >= -0x1000)))
+      if (GET_MODE (x) == VOIDmode
+         && ((CONST_DOUBLE_HIGH (x) == 0
+              && CONST_DOUBLE_LOW (x) < 0x1000)
+             || (CONST_DOUBLE_HIGH (x) == -1
+                 && CONST_DOUBLE_LOW (x) < 0
+                 && CONST_DOUBLE_LOW (x) >= -0x1000)))
        *total = 0;
       else
        *total = 8;
@@ -8423,11 +8479,11 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
                    nbits++;
                }
              else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
-                      && GET_MODE (XEXP (x, 1)) == DImode)
+                      && GET_MODE (XEXP (x, 1)) == VOIDmode)
                {
                  rtx x1 = XEXP (x, 1);
-                 unsigned HOST_WIDE_INT value1 = XINT (x1, 2);
-                 unsigned HOST_WIDE_INT value2 = XINT (x1, 3);
+                 unsigned HOST_WIDE_INT value1 = CONST_DOUBLE_LOW (x1);
+                 unsigned HOST_WIDE_INT value2 = CONST_DOUBLE_HIGH (x1);
 
                  for (nbits = 0; value1 != 0; value1 &= value1 - 1)
                    nbits++;
@@ -8515,42 +8571,71 @@ sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
        *total = sparc_costs->int_cmove;
       return false;
 
+    case IOR:
+      /* Handle the NAND vector patterns.  */
+      if (sparc_vector_mode_supported_p (GET_MODE (x))
+         && GET_CODE (XEXP (x, 0)) == NOT
+         && GET_CODE (XEXP (x, 1)) == NOT)
+       {
+         *total = COSTS_N_INSNS (1);
+         return true;
+       }
+      else
+        return false;
+
     default:
       return false;
     }
 }
 
-/* Emit the sequence of insns SEQ while preserving the register REG.  */
+/* Emit the sequence of insns SEQ while preserving the registers REG and REG2.
+   This is achieved by means of a manual dynamic stack space allocation in
+   the current frame.  We make the assumption that SEQ doesn't contain any
+   function calls, with the possible exception of calls to the PIC helper.  */
 
 static void
-emit_and_preserve (rtx seq, rtx reg)
+emit_and_preserve (rtx seq, rtx reg, rtx reg2)
 {
-  rtx slot = gen_rtx_MEM (word_mode,
-                         plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS));
+  /* We must preserve the lowest 16 words for the register save area.  */
+  HOST_WIDE_INT offset = 16*UNITS_PER_WORD;
+  /* We really need only 2 words of fresh stack space.  */
+  HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD);
 
-  emit_stack_pointer_decrement (GEN_INT (UNITS_PER_WORD));
+  rtx slot
+    = gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx,
+                                            SPARC_STACK_BIAS + offset));
+
+  emit_insn (gen_stack_pointer_dec (GEN_INT (size)));
   emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD),
+                           reg2));
   emit_insn (seq);
+  if (reg2)
+    emit_insn (gen_rtx_SET (VOIDmode,
+                           reg2,
+                           adjust_address (slot, word_mode, UNITS_PER_WORD)));
   emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
-  emit_stack_pointer_increment (GEN_INT (UNITS_PER_WORD));
+  emit_insn (gen_stack_pointer_inc (GEN_INT (size)));
 }
 
-/* Output code to add DELTA to the first argument, and then jump to FUNCTION.
-   Used for C++ multiple inheritance.  */
+/* Output the assembler code for a thunk function.  THUNK_DECL is the
+   declaration for the thunk function itself, FUNCTION is the decl for
+   the target function.  DELTA is an immediate constant offset to be
+   added to THIS.  If VCALL_OFFSET is nonzero, the word at address
+   (*THIS + VCALL_OFFSET) should be additionally added to THIS.  */
 
 static void
 sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
-                      HOST_WIDE_INT delta,
-                      HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                      HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
                       tree function)
 {
-  rtx this, insn, funexp, delta_rtx;
+  rtx this, insn, funexp;
   unsigned int int_arg_first;
 
   reload_completed = 1;
   epilogue_completed = 1;
-  no_new_pseudos = 1;
-  reset_block_changes ();
 
   emit_note (NOTE_INSN_PROLOGUE_END);
 
@@ -8558,7 +8643,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* We will emit a regular sibcall below, so we need to instruct
         output_sibcall that we are in a leaf function.  */
-      current_function_uses_only_leaf_regs = 1;
+      sparc_leaf_function_p = current_function_uses_only_leaf_regs = 1;
 
       /* This will cause final.c to invoke leaf_renumber_regs so we
         must behave as if we were in a not-yet-leafified function.  */
@@ -8568,7 +8653,7 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* We will emit the sibcall manually below, so we will need to
         manually spill non-leaf registers.  */
-      current_function_uses_only_leaf_regs = 0;
+      sparc_leaf_function_p = current_function_uses_only_leaf_regs = 0;
 
       /* We really are in a leaf function.  */
       int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
@@ -8583,27 +8668,72 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
   /* Add DELTA.  When possible use a plain add, otherwise load it into
      a register first.  */
-  delta_rtx = GEN_INT (delta);
-  if (!SPARC_SIMM13_P (delta))
+  if (delta)
+    {
+      rtx delta_rtx = GEN_INT (delta);
+
+      if (! SPARC_SIMM13_P (delta))
+       {
+         rtx scratch = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (scratch, delta_rtx);
+         delta_rtx = scratch;
+       }
+
+      /* THIS += DELTA.  */
+      emit_insn (gen_add2_insn (this, delta_rtx));
+    }
+
+  /* Add the word at address (*THIS + VCALL_OFFSET).  */
+  if (vcall_offset)
     {
+      rtx vcall_offset_rtx = GEN_INT (vcall_offset);
       rtx scratch = gen_rtx_REG (Pmode, 1);
 
-      if (input_operand (delta_rtx, GET_MODE (scratch)))
-       emit_insn (gen_rtx_SET (VOIDmode, scratch, delta_rtx));
+      gcc_assert (vcall_offset < 0);
+
+      /* SCRATCH = *THIS.  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode, this));
+
+      /* Prepare for adding VCALL_OFFSET.  The difficulty is that we
+        may not have any available scratch register at this point.  */
+      if (SPARC_SIMM13_P (vcall_offset))
+       ;
+      /* This is the case if ARCH64 (unless -ffixed-g5 is passed).  */
+      else if (! fixed_regs[5]
+              /* The below sequence is made up of at least 2 insns,
+                 while the default method may need only one.  */
+              && vcall_offset < -8192)
+       {
+         rtx scratch2 = gen_rtx_REG (Pmode, 5);
+         emit_move_insn (scratch2, vcall_offset_rtx);
+         vcall_offset_rtx = scratch2;
+       }
       else
        {
-         if (TARGET_ARCH64)
-           sparc_emit_set_const64 (scratch, delta_rtx);
-         else
-           sparc_emit_set_const32 (scratch, delta_rtx);
+         rtx increment = GEN_INT (-4096);
+
+         /* VCALL_OFFSET is a negative number whose typical range can be
+            estimated as -32768..0 in 32-bit mode.  In almost all cases
+            it is therefore cheaper to emit multiple add insns than
+            spilling and loading the constant into a register (at least
+            6 insns).  */
+         while (! SPARC_SIMM13_P (vcall_offset))
+           {
+             emit_insn (gen_add2_insn (scratch, increment));
+             vcall_offset += 4096;
+           }
+         vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
        }
 
-      delta_rtx = scratch;
-    }
+      /* SCRATCH = *(*THIS + VCALL_OFFSET).  */
+      emit_move_insn (scratch, gen_rtx_MEM (Pmode,
+                                           gen_rtx_PLUS (Pmode,
+                                                         scratch,
+                                                         vcall_offset_rtx)));
 
-  emit_insn (gen_rtx_SET (VOIDmode,
-                         this,
-                         gen_rtx_PLUS (Pmode, this, delta_rtx)));
+      /* THIS += *(*THIS + VCALL_OFFSET).  */
+      emit_insn (gen_add2_insn (this, scratch));
+    }
 
   /* Generate a tail call to the target function.  */
   if (! TREE_USED (function))
@@ -8623,17 +8753,20 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
     {
       /* The hoops we have to jump through in order to generate a sibcall
         without using delay slots...  */
-      rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1);
+      rtx spill_reg, spill_reg2, seq, scratch = gen_rtx_REG (Pmode, 1);
 
       if (flag_pic)
         {
          spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
+         spill_reg2 = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
          start_sequence ();
-         load_pic_register ();  /* clobbers %o7 */
+         /* Delay emitting the PIC helper function because it needs to
+            change the section and we are emitting assembly code.  */
+         load_pic_register (true);  /* clobbers %o7 */
          scratch = legitimize_pic_address (funexp, Pmode, scratch);
          seq = get_insns ();
          end_sequence ();
-         emit_and_preserve (seq, spill_reg);
+         emit_and_preserve (seq, spill_reg, spill_reg2);
        }
       else if (TARGET_ARCH32)
        {
@@ -8662,11 +8795,11 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
              sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
              seq = get_insns ();
              end_sequence ();
-             emit_and_preserve (seq, spill_reg);
+             emit_and_preserve (seq, spill_reg, 0);
              break;
 
            default:
-             abort();
+             gcc_unreachable ();
            }
        }
 
@@ -8680,15 +8813,28 @@ sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
+  final (insn, file, 1);
   final_end_function ();
+  free_after_compilation (cfun);
 
   reload_completed = 0;
   epilogue_completed = 0;
-  no_new_pseudos = 0;
+}
+
+/* Return true if sparc_output_mi_thunk would be able to output the
+   assembler code for the thunk function specified by the arguments
+   it is passed, and false otherwise.  */
+static bool
+sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
+                          HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
+                          HOST_WIDE_INT vcall_offset,
+                          const_tree function ATTRIBUTE_UNUSED)
+{
+  /* Bound the loop used in the default method above.  */
+  return (vcall_offset >= -32768 || ! fixed_regs[5]);
 }
 
 /* How to allocate a 'struct machine_function'.  */
@@ -8715,7 +8861,7 @@ get_some_local_dynamic_name (void)
        && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
       return cfun->machine->some_ld_name;
 
-  abort ();
+  gcc_unreachable ();
 }
 
 static int
@@ -8734,10 +8880,22 @@ get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
   return 0;
 }
 
-/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+/* Handle the TARGET_DWARF_HANDLE_FRAME_UNSPEC hook.
+   This is called from dwarf2out.c to emit call frame instructions
+   for frame-related insns containing UNSPECs and UNSPEC_VOLATILEs. */
+static void
+sparc_dwarf_handle_frame_unspec (const char *label,
+                                rtx pattern ATTRIBUTE_UNUSED,
+                                int index ATTRIBUTE_UNUSED)
+{
+  gcc_assert (index == UNSPECV_SAVEW);
+  dwarf2out_window_save (label);
+}
+
+/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
    We need to emit DTP-relative relocations.  */
 
-void
+static void
 sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
 {
   switch (size)
@@ -8749,10 +8907,142 @@ sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
       fputs ("\t.xword\t%r_tls_dtpoff64(", file);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   output_addr_const (file, x);
   fputs (")", file);
 }
 
+/* Do whatever processing is required at the end of a file.  */
+
+static void
+sparc_file_end (void)
+{
+  /* If we haven't emitted the special PIC helper function, do so now.  */
+  if (pic_helper_symbol_name[0] && !pic_helper_emitted_p)
+    emit_pic_helper ();
+
+  if (NEED_INDICATE_EXEC_STACK)
+    file_end_indicate_exec_stack ();
+}
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_TYPE.  */
+
+static const char *
+sparc_mangle_type (const_tree type)
+{
+  if (!TARGET_64BIT
+      && TYPE_MAIN_VARIANT (type) == long_double_type_node
+      && TARGET_LONG_DOUBLE_128)
+    return "g";
+
+  /* For all other types, use normal C++ mangling.  */
+  return NULL;
+}
+#endif
+
+/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
+   compare and swap on the word containing the byte or half-word.  */
+
+void
+sparc_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
+{
+  rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
+  rtx addr = gen_reg_rtx (Pmode);
+  rtx off = gen_reg_rtx (SImode);
+  rtx oldv = gen_reg_rtx (SImode);
+  rtx newv = gen_reg_rtx (SImode);
+  rtx oldvalue = gen_reg_rtx (SImode);
+  rtx newvalue = gen_reg_rtx (SImode);
+  rtx res = gen_reg_rtx (SImode);
+  rtx resv = gen_reg_rtx (SImode);
+  rtx memsi, val, mask, end_label, loop_label, cc;
+
+  emit_insn (gen_rtx_SET (VOIDmode, addr,
+                         gen_rtx_AND (Pmode, addr1, GEN_INT (-4))));
+
+  if (Pmode != SImode)
+    addr1 = gen_lowpart (SImode, addr1);
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_AND (SImode, addr1, GEN_INT (3))));
+
+  memsi = gen_rtx_MEM (SImode, addr);
+  set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
+
+  val = force_reg (SImode, memsi);
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_XOR (SImode, off,
+                                      GEN_INT (GET_MODE (mem) == QImode
+                                               ? 3 : 2))));
+
+  emit_insn (gen_rtx_SET (VOIDmode, off,
+                         gen_rtx_ASHIFT (SImode, off, GEN_INT (3))));
+
+  if (GET_MODE (mem) == QImode)
+    mask = force_reg (SImode, GEN_INT (0xff));
+  else
+    mask = force_reg (SImode, GEN_INT (0xffff));
+
+  emit_insn (gen_rtx_SET (VOIDmode, mask,
+                         gen_rtx_ASHIFT (SImode, mask, off)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, val,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      val)));
+
+  oldval = gen_lowpart (SImode, oldval);
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_ASHIFT (SImode, oldval, off)));
+
+  newval = gen_lowpart_common (SImode, newval);
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_ASHIFT (SImode, newval, off)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, oldv,
+                         gen_rtx_AND (SImode, oldv, mask)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, newv,
+                         gen_rtx_AND (SImode, newv, mask)));
+
+  end_label = gen_label_rtx ();
+  loop_label = gen_label_rtx ();
+  emit_label (loop_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, oldvalue,
+                         gen_rtx_IOR (SImode, oldv, val)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, newvalue,
+                         gen_rtx_IOR (SImode, newv, val)));
+
+  emit_insn (gen_sync_compare_and_swapsi (res, memsi, oldvalue, newvalue));
+
+  emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, resv,
+                         gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
+                                      res)));
+
+  sparc_compare_op0 = resv;
+  sparc_compare_op1 = val;
+  cc = gen_compare_reg (NE);
+
+  emit_insn (gen_rtx_SET (VOIDmode, val, resv));
+
+  sparc_compare_emitted = cc;
+  emit_jump_insn (gen_bne (loop_label));
+
+  emit_label (end_label);
+
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_AND (SImode, res, mask)));
+
+  emit_insn (gen_rtx_SET (VOIDmode, res,
+                         gen_rtx_LSHIFTRT (SImode, res, off)));
+
+  emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
+}
+
 #include "gt-sparc.h"