OSDN Git Service

* final.c (output_in_slot): New global variable.
[pf3gnuchains/gcc-fork.git] / gcc / config / sparc / sparc.c
index 3be2f9d..cf7ac04 100644 (file)
@@ -1,24 +1,24 @@
-/* Subroutines for insn-output.c for Sun SPARC.
+/* Subroutines for insn-output.c for SPARC.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
-   64 bit SPARC V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
+   64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
    at Cygnus Support.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+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)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 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 GNU CC; see the file COPYING.  If not, write to
+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.  */
 
@@ -39,7 +39,6 @@ Boston, MA 02111-1307, USA.  */
 #include "function.h"
 #include "expr.h"
 #include "optabs.h"
-#include "libfuncs.h"
 #include "recog.h"
 #include "toplev.h"
 #include "ggc.h"
@@ -47,41 +46,189 @@ Boston, MA 02111-1307, USA.  */
 #include "debug.h"
 #include "target.h"
 #include "target-def.h"
+#include "cfglayout.h"
+#include "tree-gimple.h"
+
+/* Processor costs */
+static const
+struct processor_costs cypress_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (2), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (5), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (5), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (7), /* fmul */
+  COSTS_N_INSNS (37), /* fdivs */
+  COSTS_N_INSNS (37), /* fdivd */
+  COSTS_N_INSNS (63), /* fsqrts */
+  COSTS_N_INSNS (63), /* fsqrtd */
+  COSTS_N_INSNS (1), /* imul */
+  COSTS_N_INSNS (1), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (1), /* idiv */
+  COSTS_N_INSNS (1), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs supersparc_costs = {
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (0), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (3), /* fadd, fsub */
+  COSTS_N_INSNS (3), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (3), /* fmul */
+  COSTS_N_INSNS (6), /* fdivs */
+  COSTS_N_INSNS (9), /* fdivd */
+  COSTS_N_INSNS (12), /* fsqrts */
+  COSTS_N_INSNS (12), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (4), /* idiv */
+  COSTS_N_INSNS (4), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  1, /* shift penalty */
+};
+
+static const
+struct processor_costs hypersparc_costs = {
+  COSTS_N_INSNS (1), /* int load */
+  COSTS_N_INSNS (1), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (8), /* fdivs */
+  COSTS_N_INSNS (12), /* fdivd */
+  COSTS_N_INSNS (17), /* fsqrts */
+  COSTS_N_INSNS (17), /* fsqrtd */
+  COSTS_N_INSNS (17), /* imul */
+  COSTS_N_INSNS (17), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (17), /* idiv */
+  COSTS_N_INSNS (17), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs sparclet_costs = {
+  COSTS_N_INSNS (3), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (1), /* int zeroed load */
+  COSTS_N_INSNS (1), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (1), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (1), /* fmov, fmovr */
+  COSTS_N_INSNS (1), /* fmul */
+  COSTS_N_INSNS (1), /* fdivs */
+  COSTS_N_INSNS (1), /* fdivd */
+  COSTS_N_INSNS (1), /* fsqrts */
+  COSTS_N_INSNS (1), /* fsqrtd */
+  COSTS_N_INSNS (5), /* imul */
+  COSTS_N_INSNS (5), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (5), /* idiv */
+  COSTS_N_INSNS (5), /* idivX */
+  COSTS_N_INSNS (1), /* movcc/movr */
+  0, /* shift penalty */
+};
+
+static const
+struct processor_costs ultrasparc_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (2), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (1), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (1), /* fcmp */
+  COSTS_N_INSNS (2), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (13), /* fdivs */
+  COSTS_N_INSNS (23), /* fdivd */
+  COSTS_N_INSNS (13), /* fsqrts */
+  COSTS_N_INSNS (23), /* fsqrtd */
+  COSTS_N_INSNS (4), /* imul */
+  COSTS_N_INSNS (4), /* imulX */
+  2, /* imul bit factor */
+  COSTS_N_INSNS (37), /* idiv */
+  COSTS_N_INSNS (68), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
+  2, /* shift penalty */
+};
+
+static const
+struct processor_costs ultrasparc3_costs = {
+  COSTS_N_INSNS (2), /* int load */
+  COSTS_N_INSNS (3), /* int signed load */
+  COSTS_N_INSNS (3), /* int zeroed load */
+  COSTS_N_INSNS (2), /* float load */
+  COSTS_N_INSNS (3), /* fmov, fneg, fabs */
+  COSTS_N_INSNS (4), /* fadd, fsub */
+  COSTS_N_INSNS (5), /* fcmp */
+  COSTS_N_INSNS (3), /* fmov, fmovr */
+  COSTS_N_INSNS (4), /* fmul */
+  COSTS_N_INSNS (17), /* fdivs */
+  COSTS_N_INSNS (20), /* fdivd */
+  COSTS_N_INSNS (20), /* fsqrts */
+  COSTS_N_INSNS (29), /* fsqrtd */
+  COSTS_N_INSNS (6), /* imul */
+  COSTS_N_INSNS (6), /* imulX */
+  0, /* imul bit factor */
+  COSTS_N_INSNS (40), /* idiv */
+  COSTS_N_INSNS (71), /* idivX */
+  COSTS_N_INSNS (2), /* movcc/movr */
+  0, /* shift penalty */
+};
 
-/* 1 if the caller has placed an "unimp" insn immediately after the call.
-   This is used in v8 code when calling a function that returns a structure.
-   v9 doesn't have this.  Be careful to have this test be the same as that
-   used on the call.  */
+const struct processor_costs *sparc_costs = &cypress_costs;
 
-#define SKIP_CALLERS_UNIMP_P  \
-(!TARGET_ARCH64 && current_function_returns_struct                     \
- && ! integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl)))  \
- && (TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))       \
-     == INTEGER_CST))
+#ifdef HAVE_AS_RELAX_OPTION
+/* If 'as' and 'ld' are relaxing tail call insns into branch always, use
+   "or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized.
+   With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if
+   somebody does not branch between the sethi and jmp.  */
+#define LEAF_SIBCALL_SLOT_RESERVED_P 1
+#else
+#define LEAF_SIBCALL_SLOT_RESERVED_P \
+  ((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
+#endif
 
 /* Global variables for machine-dependent things.  */
 
 /* Size of frame.  Need to know this to emit return insns from leaf procedures.
-   ACTUAL_FSIZE is set by compute_frame_size() which is called during the
-   reload pass.  This is important as the value is later used in insn
-   scheduling (to see what can go in a delay slot).
+   ACTUAL_FSIZE is set by sparc_compute_frame_size() which is called during the
+   reload pass.  This is important as the value is later used for scheduling
+   (to see what can go in a delay slot).
    APPARENT_FSIZE is the size of the stack less the register save area and less
    the outgoing argument area.  It is used when saving call preserved regs.  */
-static int apparent_fsize;
-static int actual_fsize;
+static HOST_WIDE_INT apparent_fsize;
+static HOST_WIDE_INT actual_fsize;
 
 /* Number of live general or floating point registers needed to be
    saved (as 4-byte quantities).  */
 static int num_gfregs;
 
+/* The alias set for prologue/epilogue register save/restore.  */
+static GTY(()) int sparc_sr_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;
 
-/* Coordinate with the md file wrt special insns created by
-   sparc_nonflat_function_epilogue.  */
-bool sparc_emitting_epilogue;
-
 /* Vector to say how input registers are mapped to output registers.
    HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
    eliminate it.  You must use -fomit-frame-pointer to get that.  */
@@ -119,68 +266,77 @@ char sparc_leaf_regs[] =
   1, 1, 1, 1, 1, 1, 1, 1,
   1, 1, 1, 1, 1};
 
-/* Name of where we pretend to think the frame pointer points.
-   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 const char *frame_base_name;
-static int frame_base_offset;
-
-static void sparc_init_modes   PARAMS ((void));
-static int save_regs           PARAMS ((FILE *, int, int, const char *,
-                                      int, int, int));
-static int restore_regs                PARAMS ((FILE *, int, int, const char *, int, int));
-static void build_big_number   PARAMS ((FILE *, int, const char *));
-static int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *,
-                                      enum machine_mode, tree, int, int,
-                                      int *, int *));
-
-static int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
-static int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
-
-static void sparc_output_addr_vec PARAMS ((rtx));
-static void sparc_output_addr_diff_vec PARAMS ((rtx));
-static void sparc_output_deferred_case_vectors PARAMS ((void));
-static int check_return_regs PARAMS ((rtx));
-static int epilogue_renumber PARAMS ((rtx *, int));
-static bool sparc_assemble_integer PARAMS ((rtx, unsigned int, int));
-static int set_extends PARAMS ((rtx));
-static void output_restore_regs PARAMS ((FILE *, int));
-static void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-static void sparc_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-static void sparc_flat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
-static void sparc_flat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
-static void sparc_nonflat_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT,
-                                                    int));
-static void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT,
-                                                    int));
+struct machine_function GTY(())
+{
+  /* Some local-dynamic TLS symbol name.  */
+  const char *some_ld_name;
+};
+
+/* 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;
+
+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,
+                               tree, int, int, int *, int *);
+
+static int supersparc_adjust_cost (rtx, rtx, rtx, int);
+static int hypersparc_adjust_cost (rtx, rtx, rtx, int);
+
+static void sparc_output_addr_vec (rtx);
+static void sparc_output_addr_diff_vec (rtx);
+static void sparc_output_deferred_case_vectors (void);
+static 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 int save_or_restore_regs (int, int, rtx, int, int);
+static void emit_save_regs (void);
+static void emit_restore_regs (void);
+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 PARAMS ((const char *, unsigned int));
+static void sparc_elf_asm_named_section (const char *, unsigned int);
+#endif
+
+static int sparc_adjust_cost (rtx, rtx, rtx, int);
+static int sparc_issue_rate (void);
+static void sparc_sched_init (FILE *, int, int);
+static int sparc_use_sched_lookahead (void);
+
+static void emit_soft_tfmode_libcall (const char *, int, rtx *);
+static void emit_soft_tfmode_binop (enum rtx_code, rtx *);
+static void emit_soft_tfmode_unop (enum rtx_code, rtx *);
+static void emit_soft_tfmode_cvt (enum rtx_code, rtx *);
+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_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
+                                  HOST_WIDE_INT, tree);
+static struct machine_function * sparc_init_machine_status (void);
+static bool sparc_cannot_force_const_mem (rtx);
+static rtx sparc_tls_get_addr (void);
+static rtx sparc_tls_got (void);
+static const char *get_some_local_dynamic_name (void);
+static int get_some_local_dynamic_name_1 (rtx *, void *);
+static bool sparc_rtx_costs (rtx, int, int, int *);
+static bool sparc_promote_prototypes (tree);
+static rtx sparc_struct_value_rtx (tree, int);
+static bool sparc_return_in_memory (tree, tree);
+static bool sparc_strict_argument_naming (CUMULATIVE_ARGS *);
+static tree sparc_gimplify_va_arg (tree, tree, tree *, tree *);
+static bool sparc_pass_by_reference (CUMULATIVE_ARGS *,
+                                    enum machine_mode, tree, bool);
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+const struct attribute_spec sparc_attribute_table[];
 #endif
-static void sparc_aout_select_section PARAMS ((tree, int,
-                                              unsigned HOST_WIDE_INT))
-     ATTRIBUTE_UNUSED;
-static void sparc_aout_select_rtx_section PARAMS ((enum machine_mode, rtx,
-                                                  unsigned HOST_WIDE_INT))
-     ATTRIBUTE_UNUSED;
-
-static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
-static int sparc_issue_rate PARAMS ((void));
-static void sparc_sched_init PARAMS ((FILE *, int, int));
-static int sparc_use_dfa_pipeline_interface PARAMS ((void));
-static int sparc_use_sched_lookahead PARAMS ((void));
-
-static void emit_soft_tfmode_libcall PARAMS ((const char *, int, rtx *));
-static void emit_soft_tfmode_binop PARAMS ((enum rtx_code, rtx *));
-static void emit_soft_tfmode_unop PARAMS ((enum rtx_code, rtx *));
-static void emit_soft_tfmode_cvt PARAMS ((enum rtx_code, rtx *));
-static void emit_hard_tfmode_operation PARAMS ((enum rtx_code, rtx *));
-
-static bool sparc_function_ok_for_sibcall PARAMS ((tree, tree));
-static void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT,
-                                          HOST_WIDE_INT, tree));
-static bool sparc_rtx_costs PARAMS ((rtx, int, int, int *));
 \f
 /* Option handling.  */
 
@@ -226,9 +382,9 @@ enum processor_type sparc_cpu;
 #define TARGET_ASM_INTEGER sparc_assemble_integer
 
 #undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE sparc_output_function_prologue
+#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue
 #undef TARGET_ASM_FUNCTION_EPILOGUE
-#define TARGET_ASM_FUNCTION_EPILOGUE sparc_output_function_epilogue
+#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue
 
 #undef TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
@@ -236,14 +392,22 @@ enum processor_type sparc_cpu;
 #define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
 #undef TARGET_SCHED_INIT
 #define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
 #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
 #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall
 
+#undef TARGET_INIT_LIBFUNCS
+#define TARGET_INIT_LIBFUNCS sparc_init_libfuncs
+
+#ifdef HAVE_AS_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
@@ -254,13 +418,58 @@ enum processor_type sparc_cpu;
 #undef TARGET_ADDRESS_COST
 #define TARGET_ADDRESS_COST hook_int_rtx_0
 
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+
+/* This is only needed for TARGET_ARCH64, but since PROMOTE_FUNCTION_MODE is a
+   no-op for TARGET_ARCH32 this is ok.  Otherwise we'd need to add a runtime
+   test for this value.  */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES sparc_promote_prototypes
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
+
+#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_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
+
+#ifdef SUBTARGET_INSERT_ATTRIBUTES
+#undef TARGET_INSERT_ATTRIBUTES
+#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
+#endif
+
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
+#endif
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Validate and override various options, and do some machine dependent
    initialization.  */
 
 void
-sparc_override_options ()
+sparc_override_options (void)
 {
   static struct code_model {
     const char *const name;
@@ -452,16 +661,61 @@ sparc_override_options ()
 
   /* Do various machine dependent initializations.  */
   sparc_init_modes ();
+
+  /* Acquire a unique set number for our register saves and restores.  */
+  sparc_sr_alias_set = new_alias_set ();
+
+  /* Set up function hooks.  */
+  init_machine_status = sparc_init_machine_status;
+
+  switch (sparc_cpu)
+    {
+    case PROCESSOR_V7:
+    case PROCESSOR_CYPRESS:
+      sparc_costs = &cypress_costs;
+      break;
+    case PROCESSOR_V8:
+    case PROCESSOR_SPARCLITE:
+    case PROCESSOR_SUPERSPARC:
+      sparc_costs = &supersparc_costs;
+      break;
+    case PROCESSOR_F930:
+    case PROCESSOR_F934:
+    case PROCESSOR_HYPERSPARC:
+    case PROCESSOR_SPARCLITE86X:
+      sparc_costs = &hypersparc_costs;
+      break;
+    case PROCESSOR_SPARCLET:
+    case PROCESSOR_TSC701:
+      sparc_costs = &sparclet_costs;
+      break;
+    case PROCESSOR_V9:
+    case PROCESSOR_ULTRASPARC:
+      sparc_costs = &ultrasparc_costs;
+      break;
+    case PROCESSOR_ULTRASPARC3:
+      sparc_costs = &ultrasparc3_costs;
+      break;
+    };
 }
 \f
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+/* Table of valid machine attributes.  */
+const struct attribute_spec sparc_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  SUBTARGET_ATTRIBUTE_TABLE,
+  { NULL,        0, 0, false, false, false, NULL }
+};
+#endif
+\f
 /* Miscellaneous utilities.  */
 
 /* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
    or branch on register contents instructions.  */
 
 int
-v9_regcmp_p (code)
-     enum rtx_code code;
+v9_regcmp_p (enum rtx_code code)
 {
   return (code == EQ || code == NE || code == GE || code == LT
          || code == LE || code == GT);
@@ -474,9 +728,7 @@ v9_regcmp_p (code)
    or const0_rtx.  */
 
 int
-reg_or_0_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+reg_or_0_operand (rtx op, enum machine_mode mode)
 {
   if (register_operand (op, mode))
     return 1;
@@ -494,9 +746,7 @@ reg_or_0_operand (op, mode)
 /* Return nonzero only if OP is const1_rtx.  */
 
 int
-const1_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+const1_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return op == const1_rtx;
 }
@@ -504,9 +754,7 @@ const1_operand (op, mode)
 /* Nonzero if OP is a floating point value with value 0.0.  */
 
 int
-fp_zero_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+fp_zero_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE_CLASS (GET_MODE (op)) != MODE_FLOAT)
     return 0;
@@ -516,9 +764,7 @@ fp_zero_operand (op, mode)
 /* Nonzero if OP is a register operand in floating point register.  */
 
 int
-fp_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+fp_register_operand (rtx op, enum machine_mode mode)
 {
   if (! register_operand (op, mode))
     return 0;
@@ -532,8 +778,7 @@ fp_register_operand (op, mode)
    sethi instruction.  */
 
 int
-fp_sethi_p (op)
-     rtx op;
+fp_sethi_p (rtx op)
 {
   if (GET_CODE (op) == CONST_DOUBLE)
     {
@@ -557,8 +802,7 @@ fp_sethi_p (op)
    mov instruction.  */
 
 int
-fp_mov_p (op)
-     rtx op;
+fp_mov_p (rtx op)
 {
   if (GET_CODE (op) == CONST_DOUBLE)
     {
@@ -582,8 +826,7 @@ fp_mov_p (op)
    instruction sequence.  */
 
 int
-fp_high_losum_p (op)
-     rtx op;
+fp_high_losum_p (rtx op)
 {
   /* The constraints calling this should only be in
      SFmode move insns, so any constant which cannot
@@ -609,9 +852,7 @@ fp_high_losum_p (op)
 /* Nonzero if OP is an integer register.  */
 
 int
-intreg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+intreg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (register_operand (op, SImode)
          || (TARGET_ARCH64 && register_operand (op, DImode)));
@@ -620,9 +861,7 @@ intreg_operand (op, mode)
 /* Nonzero if OP is a floating point condition code register.  */
 
 int
-fcc_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+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.  */
@@ -647,9 +886,7 @@ fcc_reg_operand (op, mode)
 /* Nonzero if OP is a floating point condition code fcc0 register.  */
 
 int
-fcc0_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+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.  */
@@ -668,9 +905,7 @@ fcc0_reg_operand (op, mode)
 /* Nonzero if OP is an integer or floating point condition code register.  */
 
 int
-icc_or_fcc_reg_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+icc_or_fcc_reg_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) == REG && REGNO (op) == SPARC_ICC_REG)
     {
@@ -685,23 +920,11 @@ icc_or_fcc_reg_operand (op, mode)
   return fcc_reg_operand (op, mode);
 }
 
-/* Nonzero if OP can appear as the dest of a RESTORE insn.  */
-int
-restore_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
-{
-  return (GET_CODE (op) == REG && GET_MODE (op) == mode
-         && (REGNO (op) < 8 || (REGNO (op) >= 24 && REGNO (op) < 32)));
-}
-
 /* Call insn on SPARC can take a PC-relative constant address, or any regular
    memory address.  */
 
 int
-call_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+call_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) != MEM)
     abort ();
@@ -710,20 +933,51 @@ call_operand (op, mode)
 }
 
 int
-call_operand_address (op, mode)
-     rtx op;
-     enum machine_mode mode;
+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 (op, mode)
-     register rtx op;
-     enum machine_mode mode;
+symbolic_operand (register rtx op, enum machine_mode mode)
 {
   enum machine_mode omode = GET_MODE (op);
 
@@ -733,12 +987,15 @@ symbolic_operand (op, mode)
   switch (GET_CODE (op))
     {
     case SYMBOL_REF:
+      return !SYMBOL_REF_TLS_MODEL (op);
+
     case LABEL_REF:
       return 1;
 
     case CONST:
       op = XEXP (op, 0);
-      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+      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);
 
@@ -751,25 +1008,22 @@ symbolic_operand (op, mode)
    operand of mode MODE.  */
 
 int
-symbolic_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+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 || GET_CODE (op) == CONST
-         || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
+  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 (op, mode)
-     rtx op;
-     enum machine_mode mode;
+label_ref_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) != LABEL_REF)
     return 0;
@@ -782,9 +1036,7 @@ label_ref_operand (op, mode)
    in either the medium/low or medium/anywhere code models of sparc64.  */
 
 int
-sp64_medium_pic_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+sp64_medium_pic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   /* Check for (const (minus (symbol_ref:GOT)
                              (const (minus (label) (pc))))).  */
@@ -809,9 +1061,7 @@ sp64_medium_pic_operand (op, mode)
    are accessed with EMBMEDANY_BASE_REG.  */
 
 int
-data_segment_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+data_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   switch (GET_CODE (op))
     {
@@ -831,9 +1081,7 @@ data_segment_operand (op, mode)
    This is needed in the medium/anywhere code model on v9.  */
 
 int
-text_segment_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+text_segment_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   switch (GET_CODE (op))
     {
@@ -855,9 +1103,7 @@ text_segment_operand (op, mode)
    not symbolic.  */
 
 int
-reg_or_nonsymb_mem_operand (op, mode)
-    register rtx op;
-    enum machine_mode mode;
+reg_or_nonsymb_mem_operand (register rtx op, enum machine_mode mode)
 {
   if (register_operand (op, mode))
     return 1;
@@ -869,9 +1115,8 @@ reg_or_nonsymb_mem_operand (op, mode)
 }
 
 int
-splittable_symbolic_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+splittable_symbolic_memory_operand (rtx op,
+                                   enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != MEM)
     return 0;
@@ -881,9 +1126,8 @@ splittable_symbolic_memory_operand (op, mode)
 }
 
 int
-splittable_immediate_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+splittable_immediate_memory_operand (rtx op,
+                                    enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != MEM)
     return 0;
@@ -895,9 +1139,7 @@ splittable_immediate_memory_operand (op, mode)
 /* Return truth value of whether OP is EQ or NE.  */
 
 int
-eq_or_neq (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+eq_or_neq (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
 }
@@ -906,19 +1148,18 @@ eq_or_neq (op, mode)
    or LTU for non-floating-point.  We handle those specially.  */
 
 int
-normal_comp_operator (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+normal_comp_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (code) != '<')
+  if (!COMPARISON_P (op))
     return 0;
 
   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);
 }
 
@@ -926,15 +1167,14 @@ normal_comp_operator (op, mode)
    MATCH_OPERATOR to recognize all the branch insns.  */
 
 int
-noov_compare_op (op, mode)
-    register rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
+noov_compare_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (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.  */
@@ -946,18 +1186,17 @@ noov_compare_op (op, mode)
    MATCH_OPERATOR to recognize all the branch insns.  */
 
 int
-noov_compare64_op (op, mode)
-    register rtx op;
-    enum machine_mode mode ATTRIBUTE_UNUSED;
+noov_compare64_op (register rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
   if (! TARGET_V9)
     return 0;
 
-  if (GET_RTX_CLASS (code) != '<')
+  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);
@@ -968,24 +1207,21 @@ noov_compare64_op (op, mode)
    conditional move or branch on register contents instructions.  */
 
 int
-v9_regcmp_op (op, mode)
-     register rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+v9_regcmp_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  enum rtx_code code;
 
-  if (GET_RTX_CLASS (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 (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+extend_op (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
 }
@@ -995,9 +1231,7 @@ extend_op (op, mode)
    because these require CC_NOOVmode, which we handle explicitly.  */
 
 int
-cc_arithop (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+cc_arithop (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) == AND
       || GET_CODE (op) == IOR
@@ -1011,9 +1245,7 @@ cc_arithop (op, mode)
    complement its second operand and set the condition codes explicitly.  */
 
 int
-cc_arithopn (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+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 ...)).  */
@@ -1026,9 +1258,7 @@ cc_arithopn (op, mode)
    most 3 address instructions.  */
 
 int
-arith_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith_operand (rtx op, enum machine_mode mode)
 {
   if (register_operand (op, mode))
     return 1;
@@ -1040,9 +1270,7 @@ arith_operand (op, mode)
 /* Return true if OP is a constant 4096  */
 
 int
-arith_4096_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+arith_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != CONST_INT)
     return 0;
@@ -1053,9 +1281,7 @@ arith_4096_operand (op, mode)
 /* Return true if OP is suitable as second operand for add/sub */
 
 int
-arith_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith_add_operand (rtx op, enum machine_mode mode)
 {
   return arith_operand (op, mode) || arith_4096_operand (op, mode);
 }
@@ -1064,9 +1290,7 @@ arith_add_operand (op, mode)
    immediate field of OR and XOR instructions.  Used for 64-bit
    constant formation patterns.  */
 int
-const64_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+const64_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return ((GET_CODE (op) == CONST_INT
           && SPARC_SIMM13_P (INTVAL (op)))
@@ -1082,9 +1306,7 @@ const64_operand (op, mode)
 
 /* The same, but only for sethi instructions.  */
 int
-const64_high_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+const64_high_operand (rtx op, enum machine_mode mode)
 {
   return ((GET_CODE (op) == CONST_INT
           && (INTVAL (op) & ~(HOST_WIDE_INT)0x3ff) != 0
@@ -1101,9 +1323,7 @@ const64_high_operand (op, mode)
    the movcc instructions.  */
 
 int
-arith11_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith11_operand (rtx op, enum machine_mode mode)
 {
   return (register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT && SPARC_SIMM11_P (INTVAL (op))));
@@ -1114,9 +1334,7 @@ arith11_operand (op, mode)
    the movrcc instructions.  */
 
 int
-arith10_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith10_operand (rtx op, enum machine_mode mode)
 {
   return (register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT && SPARC_SIMM10_P (INTVAL (op))));
@@ -1125,14 +1343,12 @@ arith10_operand (op, mode)
 /* 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.
-   v9: Return true if OP is a register, or is a CONST_INT or CONST_DOUBLE that
+   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 (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith_double_operand (rtx op, enum machine_mode mode)
 {
   return (register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT && SMALL_INT (op))
@@ -1152,9 +1368,7 @@ arith_double_operand (op, mode)
 /* Return true if OP is a constant 4096 for DImode on ARCH64 */
 
 int
-arith_double_4096_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+arith_double_4096_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (TARGET_ARCH64 &&
          ((GET_CODE (op) == CONST_INT && INTVAL (op) == 4096) ||
@@ -1166,9 +1380,7 @@ arith_double_4096_operand (op, mode)
 /* Return true if OP is suitable as second operand for add/sub in DImode */
 
 int
-arith_double_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith_double_add_operand (rtx op, enum machine_mode mode)
 {
   return arith_double_operand (op, mode) || arith_double_4096_operand (op, mode);
 }
@@ -1179,9 +1391,7 @@ arith_double_add_operand (op, mode)
 /* ??? Replace with arith11_operand?  */
 
 int
-arith11_double_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith11_double_operand (rtx op, enum machine_mode mode)
 {
   return (register_operand (op, mode)
          || (GET_CODE (op) == CONST_DOUBLE
@@ -1202,9 +1412,7 @@ arith11_double_operand (op, mode)
 /* ??? Replace with arith10_operand?  */
 
 int
-arith10_double_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arith10_double_operand (rtx op, enum machine_mode mode)
 {
   return (register_operand (op, mode)
          || (GET_CODE (op) == CONST_DOUBLE
@@ -1224,17 +1432,13 @@ arith10_double_operand (op, mode)
    which have a 13 bit immediate field.  */
 
 int
-small_int (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+small_int (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
 }
 
 int
-small_int_or_double (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+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
@@ -1247,9 +1451,7 @@ small_int_or_double (op, mode)
    interprets the extended result as an unsigned number.  */
 
 int
-uns_small_int (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+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.  */
@@ -1266,18 +1468,14 @@ uns_small_int (op, mode)
 }
 
 int
-uns_arith_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+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 (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+clobbered_register (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == REG && call_used_regs[REGNO (op)]);
 }
@@ -1285,18 +1483,12 @@ clobbered_register (op, mode)
 /* Return 1 if OP is a valid operand for the source of a move insn.  */
 
 int
-input_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+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;
 
-  /* Accept CONSTANT_P_RTX, since it will be gone by CSE1 and result in 0/1.  */
-  if (GET_CODE (op) == CONSTANT_P_RTX)
-    return 1;
-
   /* 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
@@ -1365,13 +1557,37 @@ input_operand (op, mode)
   return 0;
 }
 
+/* Return 1 if OP is valid for the lhs of a compare insn.  */
+
+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 guarentees this.  */
+   the movsi expander guarantees this.  */
 void
-sparc_emit_set_const32 (op0, op1)
-     rtx op0;
-     rtx op1;
+sparc_emit_set_const32 (rtx op0, rtx op1)
 {
   enum machine_mode mode = GET_MODE (op0);
   rtx temp;
@@ -1425,21 +1641,25 @@ sparc_emit_set_const32 (op0, op1)
 }
 
 \f
-/* SPARC-v9 code-model support.  */
+/* 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
+   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 (op0, op1, temp1)
-     rtx op0;
-     rtx op1;
-     rtx temp1;
+sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
 {
-  rtx ti_temp1 = 0;
+  rtx temp1, temp2, temp3, temp4, temp5;
+  rtx ti_temp = 0;
 
-  if (temp1 && GET_MODE (temp1) == TImode)
+  if (temp && GET_MODE (temp) == TImode)
     {
-      ti_temp1 = temp1;
-      temp1 = gen_rtx_REG (DImode, REGNO (temp1));
+      ti_temp = temp;
+      temp = gen_rtx_REG (DImode, REGNO (temp));
     }
 
+  /* SPARC-V9 code-model support.  */
   switch (sparc_cmodel)
     {
     case CM_MEDLOW:
@@ -1451,8 +1671,13 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
         The executable must be in the low 4TB of the virtual address
         space.
 
-        sethi  %hi(symbol), %temp
-        or     %temp, %lo(symbol), %reg  */
+        sethi  %hi(symbol), %temp1
+        or     %temp1, %lo(symbol), %reg  */
+      if (temp)
+       temp1 = temp;  /* op0 is allowed.  */
+      else
+       temp1 = gen_reg_rtx (DImode);
+
       emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1)));
       emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1)));
       break;
@@ -1470,11 +1695,24 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
         or     %temp1, %m44(symbol), %temp2
         sllx   %temp2, 12, %temp3
         or     %temp3, %l44(symbol), %reg  */
-      emit_insn (gen_seth44 (op0, op1));
-      emit_insn (gen_setm44 (op0, op0, op1));
-      emit_insn (gen_rtx_SET (VOIDmode, temp1,
-                             gen_rtx_ASHIFT (DImode, op0, GEN_INT (12))));
-      emit_insn (gen_setl44 (op0, temp1, op1));
+      if (temp)
+       {
+         temp1 = op0;
+         temp2 = op0;
+         temp3 = temp;  /* op0 is allowed.  */
+       }
+      else
+       {
+         temp1 = gen_reg_rtx (DImode);
+         temp2 = gen_reg_rtx (DImode);
+         temp3 = gen_reg_rtx (DImode);
+       }
+
+      emit_insn (gen_seth44 (temp1, op1));
+      emit_insn (gen_setm44 (temp2, temp1, op1));
+      emit_insn (gen_rtx_SET (VOIDmode, temp3,
+                             gen_rtx_ASHIFT (DImode, temp2, GEN_INT (12))));
+      emit_insn (gen_setl44 (op0, temp3, op1));
       break;
 
     case CM_MEDANY:
@@ -1489,29 +1727,44 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
         sethi  %hh(symbol), %temp1
         sethi  %lm(symbol), %temp2
         or     %temp1, %hm(symbol), %temp3
-        or     %temp2, %lo(symbol), %temp4
-        sllx   %temp3, 32, %temp5
-        or     %temp4, %temp5, %reg  */
-
-      /* It is possible that one of the registers we got for operands[2]
-        might coincide with that of operands[0] (which is why we made
-        it TImode).  Pick the other one to use as our scratch.  */
-      if (rtx_equal_p (temp1, op0))
+        sllx   %temp3, 32, %temp4
+        or     %temp4, %temp2, %temp5
+        or     %temp5, %lo(symbol), %reg  */
+      if (temp)
        {
-         if (ti_temp1)
-           temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-         else
-           abort();
+         /* It is possible that one of the registers we got for operands[2]
+            might coincide with that of operands[0] (which is why we made
+            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();
+           }
+         temp1 = op0;
+         temp2 = temp;  /* op0 is _not_ allowed, see above.  */
+         temp3 = op0;
+         temp4 = op0;
+         temp5 = op0;
+       }
+      else
+       {
+         temp1 = gen_reg_rtx (DImode);
+         temp2 = gen_reg_rtx (DImode);
+         temp3 = gen_reg_rtx (DImode);
+         temp4 = gen_reg_rtx (DImode);
+         temp5 = gen_reg_rtx (DImode);
        }
 
-      emit_insn (gen_sethh (op0, op1));
-      emit_insn (gen_setlm (temp1, op1));
-      emit_insn (gen_sethm (op0, op0, op1));
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
-      emit_insn (gen_rtx_SET (VOIDmode, op0,
-                             gen_rtx_PLUS (DImode, op0, temp1)));
-      emit_insn (gen_setlo (op0, op0, op1));
+      emit_insn (gen_sethh (temp1, op1));
+      emit_insn (gen_setlm (temp2, op1));
+      emit_insn (gen_sethm (temp3, temp1, op1));
+      emit_insn (gen_rtx_SET (VOIDmode, temp4,
+                             gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
+      emit_insn (gen_rtx_SET (VOIDmode, temp5,
+                             gen_rtx_PLUS (DImode, temp4, temp2)));
+      emit_insn (gen_setlo (op0, temp5, op1));
       break;
 
     case CM_EMBMEDANY:
@@ -1523,42 +1776,69 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
         look different.
 
         Data segment:  sethi   %hi(symbol), %temp1
-                       or      %temp1, %lo(symbol), %temp2
-                       add     %temp2, EMBMEDANY_BASE_REG, %reg
-
-        Text segment:  sethi   %uhi(symbol), %temp1
-                       sethi   %hi(symbol), %temp2
-                       or      %temp1, %ulo(symbol), %temp3
-                       or      %temp2, %lo(symbol), %temp4
-                       sllx    %temp3, 32, %temp5
-                       or      %temp4, %temp5, %reg  */
+                       add     %temp1, EMBMEDANY_BASE_REG, %temp2
+                       or      %temp2, %lo(symbol), %reg  */
       if (data_segment_operand (op1, GET_MODE (op1)))
        {
+         if (temp)
+           {
+             temp1 = temp;  /* op0 is allowed.  */
+             temp2 = op0;
+           }
+         else
+           {
+             temp1 = gen_reg_rtx (DImode);
+             temp2 = gen_reg_rtx (DImode);
+           }
+
          emit_insn (gen_embmedany_sethi (temp1, op1));
-         emit_insn (gen_embmedany_brsum (op0, temp1));
-         emit_insn (gen_embmedany_losum (op0, op0, op1));
+         emit_insn (gen_embmedany_brsum (temp2, temp1));
+         emit_insn (gen_embmedany_losum (op0, temp2, op1));
        }
+
+      /* Text segment: sethi   %uhi(symbol), %temp1
+                       sethi   %hi(symbol), %temp2
+                       or      %temp1, %ulo(symbol), %temp3
+                       sllx    %temp3, 32, %temp4
+                       or      %temp4, %temp2, %temp5
+                       or      %temp5, %lo(symbol), %reg  */
       else
        {
-         /* It is possible that one of the registers we got for operands[2]
-            might coincide with that of operands[0] (which is why we made
-            it TImode).  Pick the other one to use as our scratch.  */
-         if (rtx_equal_p (temp1, op0))
+         if (temp)
            {
-             if (ti_temp1)
-               temp1 = gen_rtx_REG (DImode, REGNO (temp1) + 1);
-             else
-               abort();
+             /* It is possible that one of the registers we got for operands[2]
+                might coincide with that of operands[0] (which is why we made
+                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();
+               }
+             temp1 = op0;
+             temp2 = temp;  /* op0 is _not_ allowed, see above.  */
+             temp3 = op0;
+             temp4 = op0;
+             temp5 = op0;
+           }
+         else
+           {
+             temp1 = gen_reg_rtx (DImode);
+             temp2 = gen_reg_rtx (DImode);
+             temp3 = gen_reg_rtx (DImode);
+             temp4 = gen_reg_rtx (DImode);
+             temp5 = gen_reg_rtx (DImode);
            }
 
-         emit_insn (gen_embmedany_textuhi (op0, op1));
-         emit_insn (gen_embmedany_texthi  (temp1, op1));
-         emit_insn (gen_embmedany_textulo (op0, op0, op1));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_ASHIFT (DImode, op0, GEN_INT (32))));
-         emit_insn (gen_rtx_SET (VOIDmode, op0,
-                                 gen_rtx_PLUS (DImode, op0, temp1)));
-         emit_insn (gen_embmedany_textlo  (op0, op0, op1));
+         emit_insn (gen_embmedany_textuhi (temp1, op1));
+         emit_insn (gen_embmedany_texthi  (temp2, op1));
+         emit_insn (gen_embmedany_textulo (temp3, temp1, op1));
+         emit_insn (gen_rtx_SET (VOIDmode, temp4,
+                                 gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
+         emit_insn (gen_rtx_SET (VOIDmode, temp5,
+                                 gen_rtx_PLUS (DImode, temp4, temp2)));
+         emit_insn (gen_embmedany_textlo  (op0, temp5, op1));
        }
       break;
 
@@ -1570,10 +1850,10 @@ sparc_emit_set_symbolic_const64 (op0, op1, temp1)
 /* 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 PARAMS ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_SET64 PARAMS ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_OR64 PARAMS ((rtx, HOST_WIDE_INT));
-static rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT));
+static void sparc_emit_set_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)
@@ -1592,33 +1872,25 @@ static rtx gen_safe_XOR64 PARAMS ((rtx, HOST_WIDE_INT));
    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 (dest, val)
-     rtx dest;
-     HOST_WIDE_INT val;
+sparc_emit_set_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
 {
   emit_insn (gen_rtx_SET (VOIDmode, dest, GEN_HIGHINT64 (val)));
 }
 
 static rtx
-gen_safe_SET64 (dest, val)
-     rtx dest;
-     HOST_WIDE_INT val;
+gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
 {
   return gen_rtx_SET (VOIDmode, dest, GEN_INT64 (val));
 }
 
 static rtx
-gen_safe_OR64 (src, val)
-     rtx src;
-     HOST_WIDE_INT val;
+gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
 {
   return gen_rtx_IOR (DImode, src, GEN_INT64 (val));
 }
 
 static rtx
-gen_safe_XOR64 (src, val)
-     rtx src;
-     HOST_WIDE_INT val;
+gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
 {
   return gen_rtx_XOR (DImode, src, GEN_INT64 (val));
 }
@@ -1631,15 +1903,12 @@ gen_safe_XOR64 (src, val)
    Without doing this, the optimizer cannot see such
    opportunities.  */
 
-static void sparc_emit_set_const64_quick1
-       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, int));
+static void sparc_emit_set_const64_quick1 (rtx, rtx,
+                                          unsigned HOST_WIDE_INT, int);
 
 static void
-sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg)
-  rtx op0;
-  rtx temp;
-  unsigned HOST_WIDE_INT low_bits;
-  int is_neg;
+sparc_emit_set_const64_quick1 (rtx op0, rtx temp,
+                              unsigned HOST_WIDE_INT low_bits, int is_neg)
 {
   unsigned HOST_WIDE_INT high_bits;
 
@@ -1674,17 +1943,14 @@ sparc_emit_set_const64_quick1 (op0, temp, low_bits, is_neg)
     }
 }
 
-static void sparc_emit_set_const64_quick2
-       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT,
-              unsigned HOST_WIDE_INT, int));
+static void sparc_emit_set_const64_quick2 (rtx, rtx, unsigned HOST_WIDE_INT,
+                                          unsigned HOST_WIDE_INT, int);
 
 static void
-sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count)
-  rtx op0;
-  rtx temp;
-  unsigned HOST_WIDE_INT high_bits;
-  unsigned HOST_WIDE_INT low_immediate;
-  int shift_count;
+sparc_emit_set_const64_quick2 (rtx op0, rtx temp,
+                              unsigned HOST_WIDE_INT high_bits,
+                              unsigned HOST_WIDE_INT low_immediate,
+                              int shift_count)
 {
   rtx temp2 = op0;
 
@@ -1715,17 +1981,15 @@ sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_immediate, shift_count)
                            gen_safe_OR64 (op0, low_immediate)));
 }
 
-static void sparc_emit_set_const64_longway
-       PARAMS ((rtx, rtx, unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
+static void sparc_emit_set_const64_longway (rtx, rtx, unsigned HOST_WIDE_INT,
+                                           unsigned HOST_WIDE_INT);
 
 /* Full 64-bit constant decomposition.  Even though this is the
    'worst' case, we still optimize a few things away.  */
 static void
-sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits)
-     rtx op0;
-     rtx temp;
-     unsigned HOST_WIDE_INT high_bits;
-     unsigned HOST_WIDE_INT low_bits;
+sparc_emit_set_const64_longway (rtx op0, rtx temp,
+                               unsigned HOST_WIDE_INT high_bits,
+                               unsigned HOST_WIDE_INT low_bits)
 {
   rtx sub_temp;
 
@@ -1823,15 +2087,14 @@ sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits)
 }
 
 /* Analyze a 64-bit constant for certain properties.  */
-static void analyze_64bit_constant
-       PARAMS ((unsigned HOST_WIDE_INT,
-              unsigned HOST_WIDE_INT,
-              int *, int *, int *));
+static void analyze_64bit_constant (unsigned HOST_WIDE_INT,
+                                   unsigned HOST_WIDE_INT,
+                                   int *, int *, int *);
 
 static void
-analyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
-     int *hbsp, *lbsp, *abbasp;
+analyze_64bit_constant (unsigned HOST_WIDE_INT high_bits,
+                       unsigned HOST_WIDE_INT low_bits,
+                       int *hbsp, int *lbsp, int *abbasp)
 {
   int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
   int i;
@@ -1892,12 +2155,11 @@ analyze_64bit_constant (high_bits, low_bits, hbsp, lbsp, abbasp)
   *abbasp = all_bits_between_are_set;
 }
 
-static int const64_is_2insns
-       PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT));
+static int const64_is_2insns (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
 
 static int
-const64_is_2insns (high_bits, low_bits)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
+const64_is_2insns (unsigned HOST_WIDE_INT high_bits,
+                  unsigned HOST_WIDE_INT low_bits)
 {
   int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
 
@@ -1920,14 +2182,14 @@ const64_is_2insns (high_bits, low_bits)
   return 0;
 }
 
-static unsigned HOST_WIDE_INT create_simple_focus_bits
-       PARAMS ((unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT,
-              int, int));
+static unsigned HOST_WIDE_INT create_simple_focus_bits (unsigned HOST_WIDE_INT,
+                                                       unsigned HOST_WIDE_INT,
+                                                       int, int);
 
 static unsigned HOST_WIDE_INT
-create_simple_focus_bits (high_bits, low_bits, lowest_bit_set, shift)
-     unsigned HOST_WIDE_INT high_bits, low_bits;
-     int lowest_bit_set, shift;
+create_simple_focus_bits (unsigned HOST_WIDE_INT high_bits,
+                         unsigned HOST_WIDE_INT low_bits,
+                         int lowest_bit_set, int shift)
 {
   HOST_WIDE_INT hi, lo;
 
@@ -1951,14 +2213,12 @@ create_simple_focus_bits (high_bits, low_bits, lowest_bit_set, shift)
    insn sequence possible.  Detection of all the 1-insn cases
    has been done already.  */
 void
-sparc_emit_set_const64 (op0, op1)
-     rtx op0;
-     rtx op1;
+sparc_emit_set_const64 (rtx op0, rtx op1)
 {
   unsigned HOST_WIDE_INT high_bits, low_bits;
   int lowest_bit_set, highest_bit_set;
   int all_bits_between_are_set;
-  rtx temp;
+  rtx temp = 0;
 
   /* Sanity check that we know what we are working with.  */
   if (! TARGET_ARCH64)
@@ -1974,8 +2234,6 @@ sparc_emit_set_const64 (op0, op1)
 
   if (reload_in_progress || reload_completed)
     temp = op0;
-  else
-    temp = gen_reg_rtx (DImode);
 
   if (GET_CODE (op1) != CONST_DOUBLE
       && GET_CODE (op1) != CONST_INT)
@@ -1984,6 +2242,9 @@ sparc_emit_set_const64 (op0, op1)
       return;
     }
 
+  if (! temp)
+    temp = gen_reg_rtx (DImode);
+
   if (GET_CODE (op1) == CONST_DOUBLE)
     {
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -2231,10 +2492,7 @@ sparc_emit_set_const64 (op0, op1)
    processing is needed.  */
 
 enum machine_mode
-select_cc_mode (op, x, y)
-     enum rtx_code op;
-     rtx x;
-     rtx y ATTRIBUTE_UNUSED;
+select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
 {
   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
     {
@@ -2283,9 +2541,7 @@ select_cc_mode (op, x, y)
    return the rtx for the cc reg in the proper mode.  */
 
 rtx
-gen_compare_reg (code, x, y)
-     enum rtx_code code;
-     rtx x, y;
+gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 {
   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
   rtx cc_reg;
@@ -2366,9 +2622,7 @@ gen_compare_reg (code, x, y)
    sparc_compare_op1.  */
 
 int
-gen_v9_scc (compare_code, operands)
-     enum rtx_code compare_code;
-     register rtx *operands;
+gen_v9_scc (enum rtx_code compare_code, register rtx *operands)
 {
   rtx temp, op0, op1;
 
@@ -2456,9 +2710,7 @@ gen_v9_scc (compare_code, operands)
    This function exists to take advantage of the v9 brxx insns.  */
 
 void
-emit_v9_brxx_insn (code, op0, label)
-     enum rtx_code code;
-     rtx op0, label;
+emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
 {
   emit_jump_insn (gen_rtx_SET (VOIDmode,
                           pc_rtx,
@@ -2474,9 +2726,7 @@ emit_v9_brxx_insn (code, op0, label)
    low 64bit of the register and 0 otherwise.
  */
 rtx
-gen_df_reg (reg, low)
-     rtx reg;
-     int low;
+gen_df_reg (rtx reg, int low)
 {
   int regno = REGNO (reg);
 
@@ -2490,10 +2740,7 @@ gen_df_reg (reg, low)
    assumed that no more than 3 operands are required.  */
 
 static void
-emit_soft_tfmode_libcall (func_name, nargs, operands)
-     const char *func_name;
-     int nargs;
-     rtx *operands;
+emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
 {
   rtx ret_slot = NULL, arg[3], func_sym;
   int i;
@@ -2578,9 +2825,7 @@ emit_soft_tfmode_libcall (func_name, nargs, operands)
 /* Expand soft-float TFmode calls to sparc abi routines.  */
 
 static void
-emit_soft_tfmode_binop (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_soft_tfmode_binop (enum rtx_code code, rtx *operands)
 {
   const char *func;
 
@@ -2606,9 +2851,7 @@ emit_soft_tfmode_binop (code, operands)
 }
 
 static void
-emit_soft_tfmode_unop (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_soft_tfmode_unop (enum rtx_code code, rtx *operands)
 {
   const char *func;
 
@@ -2625,9 +2868,7 @@ emit_soft_tfmode_unop (code, operands)
 }
 
 static void
-emit_soft_tfmode_cvt (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
 {
   const char *func;
 
@@ -2728,13 +2969,11 @@ emit_soft_tfmode_cvt (code, operands)
    registers.  */
 
 static void
-emit_hard_tfmode_operation (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_hard_tfmode_operation (enum rtx_code code, rtx *operands)
 {
   rtx op, dest;
 
-  if (GET_RTX_CLASS (code) == '1')
+  if (GET_RTX_CLASS (code) == RTX_UNARY)
     {
       operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
       op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]);
@@ -2759,9 +2998,7 @@ emit_hard_tfmode_operation (code, operands)
 }
 
 void
-emit_tfmode_binop (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_tfmode_binop (enum rtx_code code, rtx *operands)
 {
   if (TARGET_HARD_QUAD)
     emit_hard_tfmode_operation (code, operands);
@@ -2770,9 +3007,7 @@ emit_tfmode_binop (code, operands)
 }
 
 void
-emit_tfmode_unop (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_tfmode_unop (enum rtx_code code, rtx *operands)
 {
   if (TARGET_HARD_QUAD)
     emit_hard_tfmode_operation (code, operands);
@@ -2781,9 +3016,7 @@ emit_tfmode_unop (code, operands)
 }
 
 void
-emit_tfmode_cvt (code, operands)
-     enum rtx_code code;
-     rtx *operands;
+emit_tfmode_cvt (enum rtx_code code, rtx *operands)
 {
   if (TARGET_HARD_QUAD)
     emit_hard_tfmode_operation (code, operands);
@@ -2791,20 +3024,11 @@ emit_tfmode_cvt (code, operands)
     emit_soft_tfmode_cvt (code, operands);
 }
 \f
-/* Return nonzero if a return peephole merging return with
-   setting of output register is ok.  */
-int
-leaf_return_peephole_ok ()
-{
-  return (actual_fsize == 0);
-}
-
 /* Return nonzero if a branch/jump/call instruction will be emitting
    nop into its delay slot.  */
 
 int
-empty_delay_slot (insn)
-     rtx insn;
+empty_delay_slot (rtx insn)
 {
   rtx seq;
 
@@ -2819,71 +3043,48 @@ empty_delay_slot (insn)
   return 1;
 }
 
-/* Return nonzero if TRIAL can go into the function epilogue's
-   delay slot.  SLOT is the slot we are trying to fill.  */
+/* Return nonzero if TRIAL can go into the call delay slot.  */
 
 int
-eligible_for_epilogue_delay (trial, slot)
-     rtx trial;
-     int slot;
+tls_call_delay (rtx trial)
 {
-  rtx pat, src;
-
-  if (slot >= 1)
-    return 0;
-
-  if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
-    return 0;
-
-  if (get_attr_length (trial) != 1)
-    return 0;
-
-  /* If there are any call-saved registers, we should scan TRIAL if it
-     does not reference them.  For now just make it easy.  */
-  if (num_gfregs)
-    return 0;
-
-  /* If the function uses __builtin_eh_return, the eh_return machinery
-     occupies the delay slot.  */
-  if (current_function_calls_eh_return)
-    return 0;
+  rtx pat, unspec;
 
-  /* In the case of a true leaf function, anything can go into the delay slot.
-     A delay slot only exists however if the frame size is zero, otherwise
-     we will put an insn to adjust the stack after the return.  */
-  if (current_function_uses_only_leaf_regs)
-    {
-      if (leaf_return_peephole_ok ())
-       return ((get_attr_in_uncond_branch_delay (trial)
-                == IN_BRANCH_DELAY_TRUE));
-      return 0;
-    }
+  /* Binutils allows
+     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;
 
-  /* Otherwise, only operations which can be done in tandem with
-     a `restore' or `return' insn can go into the delay slot.  */
-  if (GET_CODE (SET_DEST (pat)) != REG
-      || REGNO (SET_DEST (pat)) < 24)
-    return 0;
+  unspec = XEXP (SET_DEST (pat), 1);
+  if (GET_CODE (unspec) != UNSPEC
+      || (XINT (unspec, 1) != UNSPEC_TLSGD
+         && XINT (unspec, 1) != UNSPEC_TLSLDM))
+    return 1;
 
-  /* If this instruction sets up floating point register and we have a return
-     instruction, it can probably go in.  But restore will not work
-     with FP_REGS.  */
-  if (REGNO (SET_DEST (pat)) >= 32)
-    {
-      if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
-         && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
-       return 1;
-      return 0;
-    }
+  return 0;
+}
+
+/* Return nonzero if TRIAL, an insn, can be combined with a 'restore'
+   instruction.  RETURN_P is true if the v9 variant 'return' is to be
+   considered in the test too.
 
-  /* The set of insns matched here must agree precisely with the set of
-     patterns paired with a RETURN in sparc.md.  */
+   TRIAL must be a SET whose destination is a REG appropriate for the
+   'restore' instruction or, if RETURN_P is true, for the 'return'
+   instruction.  */
 
-  src = SET_SRC (pat);
+static int
+eligible_for_restore_insn (rtx trial, bool return_p)
+{
+  rtx pat = PATTERN (trial);
+  rtx src = SET_SRC (pat);
 
-  /* This matches "*return_[qhs]i" or even "*return_di" on TARGET_ARCH64.  */
+  /* The 'restore src,%g0,dest' pattern for word mode and below.  */
   if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
       && arith_operand (src, GET_MODE (src)))
     {
@@ -2893,41 +3094,39 @@ eligible_for_epilogue_delay (trial, slot)
         return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
     }
 
-  /* This matches "*return_di".  */
+  /* The 'restore src,%g0,dest' pattern for double-word mode.  */
   else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
           && arith_double_operand (src, GET_MODE (src)))
     return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
 
-  /* This matches "*return_sf_no_fpu".  */
-  else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
-          && register_operand (src, SFmode))
+  /* The 'restore src,%g0,dest' pattern for float if no FPU.  */
+  else if (! TARGET_FPU && register_operand (src, SFmode))
+    return 1;
+
+  /* The 'restore src,%g0,dest' pattern for double if no FPU.  */
+  else if (! TARGET_FPU && TARGET_ARCH64 && register_operand (src, DFmode))
     return 1;
 
-  /* If we have return instruction, anything that does not use
+  /* If we have the 'return' instruction, anything that does not use
      local or output registers and can go into a delay slot wins.  */
-  else if (TARGET_V9 && ! epilogue_renumber (&pat, 1)
-          && (get_attr_in_uncond_branch_delay (trial) == IN_BRANCH_DELAY_TRUE))
+  else if (return_p && TARGET_V9 && ! epilogue_renumber (&pat, 1)
+          && (get_attr_in_uncond_branch_delay (trial)
+              == IN_UNCOND_BRANCH_DELAY_TRUE))
     return 1;
 
-  /* This matches "*return_addsi".  */
+  /* The 'restore src1,src2,dest' pattern for SImode.  */
   else if (GET_CODE (src) == PLUS
-          && arith_operand (XEXP (src, 0), SImode)
-          && arith_operand (XEXP (src, 1), SImode)
-          && (register_operand (XEXP (src, 0), SImode)
-              || register_operand (XEXP (src, 1), SImode)))
+          && register_operand (XEXP (src, 0), SImode)
+          && arith_operand (XEXP (src, 1), SImode))
     return 1;
 
-  /* This matches "*return_adddi".  */
+  /* The 'restore src1,src2,dest' pattern for DImode.  */
   else if (GET_CODE (src) == PLUS
-          && arith_double_operand (XEXP (src, 0), DImode)
-          && arith_double_operand (XEXP (src, 1), DImode)
-          && (register_operand (XEXP (src, 0), DImode)
-              || register_operand (XEXP (src, 1), DImode)))
+          && register_operand (XEXP (src, 0), DImode)
+          && arith_double_operand (XEXP (src, 1), DImode))
     return 1;
 
-  /* This can match "*return_losum_[sd]i".
-     Catch only some cases, so that return_losum* don't have
-     to be too big.  */
+  /* The 'restore src1,%lo(src2),dest' pattern.  */
   else if (GET_CODE (src) == LO_SUM
           && ! TARGET_CM_MEDMID
           && ((register_operand (XEXP (src, 0), SImode)
@@ -2937,7 +3136,7 @@ eligible_for_epilogue_delay (trial, slot)
                   && immediate_operand (XEXP (src, 1), DImode))))
     return 1;
 
-  /* sll{,x} reg,1,reg2 is add reg,reg,reg2 as well.  */
+  /* The 'restore src,src,dest' pattern.  */
   else if (GET_CODE (src) == ASHIFT
           && (register_operand (XEXP (src, 0), SImode)
               || register_operand (XEXP (src, 0), DImode))
@@ -2947,14 +3146,64 @@ eligible_for_epilogue_delay (trial, slot)
   return 0;
 }
 
-/* Return nonzero if TRIAL can go into the sibling call
+/* Return nonzero if TRIAL can go into the function return's
+   delay slot.  */
+
+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)
+    return 0;
+
+  if (get_attr_length (trial) != 1)
+    return 0;
+
+  /* If there are any call-saved registers, we should scan TRIAL if it
+     does not reference them.  For now just make it easy.  */
+  if (num_gfregs)
+    return 0;
+
+  /* If the function uses __builtin_eh_return, the eh_return machinery
+     occupies the delay slot.  */
+  if (current_function_calls_eh_return)
+    return 0;
+
+  /* In the case of a true leaf function, anything can go into the slot.  */
+  if (leaf_function_p)
+    return get_attr_in_uncond_branch_delay (trial)
+          == IN_UNCOND_BRANCH_DELAY_TRUE;
+
+  pat = PATTERN (trial);
+
+  /* Otherwise, only operations which can be done in tandem with
+     a `restore' or `return' insn can go into the delay slot.  */
+  if (GET_CODE (SET_DEST (pat)) != REG
+      || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24))
+    return 0;
+
+  /* If this instruction sets up floating point register and we have a return
+     instruction, it can probably go in.  But restore will not work
+     with FP_REGS.  */
+  if (REGNO (SET_DEST (pat)) >= 32)
+    return (TARGET_V9
+           && ! epilogue_renumber (&pat, 1)
+           && (get_attr_in_uncond_branch_delay (trial)
+               == IN_UNCOND_BRANCH_DELAY_TRUE));
+
+  return eligible_for_restore_insn (trial, true);
+}
+
+/* Return nonzero if TRIAL can go into the sibling call's
    delay slot.  */
 
 int
-eligible_for_sibcall_delay (trial)
-     rtx trial;
+eligible_for_sibcall_delay (rtx trial)
 {
-  rtx pat, src;
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  rtx pat;
 
   if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
     return 0;
@@ -2964,11 +3213,11 @@ eligible_for_sibcall_delay (trial)
 
   pat = PATTERN (trial);
 
-  if (current_function_uses_only_leaf_regs)
+  if (leaf_function_p)
     {
       /* If the tail call is done using the call instruction,
         we have to restore %o7 in the delay slot.  */
-      if ((TARGET_ARCH64 && ! TARGET_CM_MEDLOW) || flag_pic)
+      if (LEAF_SIBCALL_SLOT_RESERVED_P)
        return 0;
 
       /* %g1 is used to build the function address */
@@ -2981,7 +3230,7 @@ eligible_for_sibcall_delay (trial)
   /* Otherwise, only operations which can be done in tandem with
      a `restore' insn can go into the delay slot.  */
   if (GET_CODE (SET_DEST (pat)) != REG
-      || REGNO (SET_DEST (pat)) < 24
+      || (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24)
       || REGNO (SET_DEST (pat)) >= 32)
     return 0;
 
@@ -2990,112 +3239,26 @@ eligible_for_sibcall_delay (trial)
   if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
     return 0;
 
-  src = SET_SRC (pat);
-
-  if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
-      && arith_operand (src, GET_MODE (src)))
-    {
-      if (TARGET_ARCH64)
-        return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
-      else
-        return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
-    }
-
-  else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
-          && arith_double_operand (src, GET_MODE (src)))
-    return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
+  return eligible_for_restore_insn (trial, false);
+}
 
-  else if (! TARGET_FPU && restore_operand (SET_DEST (pat), SFmode)
-          && register_operand (src, SFmode))
-    return 1;
+int
+short_branch (int uid1, int uid2)
+{
+  int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
 
-  else if (GET_CODE (src) == PLUS
-          && arith_operand (XEXP (src, 0), SImode)
-          && arith_operand (XEXP (src, 1), SImode)
-          && (register_operand (XEXP (src, 0), SImode)
-              || register_operand (XEXP (src, 1), SImode)))
+  /* Leave a few words of "slop".  */
+  if (delta >= -1023 && delta <= 1022)
     return 1;
 
-  else if (GET_CODE (src) == PLUS
-          && arith_double_operand (XEXP (src, 0), DImode)
-          && arith_double_operand (XEXP (src, 1), DImode)
-          && (register_operand (XEXP (src, 0), DImode)
-              || register_operand (XEXP (src, 1), DImode)))
-    return 1;
-
-  else if (GET_CODE (src) == LO_SUM
-          && ! TARGET_CM_MEDMID
-          && ((register_operand (XEXP (src, 0), SImode)
-               && immediate_operand (XEXP (src, 1), SImode))
-              || (TARGET_ARCH64
-                  && register_operand (XEXP (src, 0), DImode)
-                  && immediate_operand (XEXP (src, 1), DImode))))
-    return 1;
-
-  else if (GET_CODE (src) == ASHIFT
-          && (register_operand (XEXP (src, 0), SImode)
-              || register_operand (XEXP (src, 0), DImode))
-          && XEXP (src, 1) == const1_rtx)
-    return 1;
-
-  return 0;
-}
-
-static int
-check_return_regs (x)
-     rtx x;
-{
-  switch (GET_CODE (x))
-    {
-    case REG:
-      return IN_OR_GLOBAL_P (x);
-
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-    return 1;
-
-    case SET:
-    case IOR:
-    case AND:
-    case XOR:
-    case PLUS:
-    case MINUS:
-      if (check_return_regs (XEXP (x, 1)) == 0)
-  return 0;
-    case NOT:
-    case NEG:
-    case MEM:
-      return check_return_regs (XEXP (x, 0));
-      
-    default:
-      return 0;
-    }
-
-}
-
-int
-short_branch (uid1, uid2)
-     int uid1, uid2;
-{
-  int delta = INSN_ADDRESSES (uid1) - INSN_ADDRESSES (uid2);
-
-  /* Leave a few words of "slop".  */
-  if (delta >= -1023 && delta <= 1022)
-    return 1;
-
-  return 0;
-}
+  return 0;
+}
 
 /* Return nonzero if REG is not used after INSN.
    We assume REG is a reload reg, and therefore does
    not live past labels or calls or jumps.  */
 int
-reg_unused_after (reg, insn)
-     rtx reg;
-     rtx insn;
+reg_unused_after (rtx reg, rtx insn)
 {
   enum rtx_code code, prev_code = UNKNOWN;
 
@@ -3108,7 +3271,7 @@ reg_unused_after (reg, insn)
       if (GET_CODE (insn) == CODE_LABEL)
        return 1;
 
-      if (GET_RTX_CLASS (code) == 'i')
+      if (INSN_P (insn))
        {
          rtx set = single_set (insn);
          int in_src = set && reg_overlap_mentioned_p (reg, SET_SRC (set));
@@ -3124,18 +3287,56 @@ reg_unused_after (reg, insn)
   return 1;
 }
 \f
+/* Determine if it's legal to put X into the constant pool.  This
+   is not possible if X contains the address of a symbol that is
+   not constant (TLS) or not known at final link time (PIC).  */
+
+static bool
+sparc_cannot_force_const_mem (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case CONST_INT:
+    case CONST_DOUBLE:
+      /* Accept all non-symbolic constants.  */
+      return false;
+
+    case LABEL_REF:
+      /* Labels are OK iff we are non-PIC.  */
+      return flag_pic != 0;
+
+    case SYMBOL_REF:
+      /* 'Naked' TLS symbol references are never OK,
+        non-TLS symbols are OK iff we are non-PIC.  */
+      if (SYMBOL_REF_TLS_MODEL (x))
+       return true;
+      else
+       return flag_pic != 0;
+
+    case CONST:
+      return sparc_cannot_force_const_mem (XEXP (x, 0));
+    case PLUS:
+    case MINUS:
+      return sparc_cannot_force_const_mem (XEXP (x, 0))
+         || sparc_cannot_force_const_mem (XEXP (x, 1));
+    case UNSPEC:
+      return true;
+    default:
+      abort ();
+    }
+}
+\f
 /* The table we use to reference PIC data.  */
 static GTY(()) rtx global_offset_table;
 
 /* The function we use to get at it.  */
-static GTY(()) rtx get_pc_symbol;
-static char get_pc_symbol_name[256];
+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
-check_pic (i)
-     int i;
+check_pic (int i)
 {
   switch (flag_pic)
     {
@@ -3158,8 +3359,7 @@ check_pic (i)
    reloaded while generating PIC code.  */
 
 int
-pic_address_needs_scratch (x)
-     rtx x;
+pic_address_needs_scratch (rtx x)
 {
   /* An address which is a symbolic plus a non SMALL_INT needs a temp reg.  */
   if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
@@ -3171,16 +3371,399 @@ pic_address_needs_scratch (x)
   return 0;
 }
 
+/* Determine if a given RTX is a valid constant.  We already know this
+   satisfies CONSTANT_P.  */
+
+bool
+legitimate_constant_p (rtx x)
+{
+  rtx inner;
+
+  switch (GET_CODE (x))
+    {
+    case SYMBOL_REF:
+      /* TLS symbols are not constant.  */
+      if (SYMBOL_REF_TLS_MODEL (x))
+       return false;
+      break;
+
+    case CONST:
+      inner = XEXP (x, 0);
+
+      /* Offsets of TLS symbols are never valid.
+        Discourage CSE from creating them.  */
+      if (GET_CODE (inner) == PLUS
+         && tls_symbolic_operand (XEXP (inner, 0)))
+       return false;
+      break;
+
+    case CONST_DOUBLE:
+      if (GET_MODE (x) == VOIDmode)
+        return true;
+
+      /* 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)))
+       return true;
+
+      return false;
+
+    default:
+      break;
+    }
+
+  return true;
+}
+
+/* Determine if a given RTX is a valid constant address.  */
+
+bool
+constant_address_p (rtx x)
+{
+  switch (GET_CODE (x))
+    {
+    case LABEL_REF:
+    case CONST_INT:
+    case HIGH:
+      return true;
+
+    case CONST:
+      if (flag_pic && pic_address_needs_scratch (x))
+       return false;
+      return legitimate_constant_p (x);
+
+    case SYMBOL_REF:
+      return !flag_pic && legitimate_constant_p (x);
+
+    default:
+      return false;
+    }
+}
+
+/* Nonzero if the constant value X is a legitimate general operand
+   when generating PIC code.  It is given that flag_pic is on and
+   that X satisfies CONSTANT_P or is a CONST_DOUBLE.  */
+
+bool
+legitimate_pic_operand_p (rtx x)
+{
+  if (pic_address_needs_scratch (x))
+    return false;
+  if (tls_symbolic_operand (x)
+      || (GET_CODE (x) == CONST
+         && GET_CODE (XEXP (x, 0)) == PLUS
+         && tls_symbolic_operand (XEXP (XEXP (x, 0), 0))))
+    return false;
+  return true;
+}
+
+/* Return nonzero if ADDR is a valid memory address.
+   STRICT specifies whether strict register checking applies.  */
+   
+int
+legitimate_address_p (enum machine_mode mode, rtx addr, int strict)
+{
+  rtx rs1 = NULL, rs2 = NULL, imm1 = NULL, imm2;
+
+  if (REG_P (addr) || GET_CODE (addr) == SUBREG)
+    rs1 = addr;
+  else if (GET_CODE (addr) == PLUS)
+    {
+      rs1 = XEXP (addr, 0);
+      rs2 = XEXP (addr, 1);
+
+      /* Canonicalize.  REG comes first, if there are no regs,
+        LO_SUM comes first.  */
+      if (!REG_P (rs1)
+         && GET_CODE (rs1) != SUBREG
+         && (REG_P (rs2)
+             || GET_CODE (rs2) == SUBREG
+             || (GET_CODE (rs2) == LO_SUM && GET_CODE (rs1) != LO_SUM)))
+       {
+         rs1 = XEXP (addr, 1);
+         rs2 = XEXP (addr, 0);
+       }
+
+      if ((flag_pic == 1
+          && rs1 == pic_offset_table_rtx
+          && !REG_P (rs2)
+          && GET_CODE (rs2) != SUBREG
+          && GET_CODE (rs2) != LO_SUM
+          && GET_CODE (rs2) != MEM
+          && !tls_symbolic_operand (rs2)
+          && (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
+          && (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
+         || ((REG_P (rs1)
+              || GET_CODE (rs1) == SUBREG)
+             && RTX_OK_FOR_OFFSET_P (rs2)))
+       {
+         imm1 = rs2;
+         rs2 = NULL;
+       }
+      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
+            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.  */
+         if (mode == TFmode
+             && !(TARGET_FPU && TARGET_ARCH64 && TARGET_V9
+                  && TARGET_HARD_QUAD))
+           return 0;
+
+         /* We prohibit REG + REG on ARCH32 if not optimizing for
+            DFmode/DImode because then mem_min_alignment is likely to be zero
+            after reload and the  forced split would lack a matching splitter
+            pattern.  */
+         if (TARGET_ARCH32 && !optimize
+             && (mode == DFmode || mode == DImode))
+           return 0;
+       }
+      else if (USE_AS_OFFSETABLE_LO10
+              && GET_CODE (rs1) == LO_SUM
+              && TARGET_ARCH64
+              && ! 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))
+           return 0;
+       }
+    }
+  else if (GET_CODE (addr) == LO_SUM)
+    {
+      rs1 = XEXP (addr, 0);
+      imm1 = XEXP (addr, 1);
+
+      if (! CONSTANT_P (imm1) || tls_symbolic_operand (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)
+       return 0;
+    }
+  else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
+    return 1;
+  else
+    return 0;
+
+  if (GET_CODE (rs1) == SUBREG)
+    rs1 = SUBREG_REG (rs1);
+  if (!REG_P (rs1))
+    return 0;
+
+  if (rs2)
+    {
+      if (GET_CODE (rs2) == SUBREG)
+       rs2 = SUBREG_REG (rs2);
+      if (!REG_P (rs2))
+       return 0;
+    }
+
+  if (strict)
+    {
+      if (!REGNO_OK_FOR_BASE_P (REGNO (rs1))
+         || (rs2 && !REGNO_OK_FOR_BASE_P (REGNO (rs2))))
+       return 0;
+    }
+  else
+    {
+      if ((REGNO (rs1) >= 32
+          && REGNO (rs1) != FRAME_POINTER_REGNUM
+          && REGNO (rs1) < FIRST_PSEUDO_REGISTER)
+         || (rs2
+             && (REGNO (rs2) >= 32
+                 && REGNO (rs2) != FRAME_POINTER_REGNUM
+                 && REGNO (rs2) < FIRST_PSEUDO_REGISTER)))
+       return 0;
+    }
+  return 1;
+}
+
+/* Construct the SYMBOL_REF for the tls_get_offset function.  */
+
+static GTY(()) rtx sparc_tls_symbol;
+static rtx
+sparc_tls_get_addr (void)
+{
+  if (!sparc_tls_symbol)
+    sparc_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+
+  return sparc_tls_symbol;
+}
+
+static rtx
+sparc_tls_got (void)
+{
+  rtx temp;
+  if (flag_pic)
+    {
+      current_function_uses_pic_offset_table = 1;
+      return pic_offset_table_rtx;
+    }
+
+  if (!global_offset_table)
+    global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
+  temp = gen_reg_rtx (Pmode);
+  emit_move_insn (temp, global_offset_table);
+  return temp;
+}
+
+
+/* ADDR contains a thread-local SYMBOL_REF.  Generate code to compute
+   this (thread-local) address.  */
+
+rtx
+legitimize_tls_address (rtx addr)
+{
+  rtx temp1, temp2, temp3, ret, o0, got, insn;
+
+  if (no_new_pseudos)
+    abort ();
+
+  if (GET_CODE (addr) == SYMBOL_REF)
+    switch (SYMBOL_REF_TLS_MODEL (addr))
+      {
+      case TLS_MODEL_GLOBAL_DYNAMIC:
+       start_sequence ();
+       temp1 = gen_reg_rtx (SImode);
+       temp2 = gen_reg_rtx (SImode);
+       ret = gen_reg_rtx (Pmode);
+       o0 = gen_rtx_REG (Pmode, 8);
+       got = sparc_tls_got ();
+       emit_insn (gen_tgd_hi22 (temp1, addr));
+       emit_insn (gen_tgd_lo10 (temp2, temp1, addr));
+       if (TARGET_ARCH32)
+         {
+           emit_insn (gen_tgd_add32 (o0, got, temp2, addr));
+           insn = emit_call_insn (gen_tgd_call32 (o0, sparc_tls_get_addr (),
+                                                  addr, const1_rtx));
+         }
+       else
+         {
+           emit_insn (gen_tgd_add64 (o0, got, temp2, addr));
+           insn = emit_call_insn (gen_tgd_call64 (o0, sparc_tls_get_addr (),
+                                                  addr, const1_rtx));
+         }
+        CALL_INSN_FUNCTION_USAGE (insn)
+         = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0),
+                              CALL_INSN_FUNCTION_USAGE (insn));
+       insn = get_insns ();
+       end_sequence ();
+       emit_libcall_block (insn, ret, o0, addr);
+       break;
+
+      case TLS_MODEL_LOCAL_DYNAMIC:
+       start_sequence ();
+       temp1 = gen_reg_rtx (SImode);
+       temp2 = gen_reg_rtx (SImode);
+       temp3 = gen_reg_rtx (Pmode);
+       ret = gen_reg_rtx (Pmode);
+       o0 = gen_rtx_REG (Pmode, 8);
+       got = sparc_tls_got ();
+       emit_insn (gen_tldm_hi22 (temp1));
+       emit_insn (gen_tldm_lo10 (temp2, temp1));
+       if (TARGET_ARCH32)
+         {
+           emit_insn (gen_tldm_add32 (o0, got, temp2));
+           insn = emit_call_insn (gen_tldm_call32 (o0, sparc_tls_get_addr (),
+                                                   const1_rtx));
+         }
+       else
+         {
+           emit_insn (gen_tldm_add64 (o0, got, temp2));
+           insn = emit_call_insn (gen_tldm_call64 (o0, sparc_tls_get_addr (),
+                                                   const1_rtx));
+         }
+        CALL_INSN_FUNCTION_USAGE (insn)
+         = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_USE (VOIDmode, o0),
+                              CALL_INSN_FUNCTION_USAGE (insn));
+       insn = get_insns ();
+       end_sequence ();
+       emit_libcall_block (insn, temp3, o0,
+                           gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+                                           UNSPEC_TLSLD_BASE));
+       temp1 = gen_reg_rtx (SImode);
+       temp2 = gen_reg_rtx (SImode);
+       emit_insn (gen_tldo_hix22 (temp1, addr));
+       emit_insn (gen_tldo_lox10 (temp2, temp1, addr));
+       if (TARGET_ARCH32)
+         emit_insn (gen_tldo_add32 (ret, temp3, temp2, addr));
+       else
+         emit_insn (gen_tldo_add64 (ret, temp3, temp2, addr));
+       break;
+
+      case TLS_MODEL_INITIAL_EXEC:
+       temp1 = gen_reg_rtx (SImode);
+       temp2 = gen_reg_rtx (SImode);
+       temp3 = gen_reg_rtx (Pmode);
+       got = sparc_tls_got ();
+       emit_insn (gen_tie_hi22 (temp1, addr));
+       emit_insn (gen_tie_lo10 (temp2, temp1, addr));
+       if (TARGET_ARCH32)
+         emit_insn (gen_tie_ld32 (temp3, got, temp2, addr));
+       else
+         emit_insn (gen_tie_ld64 (temp3, got, temp2, addr));
+        if (TARGET_SUN_TLS)
+         {
+           ret = gen_reg_rtx (Pmode);
+           if (TARGET_ARCH32)
+             emit_insn (gen_tie_add32 (ret, gen_rtx_REG (Pmode, 7),
+                                       temp3, addr));
+           else
+             emit_insn (gen_tie_add64 (ret, gen_rtx_REG (Pmode, 7),
+                                       temp3, addr));
+         }
+       else
+         ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp3);
+       break;
+
+      case TLS_MODEL_LOCAL_EXEC:
+       temp1 = gen_reg_rtx (Pmode);
+       temp2 = gen_reg_rtx (Pmode);
+       if (TARGET_ARCH32)
+         {
+           emit_insn (gen_tle_hix22_sp32 (temp1, addr));
+           emit_insn (gen_tle_lox10_sp32 (temp2, temp1, addr));
+         }
+       else
+         {
+           emit_insn (gen_tle_hix22_sp64 (temp1, addr));
+           emit_insn (gen_tle_lox10_sp64 (temp2, temp1, addr));
+         }
+       ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp2);
+       break;
+
+      default:
+       abort ();
+      }
+
+  else
+    abort ();  /* for now ... */
+
+  return ret;
+}
+
+
 /* Legitimize PIC addresses.  If the address is already position-independent,
    we return ORIG.  Newly generated position-independent addresses go into a
    reg.  This is REG if nonzero, otherwise we allocate register(s) as
    necessary.  */
 
 rtx
-legitimize_pic_address (orig, mode, reg)
-     rtx orig;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     rtx reg;
+legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
+                       rtx reg)
 {
   if (GET_CODE (orig) == SYMBOL_REF)
     {
@@ -3222,11 +3805,10 @@ legitimize_pic_address (orig, mode, reg)
       else
        address = orig;
 
-      pic_ref = gen_rtx_MEM (Pmode,
-                            gen_rtx_PLUS (Pmode,
-                                          pic_offset_table_rtx, address));
+      pic_ref = gen_const_mem (Pmode,
+                              gen_rtx_PLUS (Pmode,
+                                            pic_offset_table_rtx, address));
       current_function_uses_pic_offset_table = 1;
-      RTX_UNCHANGING_P (pic_ref) = 1;
       insn = emit_move_insn (reg, pic_ref);
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
@@ -3280,41 +3862,88 @@ legitimize_pic_address (orig, mode, reg)
   return orig;
 }
 
-/* Emit special PIC prologues.  */
+/* Try machine-dependent ways of modifying an illegitimate address X
+   to be legitimate.  If we find one, return the new, valid address.
 
-void
-load_pic_register ()
+   OLDX is the address as it was before break_out_memory_refs was called.
+   In some cases it is useful to look at this to decide what needs to be done.
+
+   MODE is the mode of the operand pointed to by X.  */
+
+rtx
+legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, enum machine_mode mode)
+{
+  rtx orig_x = x;
+
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT)
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
+                     force_operand (XEXP (x, 0), NULL_RTX));
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == MULT)
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+                     force_operand (XEXP (x, 1), NULL_RTX));
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS)
+    x = gen_rtx_PLUS (Pmode, force_operand (XEXP (x, 0), NULL_RTX),
+                     XEXP (x, 1));
+  if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == PLUS)
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+                     force_operand (XEXP (x, 1), NULL_RTX));
+
+  if (x != orig_x && legitimate_address_p (mode, x, FALSE))
+    return x;
+
+  if (tls_symbolic_operand (x))
+    x = legitimize_tls_address (x);
+  else if (flag_pic)
+    x = legitimize_pic_address (x, mode, 0);
+  else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
+                     copy_to_mode_reg (Pmode, XEXP (x, 1)));
+  else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 0)))
+    x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
+                     copy_to_mode_reg (Pmode, XEXP (x, 0)));
+  else if (GET_CODE (x) == SYMBOL_REF
+          || GET_CODE (x) == CONST
+           || GET_CODE (x) == LABEL_REF)
+    x = copy_to_suggested_reg (x, NULL_RTX, Pmode);
+  return x;
+}
+
+/* Emit the special PIC prologue.  */
+
+static void
+load_pic_register (void)
 {
-  /* Labels to get the PC in the prologue of this function.  */
   int orig_flag_pic = flag_pic;
 
-  if (! flag_pic)
-    abort ();
-
-  /* If we haven't emitted the special get_pc helper function, do so now.  */
-  if (get_pc_symbol_name[0] == 0)
+  /* If we haven't emitted the special helper function, do so now.  */
+  if (add_pc_to_pic_symbol_name[0] == 0)
     {
+      const char *pic_name = reg_names[REGNO (pic_offset_table_rtx)];
       int align;
 
-      ASM_GENERATE_INTERNAL_LABEL (get_pc_symbol_name, "LGETPC", 0);
+      ASM_GENERATE_INTERNAL_LABEL (add_pc_to_pic_symbol_name, "LADDPC", 0);
       text_section ();
 
       align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
       if (align > 0)
        ASM_OUTPUT_ALIGN (asm_out_file, align);
-      (*targetm.asm_out.internal_label) (asm_out_file, "LGETPC", 0);
-      fputs ("\tretl\n\tadd\t%o7, %l7, %l7\n", asm_out_file);
+      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);
     }
 
   /* 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_");
-  get_pc_symbol = gen_rtx_SYMBOL_REF (Pmode, get_pc_symbol_name);
-  flag_pic = 0;
-
-  emit_insn (gen_get_pc (pic_offset_table_rtx, global_offset_table,
-                        get_pc_symbol));
+  add_pc_to_pic_symbol = gen_rtx_SYMBOL_REF (Pmode, add_pc_to_pic_symbol_name);
 
+  flag_pic = 0;
+  emit_insn (gen_load_pcrel_sym (pic_offset_table_rtx, global_offset_table,
+                                add_pc_to_pic_symbol));
   flag_pic = orig_flag_pic;
 
   /* Need to emit this whether or not we obey regdecls,
@@ -3328,9 +3957,7 @@ load_pic_register ()
    least a DESIRED byte boundary.  */
 
 int
-mem_min_alignment (mem, desired)
-     rtx mem;
-     int desired;
+mem_min_alignment (rtx mem, int desired)
 {
   rtx addr, base, offset;
 
@@ -3523,7 +4150,7 @@ int sparc_mode_class [NUM_MACHINE_MODES];
 enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
 
 static void
-sparc_init_modes ()
+sparc_init_modes (void)
 {
   int i;
 
@@ -3559,16 +4186,13 @@ sparc_init_modes ()
            sparc_mode_class[i] = 0;
          break;
        case MODE_CC:
-       default:
-         /* mode_class hasn't been initialized yet for EXTRA_CC_MODES, so
-            we must explicitly check for them here.  */
          if (i == (int) CCFPmode || i == (int) CCFPEmode)
            sparc_mode_class[i] = 1 << (int) CCFP_MODE;
-         else if (i == (int) CCmode || i == (int) CC_NOOVmode
-                  || i == (int) CCXmode || i == (int) CCX_NOOVmode)
-           sparc_mode_class[i] = 1 << (int) CC_MODE;
          else
-           sparc_mode_class[i] = 0;
+           sparc_mode_class[i] = 1 << (int) CC_MODE;
+         break;
+       default:
+         sparc_mode_class[i] = 0;
          break;
        }
     }
@@ -3596,145 +4220,22 @@ sparc_init_modes ()
     }
 }
 \f
-/* Save non call used registers from LOW to HIGH at BASE+OFFSET.
-   N_REGS is the number of 4-byte regs saved thus far.  This applies even to
-   v9 int regs as it simplifies the code.  */
+/* Compute the frame size required by the function.  This function is called
+   during the reload pass and also by sparc_expand_prologue.  */
 
-static int
-save_regs (file, low, high, base, offset, n_regs, real_offset)
-     FILE *file;
-     int low, high;
-     const char *base;
-     int offset;
-     int n_regs;
-     int real_offset;
+HOST_WIDE_INT
+sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function_p)
 {
+  int outgoing_args_size = (current_function_outgoing_args_size
+                           + REG_PARM_STACK_SPACE (current_function_decl));
+  int n_regs = 0;  /* N_REGS is the number of 4-byte regs saved thus far.  */
   int i;
 
-  if (TARGET_ARCH64 && high <= 32)
+  if (TARGET_ARCH64)
     {
-      for (i = low; i < high; i++)
-       {
-         if (regs_ever_live[i] && ! call_used_regs[i])
-           {
-             fprintf (file, "\tstx\t%s, [%s+%d]\n",
-                      reg_names[i], base, offset + 4 * n_regs);
-             if (dwarf2out_do_frame ())
-               dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
-             n_regs += 2;
-           }
-       }
-    }
-  else
-    {
-      for (i = low; i < high; i += 2)
-       {
-         if (regs_ever_live[i] && ! call_used_regs[i])
-           {
-             if (regs_ever_live[i+1] && ! call_used_regs[i+1])
-               {
-                 fprintf (file, "\tstd\t%s, [%s+%d]\n",
-                          reg_names[i], base, offset + 4 * n_regs);
-                 if (dwarf2out_do_frame ())
-                   {
-                     char *l = dwarf2out_cfi_label ();
-                     dwarf2out_reg_save (l, i, real_offset + 4 * n_regs);
-                     dwarf2out_reg_save (l, i+1, real_offset + 4 * n_regs + 4);
-                   }
-                 n_regs += 2;
-               }
-             else
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n",
-                          reg_names[i], base, offset + 4 * n_regs);
-                 if (dwarf2out_do_frame ())
-                   dwarf2out_reg_save ("", i, real_offset + 4 * n_regs);
-                 n_regs += 2;
-               }
-           }
-         else
-           {
-             if (regs_ever_live[i+1] && ! call_used_regs[i+1])
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n",
-                          reg_names[i+1], base, offset + 4 * n_regs + 4);
-                 if (dwarf2out_do_frame ())
-                   dwarf2out_reg_save ("", i + 1, real_offset + 4 * n_regs + 4);
-                 n_regs += 2;
-               }
-           }
-       }
-    }
-  return n_regs;
-}
-
-/* Restore non call used registers from LOW to HIGH at BASE+OFFSET.
-
-   N_REGS is the number of 4-byte regs saved thus far.  This applies even to
-   v9 int regs as it simplifies the code.  */
-
-static int
-restore_regs (file, low, high, base, offset, n_regs)
-     FILE *file;
-     int low, high;
-     const char *base;
-     int offset;
-     int n_regs;
-{
-  int i;
-
-  if (TARGET_ARCH64 && high <= 32)
-    {
-      for (i = low; i < high; i++)
-       {
-         if (regs_ever_live[i] && ! call_used_regs[i])
-           fprintf (file, "\tldx\t[%s+%d], %s\n",
-             base, offset + 4 * n_regs, reg_names[i]),
-           n_regs += 2;
-       }
-    }
-  else
-    {
-      for (i = low; i < high; i += 2)
-       {
-         if (regs_ever_live[i] && ! call_used_regs[i])
-           if (regs_ever_live[i+1] && ! call_used_regs[i+1])
-             fprintf (file, "\tldd\t[%s+%d], %s\n",
-                      base, offset + 4 * n_regs, reg_names[i]),
-             n_regs += 2;
-           else
-             fprintf (file, "\tld\t[%s+%d], %s\n",
-                      base, offset + 4 * n_regs, reg_names[i]),
-             n_regs += 2;
-         else if (regs_ever_live[i+1] && ! call_used_regs[i+1])
-           fprintf (file, "\tld\t[%s+%d], %s\n",
-                    base, offset + 4 * n_regs + 4, reg_names[i+1]),
-           n_regs += 2;
-       }
-    }
-  return n_regs;
-}
-
-/* Compute the frame size required by the function.  This function is called
-   during the reload pass and also by output_function_prologue().  */
-
-int
-compute_frame_size (size, leaf_function)
-     int size;
-     int leaf_function;
-{
-  int n_regs = 0, i;
-  int outgoing_args_size = (current_function_outgoing_args_size
-                           + REG_PARM_STACK_SPACE (current_function_decl));
-
-  /* N_REGS is the number of 4-byte regs saved thus far.  This applies
-     even to v9 int regs to be consistent with save_regs/restore_regs.  */
-
-  if (TARGET_ARCH64)
-    {
-      for (i = 0; i < 8; i++)
-       if (regs_ever_live[i] && ! call_used_regs[i])
-         n_regs += 2;
+      for (i = 0; i < 8; i++)
+       if (regs_ever_live[i] && ! call_used_regs[i])
+         n_regs += 2;
     }
   else
     {
@@ -3749,14 +4250,14 @@ compute_frame_size (size, leaf_function)
        || (regs_ever_live[i+1] && ! call_used_regs[i+1]))
       n_regs += 2;
 
-  /* Set up values for use in `function_epilogue'.  */
+  /* Set up values for use in prologue and epilogue.  */
   num_gfregs = n_regs;
 
-  if (leaf_function && n_regs == 0
-      && size == 0 && current_function_outgoing_args_size == 0)
-    {
-      actual_fsize = apparent_fsize = 0;
-    }
+  if (leaf_function_p
+      && n_regs == 0
+      && size == 0
+      && current_function_outgoing_args_size == 0)
+    actual_fsize = apparent_fsize = 0;
   else
     {
       /* We subtract STARTING_FRAME_OFFSET, remember it's negative.  */
@@ -3769,47 +4270,16 @@ compute_frame_size (size, leaf_function)
      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.  */
-  if (leaf_function == 0 || size > 0)
+  if (! leaf_function_p || size > 0)
     actual_fsize += (16 * UNITS_PER_WORD) + (TARGET_ARCH64 ? 0 : 8);
 
   return SPARC_STACK_ALIGN (actual_fsize);
 }
 
-/* Build a (32 bit) big number in a register.  */
-/* ??? We may be able to use the set macro here too.  */
-
-static void
-build_big_number (file, num, reg)
-     FILE *file;
-     int num;
-     const char *reg;
-{
-  if (num >= 0 || ! TARGET_ARCH64)
-    {
-      fprintf (file, "\tsethi\t%%hi(%d), %s\n", num, reg);
-      if ((num & 0x3ff) != 0)
-       fprintf (file, "\tor\t%s, %%lo(%d), %s\n", reg, num, reg);
-    }
-  else /* num < 0 && TARGET_ARCH64 */
-    {
-      /* Sethi does not sign extend, so we must use a little trickery
-        to use it for negative numbers.  Invert the constant before
-        loading it in, then use xor immediate to invert the loaded bits
-        (along with the upper 32 bits) to the desired constant.  This
-        works because the sethi and immediate fields overlap.  */
-      int asize = num;
-      int inv = ~asize;
-      int low = -0x400 + (asize & 0x3FF);
-         
-      fprintf (file, "\tsethi\t%%hi(%d), %s\n\txor\t%s, %d, %s\n",
-              inv, reg, reg, low, reg);
-    }
-}
-
 /* Output any necessary .register pseudo-ops.  */
+
 void
-sparc_output_scratch_registers (file)
-     FILE *file ATTRIBUTE_UNUSED;
+sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_AS_REGISTER_PSEUDO_OP
   int i;
@@ -3832,105 +4302,260 @@ sparc_output_scratch_registers (file)
 #endif
 }
 
-/* This function generates the assembly code for function entry.
-   FILE is a stdio stream to output the code to.
-   SIZE is an int: how many units of temporary storage to allocate.
-   Refer to the array `regs_ever_live' to determine which registers
-   to save; `regs_ever_live[I]' is nonzero if register number I
-   is ever used in the function.  This macro is responsible for
-   knowing which registers should not be saved even if used.  */
+/* Save/restore call-saved registers from LOW to HIGH at BASE+OFFSET
+   as needed.  LOW should be double-word aligned for 32-bit registers.
+   Return the new OFFSET.  */
+
+#define SORR_SAVE    0
+#define SORR_RESTORE 1
+
+static int
+save_or_restore_regs (int low, int high, rtx base, int offset, int action)
+{
+  rtx mem, insn;
+  int i;
+
+  if (TARGET_ARCH64 && high <= 32)
+    {
+      for (i = low; i < high; i++)
+       {
+         if (regs_ever_live[i] && ! call_used_regs[i])
+           {
+             mem = gen_rtx_MEM (DImode, plus_constant (base, offset));
+             set_mem_alias_set (mem, sparc_sr_alias_set);
+             if (action == SORR_SAVE)
+               {
+                 insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
+                 RTX_FRAME_RELATED_P (insn) = 1;
+               }
+             else  /* action == SORR_RESTORE */
+               emit_move_insn (gen_rtx_REG (DImode, i), mem);
+             offset += 8;
+           }
+       }
+    }
+  else
+    {
+      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];
+         enum machine_mode mode;
+         int regno;
+
+         if (reg0 && reg1)
+           {
+             mode = i < 32 ? DImode : DFmode;
+             regno = i;
+           }
+         else if (reg0)
+           {
+             mode = i < 32 ? SImode : SFmode;
+             regno = i;
+           }
+         else if (reg1)
+           {
+             mode = i < 32 ? SImode : SFmode;
+             regno = i + 1;
+             offset += 4;
+           }
+         else
+           continue;
+
+         mem = gen_rtx_MEM (mode, plus_constant (base, offset));
+         set_mem_alias_set (mem, sparc_sr_alias_set);
+         if (action == SORR_SAVE)
+           {
+             insn = emit_move_insn (mem, gen_rtx_REG (mode, regno));
+             RTX_FRAME_RELATED_P (insn) = 1;
+           }
+         else  /* action == SORR_RESTORE */
+           emit_move_insn (gen_rtx_REG (mode, regno), mem);
+
+         /* Always preserve double-word alignment.  */
+         offset = (offset + 7) & -8;
+       }
+    }
+
+  return offset;
+}
+
+/* Emit code to save call-saved registers.  */
+
+static void
+emit_save_regs (void)
+{
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  offset = frame_base_offset - apparent_fsize;
+
+  if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+    {
+      /* ??? This might be optimized a little as %g1 might already have a
+        value close enough that a single add insn will do.  */
+      /* ??? Although, all of this is probably only a temporary fix
+        because if %g1 can hold a function result, then
+        sparc_expand_epilogue will lose (the result will be
+        clobbered).  */
+      base = gen_rtx_REG (Pmode, 1);
+      emit_move_insn (base, GEN_INT (offset));
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             base,
+                             gen_rtx_PLUS (Pmode, frame_base_reg, base)));
+      offset = 0;
+    }
+  else
+    base = frame_base_reg;
 
-/* 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.
+  offset = save_or_restore_regs (0, 8, base, offset, SORR_SAVE);
+  save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, SORR_SAVE);
+}
 
-   If this function is a leaf procedure, then we may choose not
-   to do a "save" insn.  The decision about whether or not
-   to do this is made in regclass.c.  */
+/* Emit code to restore call-saved registers.  */
 
 static void
-sparc_output_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
+emit_restore_regs (void)
 {
-  if (TARGET_FLAT)
-    sparc_flat_function_prologue (file, size);
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  offset = frame_base_offset - apparent_fsize;
+
+  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
+    {
+      base = gen_rtx_REG (Pmode, 1);
+      emit_move_insn (base, GEN_INT (offset));
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             base,
+                             gen_rtx_PLUS (Pmode, frame_base_reg, base)));
+      offset = 0;
+    }
   else
-    sparc_nonflat_function_prologue (file, size,
-                                    current_function_uses_only_leaf_regs);
+    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);
 }
 
-/* Output code for the function prologue.  */
+/* Emit an increment for the stack pointer.  */
 
 static void
-sparc_nonflat_function_prologue (file, size, leaf_function)
-     FILE *file;
-     HOST_WIDE_INT size;
-     int leaf_function;
+emit_stack_pointer_increment (rtx increment)
 {
-  sparc_output_scratch_registers (file);
+  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));
+}
+
+/* Emit a decrement for the stack pointer.  */
+
+static void
+emit_stack_pointer_decrement (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));
+}
+
+/* Expand the function prologue.  The prologue is responsible for reserving
+   storage for the frame, saving the call-saved registers and loading the
+   PIC register if needed.  */
+
+void
+sparc_expand_prologue (void)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
 
   /* Need to use actual_fsize, since we are also allocating
      space for our callee (and our own register save area).  */
-  actual_fsize = compute_frame_size (size, leaf_function);
+  actual_fsize = sparc_compute_frame_size (get_frame_size(), leaf_function_p);
 
-  if (leaf_function)
+  if (leaf_function_p)
     {
-      frame_base_name = "%sp";
+      frame_base_reg = stack_pointer_rtx;
       frame_base_offset = actual_fsize + SPARC_STACK_BIAS;
     }
   else
     {
-      frame_base_name = "%fp";
+      frame_base_reg = hard_frame_pointer_rtx;
       frame_base_offset = SPARC_STACK_BIAS;
     }
 
-  /* This is only for the human reader.  */
-  fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
-
   if (actual_fsize == 0)
     /* do nothing.  */ ;
-  else if (! leaf_function)
+  else if (leaf_function_p)
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tsave\t%%sp, -%d, %%sp\n", actual_fsize);
+       emit_stack_pointer_increment (GEN_INT (- actual_fsize));
       else if (actual_fsize <= 8192)
        {
-         fprintf (file, "\tsave\t%%sp, -4096, %%sp\n");
-         fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096);
+         emit_stack_pointer_increment (GEN_INT (-4096));
+         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         build_big_number (file, -actual_fsize, "%g1");
-         fprintf (file, "\tsave\t%%sp, %%g1, %%sp\n");
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_stack_pointer_increment (reg);
        }
     }
-  else /* leaf function */
+  else
     {
       if (actual_fsize <= 4096)
-       fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize);
+        emit_insn (gen_save_register_window (GEN_INT (-actual_fsize)));
       else if (actual_fsize <= 8192)
        {
-         fprintf (file, "\tadd\t%%sp, -4096, %%sp\n");
-         fprintf (file, "\tadd\t%%sp, -%d, %%sp\n", actual_fsize - 4096);
+         emit_insn (gen_save_register_window (GEN_INT (-4096)));
+         emit_stack_pointer_increment (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         build_big_number (file, -actual_fsize, "%g1");
-         fprintf (file, "\tadd\t%%sp, %%g1, %%sp\n");
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_insn (gen_save_register_window (reg));
        }
     }
 
+  /* Call-saved registers are saved just above the outgoing argument area.  */
+  if (num_gfregs)
+    emit_save_regs ();
+
+  /* Load the PIC register if needed.  */
+  if (flag_pic && current_function_uses_pic_offset_table)
+    load_pic_register ();
+}
+/* This function generates the assembly code for function entry, which boils
+   down to emitting the necessary .register directives.  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?  */
+
+static void
+sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+  int 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 ? STACK_POINTER_REGNUM
-                                : HARD_FRAME_POINTER_REGNUM),
+      dwarf2out_def_cfa (label,
+                        leaf_function_p
+                        ? STACK_POINTER_REGNUM
+                        : HARD_FRAME_POINTER_REGNUM,
                         frame_base_offset);
 
-      if (! leaf_function)
+      if (! leaf_function_p)
        {
          /* Note the register window save.  This tells the unwinder that
             it needs to restore the window registers from the previous
@@ -3941,372 +4566,304 @@ sparc_nonflat_function_prologue (file, size, leaf_function)
          dwarf2out_return_reg (label, 31);
        }
     }
+}
 
-  /* If doing anything with PIC, do it now.  */
-  if (! flag_pic)
-    fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
+/* Expand the function epilogue, either normal or part of a sibcall.
+   We emit all the instructions except the return or the call.  */
+
+void
+sparc_expand_epilogue (void)
+{
+  int leaf_function_p = current_function_uses_only_leaf_regs;
 
-  /* Call saved registers are saved just above the outgoing argument area.  */
   if (num_gfregs)
-    {
-      int offset, real_offset, n_regs;
-      const char *base;
+    emit_restore_regs ();
 
-      real_offset = -apparent_fsize;
-      offset = -apparent_fsize + frame_base_offset;
-      if (offset < -4096 || offset + num_gfregs * 4 > 4096)
+  if (actual_fsize == 0)
+    /* do nothing.  */ ;
+  else if (leaf_function_p)
+    {
+      if (actual_fsize <= 4096)
+       emit_stack_pointer_decrement (GEN_INT (- actual_fsize));
+      else if (actual_fsize <= 8192)
        {
-         /* ??? This might be optimized a little as %g1 might already have a
-            value close enough that a single add insn will do.  */
-         /* ??? Although, all of this is probably only a temporary fix
-            because if %g1 can hold a function result, then
-            output_function_epilogue will lose (the result will get
-            clobbered).  */
-         build_big_number (file, offset, "%g1");
-         fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
-         base = "%g1";
-         offset = 0;
+         emit_stack_pointer_decrement (GEN_INT (-4096));
+         emit_stack_pointer_decrement (GEN_INT (4096 - actual_fsize));
        }
       else
        {
-         base = frame_base_name;
+         rtx reg = gen_rtx_REG (Pmode, 1);
+         emit_move_insn (reg, GEN_INT (-actual_fsize));
+         emit_stack_pointer_decrement (reg);
        }
-
-      n_regs = save_regs (file, 0, 8, base, offset, 0, real_offset);
-      save_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs,
-                real_offset);
     }
 }
-
-/* Output code to restore any call saved registers.  */
-
+  
+/* This function generates the assembly code for function exit.  */
+  
 static void
-output_restore_regs (file, leaf_function)
-     FILE *file;
-     int leaf_function ATTRIBUTE_UNUSED;
+sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  int offset, n_regs;
-  const char *base;
+  /* 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
+     plus 8) point to the first instruction in the next function.  */
 
-  offset = -apparent_fsize + frame_base_offset;
-  if (offset < -4096 || offset + num_gfregs * 4 > 4096 - 8 /*double*/)
-    {
-      build_big_number (file, offset, "%g1");
-      fprintf (file, "\tadd\t%s, %%g1, %%g1\n", frame_base_name);
-      base = "%g1";
-      offset = 0;
-    }
-  else
-    {
-      base = frame_base_name;
-    }
+  rtx insn, last_real_insn;
 
-  n_regs = restore_regs (file, 0, 8, base, offset, 0);
-  restore_regs (file, 32, TARGET_V9 ? 96 : 64, base, offset, n_regs);
-}
+  insn = get_last_insn ();
 
-/* This function generates the assembly code for function exit,
-   on machines that need it.
+  last_real_insn = prev_real_insn (insn);
+  if (last_real_insn
+      && GET_CODE (last_real_insn) == INSN
+      && GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
+    last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
 
-   The function epilogue should not depend on the current stack pointer!
-   It should use the frame pointer only.  This is mandatory because
-   of alloca; we also take advantage of it to omit stack adjustments
-   before returning.  */
+  if (last_real_insn && GET_CODE (last_real_insn) == CALL_INSN)
+    fputs("\tnop\n", file);
 
-static void
-sparc_output_function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
-{
-  if (TARGET_FLAT)
-    sparc_flat_function_epilogue (file, size);
-  else
-    sparc_nonflat_function_epilogue (file, size,
-                                    current_function_uses_only_leaf_regs);
+  sparc_output_deferred_case_vectors ();
 }
-
-/* Output code for the function epilogue.  */
-
+  
+/* Output a 'restore' instruction.  */
 static void
-sparc_nonflat_function_epilogue (file, size, leaf_function)
-     FILE *file;
-     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
-     int leaf_function;
+output_restore (rtx pat)
 {
-  const char *ret;
+  rtx operands[3];
 
-  if (current_function_epilogue_delay_list == 0)
+  if (! pat)
     {
-      /* If code does not drop into the epilogue, we need
-        do nothing except output pending case vectors.
+      fputs ("\t restore\n", asm_out_file);
+      return;
+    }
 
-        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 plus 8) point to
-        the first instruction in the next function.  */
-      rtx insn;
+  if (GET_CODE (pat) != SET)
+    abort ();
 
-      fputs("\tnop\n", file);
+  operands[0] = SET_DEST (pat);
+  pat = SET_SRC (pat);
 
-      insn = get_last_insn ();
-      if (GET_CODE (insn) == NOTE)
-             insn = prev_nonnote_insn (insn);
-      if (insn && GET_CODE (insn) == BARRIER)
-             goto output_vectors;
+  switch (GET_CODE (pat))
+    {
+      case PLUS:
+       operands[1] = XEXP (pat, 0);
+       operands[2] = XEXP (pat, 1);
+       output_asm_insn (" restore %r1, %2, %Y0", operands);
+       break;
+      case LO_SUM:
+       operands[1] = XEXP (pat, 0);
+       operands[2] = XEXP (pat, 1);
+       output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
+       break;
+      case ASHIFT:
+       operands[1] = XEXP (pat, 0);
+       if (XEXP (pat, 1) != const1_rtx)
+         abort();
+       output_asm_insn (" restore %r1, %r1, %Y0", operands);
+       break;
+      default:
+       operands[1] = pat;
+       output_asm_insn (" restore %%g0, %1, %Y0", operands);
+       break;
     }
+}
+  
+/* Output a return.  */
 
-  if (num_gfregs)
-    output_restore_regs (file, leaf_function);
+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)
+    {
+      /* 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.  */
 
-  /* Work out how to skip the caller's unimp instruction if required.  */
-  if (leaf_function)
-    ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%o7+12" : "retl");
-  else
-    ret = (SKIP_CALLERS_UNIMP_P ? "jmp\t%i7+12" : "ret");
+      if (current_function_calls_eh_return)
+       abort ();
 
-  if (! leaf_function)
+      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 ();
+
+         final_scan_insn (delay, asm_out_file, 1, 0, 2, NULL);
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
+       }
+      else
+       fputs ("\t nop\n", asm_out_file);
+    }
+  else
     {
+      /* This is a regular function so we have to restore the register window.
+        We may have a pending insn for the delay slot, which will be either
+        combined with the 'restore' instruction or put in the delay slot of
+        the 'return' instruction.  */
+
       if (current_function_calls_eh_return)
        {
-         if (current_function_epilogue_delay_list)
-           abort ();
-         if (SKIP_CALLERS_UNIMP_P)
+         /* 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 ();
 
-         fputs ("\trestore\n\tretl\n\tadd\t%sp, %g1, %sp\n", file);
+         if (! flag_delayed_branch)
+           fputs ("\tadd\t%fp, %g1, %fp\n", asm_out_file);
+
+         if (TARGET_V9)
+           fputs ("\treturn\t%i7+8\n", asm_out_file);
+         else
+           fputs ("\trestore\n\tjmp\t%o7+8\n", asm_out_file);
+
+         if (flag_delayed_branch)
+           fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
+         else
+           fputs ("\t nop\n", asm_out_file);
        }
-      /* If we wound up with things in our delay slot, flush them here.  */
-      else if (current_function_epilogue_delay_list)
+      else if (delay_slot_filled_p)
        {
-         rtx delay = PATTERN (XEXP (current_function_epilogue_delay_list, 0));
+         rtx delay, pat;
+
+         delay = NEXT_INSN (insn);
+         if (! delay)
+           abort ();
 
-         if (TARGET_V9 && ! epilogue_renumber (&delay, 1))
+         pat = PATTERN (delay);
+
+         if (TARGET_V9 && ! epilogue_renumber (&pat, 1))
            {
-             epilogue_renumber (&delay, 0);
-             fputs (SKIP_CALLERS_UNIMP_P
-                    ? "\treturn\t%i7+12\n"
-                    : "\treturn\t%i7+8\n", file);
-             final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                              file, 1, 0, 0);
+             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, 2, NULL);
            }
          else
            {
-             rtx insn, src;
-
-             if (GET_CODE (delay) != SET)
-               abort();
-
-             src = SET_SRC (delay);
-             if (GET_CODE (src) == ASHIFT)
-               {
-                 if (XEXP (src, 1) != const1_rtx)
-                   abort();
-                 SET_SRC (delay)
-                   = gen_rtx_PLUS (GET_MODE (src), XEXP (src, 0),
-                                   XEXP (src, 0));
-               }
-
-             insn = gen_rtx_PARALLEL (VOIDmode,
-                                      gen_rtvec (2, delay,
-                                                 gen_rtx_RETURN (VOIDmode)));
-             insn = emit_jump_insn (insn);
-
-             sparc_emitting_epilogue = true;
-             final_scan_insn (insn, file, 1, 0, 1);
-             sparc_emitting_epilogue = false;
+             fprintf (asm_out_file, "\tjmp\t%%i7+%d\n",
+                      sparc_skip_caller_unimp ? 12 : 8);
+             output_restore (pat);
            }
+
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
        }
-      else if (TARGET_V9 && ! SKIP_CALLERS_UNIMP_P)
-       fputs ("\treturn\t%i7+8\n\tnop\n", file);
       else
-       fprintf (file, "\t%s\n\trestore\n", ret);
+        {
+         /* 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);
+         else if (flag_delayed_branch)
+           fprintf (asm_out_file, "\tjmp\t%%i7+%d\n\t restore\n",
+                    sparc_skip_caller_unimp ? 12 : 8);
+         else
+           fprintf (asm_out_file, "\trestore\n\tjmp\t%%o7+%d\n\t nop\n",
+                    sparc_skip_caller_unimp ? 12 : 8);
+       }
     }
-  /* All of the following cases are for leaf functions.  */
-  else if (current_function_calls_eh_return)
-    abort ();
-  else if (current_function_epilogue_delay_list)
-    {
-      /* eligible_for_epilogue_delay_slot ensures that if this is a
-        leaf function, then we will only have insn in the delay slot
-        if the frame size is zero, thus no adjust for the stack is
-        needed here.  */
-      if (actual_fsize != 0)
-       abort ();
-      fprintf (file, "\t%s\n", ret);
-      final_scan_insn (XEXP (current_function_epilogue_delay_list, 0),
-                      file, 1, 0, 1);
-    }
-  /* Output 'nop' instead of 'sub %sp,-0,%sp' when no frame, so as to
-        avoid generating confusing assembly language output.  */
-  else if (actual_fsize == 0)
-    fprintf (file, "\t%s\n\tnop\n", ret);
-  else if (actual_fsize <= 4096)
-    fprintf (file, "\t%s\n\tsub\t%%sp, -%d, %%sp\n", ret, actual_fsize);
-  else if (actual_fsize <= 8192)
-    fprintf (file, "\tsub\t%%sp, -4096, %%sp\n\t%s\n\tsub\t%%sp, -%d, %%sp\n",
-            ret, actual_fsize - 4096);
-  else if ((actual_fsize & 0x3ff) == 0)
-    fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n",
-            actual_fsize, ret);
-  else          
-    fprintf (file, "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n\t%s\n\tadd\t%%sp, %%g1, %%sp\n",
-            actual_fsize, actual_fsize, ret);
-
- output_vectors:
-  sparc_output_deferred_case_vectors ();
+
+  return "";
 }
 
 /* Output a sibling call.  */
 
 const char *
-output_sibcall (insn, call_operand)
-     rtx insn, call_operand;
+output_sibcall (rtx insn, rtx call_operand)
 {
-  int leaf_regs = current_function_uses_only_leaf_regs;
-  rtx operands[3];
-  int delay_slot = dbr_sequence_length () > 0;
+  int leaf_function_p = current_function_uses_only_leaf_regs;
+  bool delay_slot_filled_p = dbr_sequence_length () > 0;
+  rtx operands[1];
 
-  if (num_gfregs)
+  if (! flag_delayed_branch)
+    abort();
+
+  operands[0] = call_operand;
+
+  if (leaf_function_p)
     {
-      /* Call to restore global regs might clobber
-        the delay slot. Instead of checking for this
-        output the delay slot now.  */
-      if (delay_slot)
+      /* 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();
+
+      if (delay_slot_filled_p)
        {
          rtx delay = NEXT_INSN (insn);
-
          if (! delay)
            abort ();
 
-         final_scan_insn (delay, asm_out_file, 1, 0, 1);
+         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, 2, NULL);
+
          PATTERN (delay) = gen_blockage ();
          INSN_CODE (delay) = -1;
-         delay_slot = 0;
-       }
-      output_restore_regs (asm_out_file, leaf_regs);
-    }
-
-  operands[0] = call_operand;
-
-  if (leaf_regs)
-    {
-#ifdef HAVE_AS_RELAX_OPTION
-      /* If as and ld are relaxing tail call insns into branch always,
-        use or %o7,%g0,X; call Y; or X,%g0,%o7 always, so that it can
-        be optimized.  With sethi/jmpl as nor ld has no easy way how to
-        find out if somebody does not branch between the sethi and jmpl.  */
-      int spare_slot = 0;
-#else
-      int spare_slot = ((TARGET_ARCH32 || TARGET_CM_MEDLOW) && ! flag_pic);
-#endif
-      int size = 0;
-
-      if ((actual_fsize || ! spare_slot) && delay_slot)
-       {
-         rtx delay = NEXT_INSN (insn);
-
-         if (! delay)
-           abort ();
-
-         final_scan_insn (delay, asm_out_file, 1, 0, 1);
-         PATTERN (delay) = gen_blockage ();
-         INSN_CODE (delay) = -1;
-         delay_slot = 0;
-       }
-      if (actual_fsize)
-       {
-         if (actual_fsize <= 4096)
-           size = actual_fsize;
-         else if (actual_fsize <= 8192)
-           {
-             fputs ("\tsub\t%sp, -4096, %sp\n", asm_out_file);
-             size = actual_fsize - 4096;
-           }
-         else if ((actual_fsize & 0x3ff) == 0)
-           fprintf (asm_out_file,
-                    "\tsethi\t%%hi(%d), %%g1\n\tadd\t%%sp, %%g1, %%sp\n",
-                    actual_fsize);
-         else
-           {
-             fprintf (asm_out_file,
-                      "\tsethi\t%%hi(%d), %%g1\n\tor\t%%g1, %%lo(%d), %%g1\n",
-                      actual_fsize, actual_fsize);
-             fputs ("\tadd\t%%sp, %%g1, %%sp\n", asm_out_file);
-           }
-       }
-      if (spare_slot)
-       {
-         output_asm_insn ("sethi\t%%hi(%a0), %%g1", operands);
-         output_asm_insn ("jmpl\t%%g1 + %%lo(%a0), %%g0", operands);
-         if (size)
-           fprintf (asm_out_file, "\t sub\t%%sp, -%d, %%sp\n", size);
-         else if (! delay_slot)
-           fputs ("\t nop\n", asm_out_file);
        }
       else
        {
-         if (size)
-           fprintf (asm_out_file, "\tsub\t%%sp, -%d, %%sp\n", size);
          /* 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);
        }
-      return "";
     }
-
-  output_asm_insn ("call\t%a0, 0", operands);
-  if (delay_slot)
+  else
     {
-      rtx delay = NEXT_INSN (insn), pat;
+      /* This is a regular function so we have to restore the register window.
+        We may have a pending insn for the delay slot, which will be combined
+        with the 'restore' instruction.  */
 
-      if (! delay)
-       abort ();
-
-      pat = PATTERN (delay);
-      if (GET_CODE (pat) != SET)
-       abort ();
+      output_asm_insn ("call\t%a0, 0", operands);
 
-      operands[0] = SET_DEST (pat);
-      pat = SET_SRC (pat);
-      switch (GET_CODE (pat))
+      if (delay_slot_filled_p)
        {
-       case PLUS:
-         operands[1] = XEXP (pat, 0);
-         operands[2] = XEXP (pat, 1);
-         output_asm_insn (" restore %r1, %2, %Y0", operands);
-         break;
-       case LO_SUM:
-         operands[1] = XEXP (pat, 0);
-         operands[2] = XEXP (pat, 1);
-         output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
-         break;
-       case ASHIFT:
-         operands[1] = XEXP (pat, 0);
-         output_asm_insn (" restore %r1, %r1, %Y0", operands);
-         break;
-       default:
-         operands[1] = pat;
-         output_asm_insn (" restore %%g0, %1, %Y0", operands);
-         break;
+         rtx delay = NEXT_INSN (insn);
+         if (! delay)
+           abort ();
+
+         output_restore (PATTERN (delay));
+
+         PATTERN (delay) = gen_blockage ();
+         INSN_CODE (delay) = -1;
        }
-      PATTERN (delay) = gen_blockage ();
-      INSN_CODE (delay) = -1;
+      else
+       output_restore (NULL_RTX);
     }
-  else
-    fputs ("\t restore\n", asm_out_file);
+
   return "";
 }
 \f
 /* Functions for handling argument passing.
 
-   For v8 the first six args are normally in registers and the rest are
+   For 32-bit, the first 6 args are normally in registers and the rest are
    pushed.  Any arg that starts within the first 6 words is at least
    partially passed in a register unless its data type forbids.
 
-   For v9, the argument registers are laid out as an array of 16 elements
+   For 64-bit, the argument registers are laid out as an array of 16 elements
    and arguments are added sequentially.  The first 6 int args and up to the
    first 16 fp args (depending on size) are passed in regs.
 
@@ -4331,7 +4888,7 @@ output_sibcall (insn, call_operand)
 
    Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
 
-   Integral arguments are always passed as 64 bit quantities appropriately
+   Integral arguments are always passed as 64-bit quantities appropriately
    extended.
 
    Passing of floating point values is handled as follows.
@@ -4348,7 +4905,81 @@ output_sibcall (insn, call_operand)
      appropriate integer reg and the appropriate fp reg.
      If the value is not one of the first 6 arguments the value is passed in
      the appropriate fp reg and in memory.
-   */
+
+
+   Summary of the calling conventions implemented by GCC on SPARC:
+
+   32-bit ABI:
+                                size      argument     return value
+
+      small integer              <4       int. reg.      int. reg.
+      word                        4       int. reg.      int. reg.
+      double word                 8       int. reg.      int. reg.
+
+      _Complex small integer     <8       int. reg.      int. reg.
+      _Complex word               8       int. reg.      int. reg.
+      _Complex double word       16        memory        int. reg.
+
+      vector integer            <=8       int. reg.       FP reg.
+      vector integer             >8        memory         memory
+
+      float                       4       int. reg.       FP reg.
+      double                      8       int. reg.       FP reg.
+      long double                16        memory         memory
+
+      _Complex float              8        memory         FP reg.
+      _Complex double            16        memory         FP reg.
+      _Complex long double       32        memory         FP reg.
+
+      vector float             <=32        memory         FP reg.
+      vector float              >32        memory         memory
+
+      aggregate                 any        memory         memory
+
+
+
+    64-bit ABI:
+                                size      argument     return value
+
+      small integer              <8       int. reg.      int. reg.
+      word                        8       int. reg.      int. reg.
+      double word                16       int. reg.      int. reg.
+
+      _Complex small integer    <16       int. reg.      int. reg.
+      _Complex word              16       int. reg.      int. reg.
+      _Complex double word       32        memory        int. reg.
+
+      vector integer           <=16        FP reg.        FP reg.
+      vector integer       16<s<=32        memory         FP reg.
+      vector integer            >32        memory         memory
+
+      float                       4        FP reg.        FP reg.
+      double                      8        FP reg.        FP reg.
+      long double                16        FP reg.        FP reg.
+
+      _Complex float              8        FP reg.        FP reg.
+      _Complex double            16        FP reg.        FP reg.
+      _Complex long double       32        memory         FP reg.
+
+      vector float             <=16        FP reg.        FP reg.
+      vector float         16<s<=32        memory         FP reg.
+      vector float              >32        memory         memory
+
+      aggregate                <=16         reg.           reg.
+      aggregate            16<s<=32        memory          reg.
+      aggregate                 >32        memory         memory
+
+
+
+Note #1: complex floating-point types follow the extended SPARC ABIs as
+implemented by the Sun compiler.
+
+Note #2: integral vector types follow the scalar floating-point types
+conventions to match what is implemented by the Sun VIS SDK.
+
+Note #3: floating-point vector types follow the complex floating-point
+types conventions.  */
+
 
 /* Maximum number of int regs for args.  */
 #define SPARC_INT_ARG_MAX 6
@@ -4363,19 +4994,65 @@ output_sibcall (insn, call_operand)
    For a library call, FNTYPE is 0.  */
 
 void
-init_cumulative_args (cum, fntype, libname, fndecl)
-     CUMULATIVE_ARGS *cum;
-     tree fntype;
-     rtx libname ATTRIBUTE_UNUSED;
-     tree fndecl ATTRIBUTE_UNUSED;
+init_cumulative_args (struct sparc_args *cum, tree fntype,
+                     rtx libname ATTRIBUTE_UNUSED,
+                     tree fndecl ATTRIBUTE_UNUSED)
 {
   cum->words = 0;
   cum->prototype_p = fntype && TYPE_ARG_TYPES (fntype);
   cum->libcall_p = fntype == 0;
 }
 
+/* Handle the TARGET_PROMOTE_PROTOTYPES target hook.
+   When a prototype says `char' or `short', really pass an `int'.  */
+
+static bool
+sparc_promote_prototypes (tree fntype ATTRIBUTE_UNUSED)
+{
+  return TARGET_ARCH32 ? true : false;
+}
+
+/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook.  */
+
+static bool
+sparc_strict_argument_naming (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED)
+{
+  return TARGET_ARCH64 ? true : false;
+}
+
+/* Scan the record type TYPE and return the following predicates:
+    - INTREGS_P: the record contains at least one field or sub-field
+      that is eligible for promotion in integer registers.
+    - FP_REGS_P: the record contains at least one field or sub-field
+      that is eligible for promotion in floating-point registers.
+    - PACKED_P: the record contains at least one field that is packed.
+
+   Sub-fields are not taken into account for the PACKED_P predicate.  */
+
+static void
+scan_record_type (tree type, int *intregs_p, int *fpregs_p, int *packed_p)
+{
+  tree field;
+
+  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+    {
+      if (TREE_CODE (field) == FIELD_DECL)
+       {
+         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)
+           *fpregs_p = 1;
+         else
+           *intregs_p = 1;
+
+         if (packed_p && DECL_PACKED (field))
+           *packed_p = 1;
+       }
+    }
+}
+
 /* Compute the slot number to pass an argument in.
-   Returns the slot number or -1 if passing on the stack.
+   Return the slot number or -1 if passing on the stack.
 
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
@@ -4390,14 +5067,9 @@ init_cumulative_args (cum, fntype, libname, fndecl)
    *PPADDING records the amount of padding needed in words.  */
 
 static int
-function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
-     const CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
-     int incoming_p;
-     int *pregno;
-     int *ppadding;
+function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
+                    tree type, int named, int incoming_p,
+                    int *pregno, int *ppadding)
 {
   int regbase = (incoming_p
                 ? SPARC_INCOMING_INT_ARG_FIRST
@@ -4407,109 +5079,90 @@ function_arg_slotno (cum, mode, type, named, incoming_p, pregno, ppadding)
 
   *ppadding = 0;
 
-  if (type != 0 && TREE_ADDRESSABLE (type))
+  if (type && TREE_ADDRESSABLE (type))
     return -1;
+
   if (TARGET_ARCH32
-      && type != 0 && mode == BLKmode
+      && mode == BLKmode
+      && type
       && TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
     return -1;
 
-  switch (mode)
+  /* For SPARC64, objects requiring 16-byte alignment get it.  */
+  if (TARGET_ARCH64
+      && GET_MODE_ALIGNMENT (mode) >= 2 * BITS_PER_WORD
+      && (slotno & 1) != 0)
+    slotno++, *ppadding = 1;
+
+  switch (GET_MODE_CLASS (mode))
     {
-    case VOIDmode :
-      /* MODE is VOIDmode when generating the actual call.
-        See emit_call_1.  */
-      return -1;
+    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)
+           return -1;
+         regno = SPARC_FP_ARG_FIRST + slotno * 2;
+         /* Arguments filling only one single FP register are
+            right-justified in the outer double FP register.  */
+         if (GET_MODE_SIZE (mode) <= 4)
+           regno++;
+         break;
+       }
+      /* fallthrough */
 
-    case QImode : case CQImode :
-    case HImode : case CHImode :
-    case SImode : case CSImode :
-    case DImode : case CDImode :
-    case TImode : case CTImode :
+    case MODE_INT:
+    case MODE_COMPLEX_INT:
       if (slotno >= SPARC_INT_ARG_MAX)
        return -1;
       regno = regbase + slotno;
       break;
 
-    case SFmode : case SCmode :
-    case DFmode : case DCmode :
-    case TFmode : case TCmode :
-      if (TARGET_ARCH32)
-       {
-         if (slotno >= SPARC_INT_ARG_MAX)
-           return -1;
-         regno = regbase + slotno;
-       }
-      else
-       {
-         if ((mode == TFmode || mode == TCmode)
-             && (slotno & 1) != 0)
-           slotno++, *ppadding = 1;
-         if (TARGET_FPU && named)
-           {
-             if (slotno >= SPARC_FP_ARG_MAX)
-               return -1;
-             regno = SPARC_FP_ARG_FIRST + slotno * 2;
-             if (mode == SFmode)
-               regno++;
-           }
-         else
-           {
-             if (slotno >= SPARC_INT_ARG_MAX)
-               return -1;
-             regno = regbase + slotno;
-           }
-       }
-      break;
+    case MODE_RANDOM:
+      if (mode == VOIDmode)
+       /* MODE is VOIDmode when generating the actual call.  */
+       return -1;
 
-    case BLKmode :
-      /* For sparc64, objects requiring 16 byte alignment get it.  */
-      if (TARGET_ARCH64)
-       {
-         if (type && TYPE_ALIGN (type) == 128 && (slotno & 1) != 0)
-           slotno++, *ppadding = 1;
-       }
+      if (mode != BLKmode)
+       abort ();
 
-      if (TARGET_ARCH32
-         || (type && TREE_CODE (type) == UNION_TYPE))
+      /* 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 (slotno >= SPARC_INT_ARG_MAX)
            return -1;
          regno = regbase + slotno;
        }
-      else
+      else  /* TARGET_ARCH64 && type && TREE_CODE (type) == RECORD_TYPE */
        {
-         tree field;
-         int intregs_p = 0, fpregs_p = 0;
-         /* The ABI obviously doesn't specify how packed
-            structures are passed.  These are defined to be passed
-            in int regs if possible, otherwise memory.  */
-         int packed_p = 0;
-
-         /* First see what kinds of registers we need.  */
-         for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-           {
-             if (TREE_CODE (field) == FIELD_DECL)
-               {
-                 if (TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
-                     && TARGET_FPU)
-                   fpregs_p = 1;
-                 else
-                   intregs_p = 1;
-                 if (DECL_PACKED (field))
-                   packed_p = 1;
-               }
-           }
+         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);
+
+         /* The ABI obviously doesn't specify how packed structures
+            are passed.  These are defined to be passed in int regs
+            if possible, otherwise memory.  */
          if (packed_p || !named)
            fpregs_p = 0, intregs_p = 1;
 
          /* If all arg slots are filled, then must pass on stack.  */
          if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
            return -1;
+
          /* If there are only int args and all int arg slots are filled,
             then must pass on stack.  */
          if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
            return -1;
+
          /* Note that even if all int arg slots are filled, fp members may
             still be passed in regs if such regs are available.
             *PREGNO isn't set because there may be more than one, it's up
@@ -4535,49 +5188,45 @@ struct function_arg_record_value_parms
   int named;           /* whether the argument is named.  */
   int regbase;         /* regno of the base register.  */
   int stack;           /* 1 if part of the argument is on the stack.  */
-  int intoffset;       /* offset of the pending integer field.  */
+  int intoffset;       /* offset of the first pending integer field.  */
   unsigned int nregs;  /* number of words passed in registers.  */
 };
 
 static void function_arg_record_value_3
      PARAMS ((HOST_WIDE_INT, struct function_arg_record_value_parms *));
(HOST_WIDE_INT, struct function_arg_record_value_parms *);
 static void function_arg_record_value_2
-       PARAMS ((tree, HOST_WIDE_INT,
-                struct function_arg_record_value_parms *));
+ (tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
 static void function_arg_record_value_1
-        PARAMS ((tree, HOST_WIDE_INT,
-                struct function_arg_record_value_parms *));
-static rtx function_arg_record_value
-       PARAMS ((tree, enum machine_mode, int, int, int));
+ (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);
 
 /* A subroutine of function_arg_record_value.  Traverse the structure
-   recusively and determine how many registers will be required.  */
+   recursively and determine how many registers will be required.  */
 
 static void
-function_arg_record_value_1 (type, startbitpos, parms)
-     tree type;
-     HOST_WIDE_INT startbitpos;
-     struct function_arg_record_value_parms *parms;
+function_arg_record_value_1 (tree type, HOST_WIDE_INT startbitpos,
+                            struct function_arg_record_value_parms *parms,
+                            bool packed_p)
 {
   tree field;
 
-  /* The ABI obviously doesn't specify how packed structures are
-     passed.  These are defined to be passed in int regs if possible,
-     otherwise memory.  */
-  int packed_p = 0;
-
   /* We need to compute how many registers are needed so we can
      allocate the PARALLEL but before we can do that we need to know
-     whether there are any packed fields.  If there are, int regs are
-     used regardless of whether there are fp values present.  */
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-    {
-      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
-       {
-         packed_p = 1;
-         break;
-       }
-    }
+     whether there are any packed fields.  The ABI obviously doesn't
+     specify how structures are passed in this case, so they are
+     defined to be passed in int regs if possible, otherwise memory,
+     regardless of whether there are fp values present.  */
+
+  if (! packed_p)
+    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+      {
+       if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
+         {
+           packed_p = true;
+           break;
+         }
+      }
 
   /* Compute how many registers we need.  */
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
@@ -4593,21 +5242,25 @@ function_arg_record_value_1 (type, startbitpos, parms)
          /* ??? FIXME: else assume zero offset.  */
 
          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           function_arg_record_value_1 (TREE_TYPE (field), bitpos, parms);
-         else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
-                   || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE
-                       && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
-                           == REAL_TYPE)))
-                  && TARGET_FPU
-                  && ! packed_p
-                  && parms->named)
+           function_arg_record_value_1 (TREE_TYPE (field),
+                                        bitpos,
+                                        parms,
+                                        packed_p);
+         else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+                   || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+                  && TARGET_FPU
+                  && parms->named
+                  && ! packed_p)
            {
              if (parms->intoffset != -1)
                {
+                 unsigned int startbit, endbit;
                  int intslots, this_slotno;
 
-                 intslots = (bitpos - parms->intoffset + BITS_PER_WORD - 1)
-                   / BITS_PER_WORD;
+                 startbit = parms->intoffset & -BITS_PER_WORD;
+                 endbit   = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
+
+                 intslots = (endbit - startbit) / BITS_PER_WORD;
                  this_slotno = parms->slotno + parms->intoffset
                    / BITS_PER_WORD;
 
@@ -4641,9 +5294,8 @@ function_arg_record_value_1 (type, startbitpos, parms)
    structure between parms->intoffset and bitpos to integer registers.  */
 
 static void 
-function_arg_record_value_3 (bitpos, parms)
-     HOST_WIDE_INT bitpos;
-     struct function_arg_record_value_parms *parms;
+function_arg_record_value_3 (HOST_WIDE_INT bitpos,
+                            struct function_arg_record_value_parms *parms)
 {
   enum machine_mode mode;
   unsigned int regno;
@@ -4687,6 +5339,7 @@ function_arg_record_value_3 (bitpos, parms)
 
       this_slotno += 1;
       intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+      mode = word_mode;
       parms->nregs += 1;
       intslots -= 1;
     }
@@ -4699,22 +5352,21 @@ function_arg_record_value_3 (bitpos, parms)
    to make that happen.  */
 
 static void
-function_arg_record_value_2 (type, startbitpos, parms)
-     tree type;
-     HOST_WIDE_INT startbitpos;
-     struct function_arg_record_value_parms *parms;
+function_arg_record_value_2 (tree type, HOST_WIDE_INT startbitpos,
+                            struct function_arg_record_value_parms *parms,
+                            bool packed_p)
 {
   tree field;
-  int packed_p = 0;
 
-  for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
-    {
-      if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
-       {
-         packed_p = 1;
-         break;
-       }
-    }
+  if (! packed_p)
+    for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+      {
+       if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
+         {
+           packed_p = true;
+           break;
+         }
+      }
 
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     {
@@ -4729,14 +5381,15 @@ function_arg_record_value_2 (type, startbitpos, parms)
          /* ??? FIXME: else assume zero offset.  */
 
          if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
-           function_arg_record_value_2 (TREE_TYPE (field), bitpos, parms);
-         else if ((TREE_CODE (TREE_TYPE (field)) == REAL_TYPE
-                   || (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE
-                       && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
-                           == REAL_TYPE)))
-                  && TARGET_FPU
-                  && ! packed_p
-                  && parms->named)
+           function_arg_record_value_2 (TREE_TYPE (field),
+                                        bitpos,
+                                        parms,
+                                        packed_p);
+         else if ((FLOAT_TYPE_P (TREE_TYPE (field))
+                   || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
+                  && TARGET_FPU
+                  && parms->named
+                  && ! packed_p)
            {
              int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
              int regno;
@@ -4744,9 +5397,6 @@ function_arg_record_value_2 (type, startbitpos, parms)
              rtx reg;
 
              function_arg_record_value_3 (bitpos, parms);
-             regno = SPARC_FP_ARG_FIRST + this_slotno * 2
-                     + ((mode == SFmode || mode == SCmode)
-                        && (bitpos & 32) != 0);
              switch (mode)
                {
                case SCmode: mode = SFmode; break;
@@ -4754,6 +5404,9 @@ function_arg_record_value_2 (type, startbitpos, parms)
                case TCmode: mode = TFmode; break;
                default: break;
                }
+             regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+             if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+               regno++;
              reg = gen_rtx_REG (mode, regno);
              XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
                = gen_rtx_EXPR_LIST (VOIDmode, reg,
@@ -4794,10 +5447,8 @@ function_arg_record_value_2 (type, startbitpos, parms)
    REGBASE is the regno of the base register for the parameter array.  */
    
 static rtx
-function_arg_record_value (type, mode, slotno, named, regbase)
-     tree type;
-     enum machine_mode mode;
-     int slotno, named, regbase;
+function_arg_record_value (tree type, enum machine_mode mode,
+                          int slotno, int named, int regbase)
 {
   HOST_WIDE_INT typesize = int_size_in_bytes (type);
   struct function_arg_record_value_parms parms;
@@ -4812,8 +5463,9 @@ function_arg_record_value (type, mode, slotno, named, regbase)
   /* Compute how many registers we need.  */
   parms.nregs = 0;
   parms.intoffset = 0;
-  function_arg_record_value_1 (type, 0, &parms);
+  function_arg_record_value_1 (type, 0, &parms, false);
 
+  /* Take into account pending integer fields.  */
   if (parms.intoffset != -1)
     {
       unsigned int startbit, endbit;
@@ -4874,7 +5526,7 @@ function_arg_record_value (type, mode, slotno, named, regbase)
   /* Fill in the entries.  */
   parms.nregs = 0;
   parms.intoffset = 0;
-  function_arg_record_value_2 (type, 0, &parms);
+  function_arg_record_value_2 (type, 0, &parms, false);
   function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
 
   if (parms.nregs != nregs)
@@ -4883,6 +5535,33 @@ function_arg_record_value (type, mode, slotno, named, regbase)
   return parms.ret;
 }
 
+/* Used by function_arg and function_value to implement the conventions
+   of the 64-bit ABI for passing and returning unions.
+   Return an expression valid as a return value for the two macros
+   FUNCTION_ARG and FUNCTION_VALUE.
+
+   SIZE is the size in bytes of the union.
+   MODE is the argument's machine 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)
+{
+  int nwords = ROUND_ADVANCE (size), i;
+  rtx regs;
+
+  /* Unions are passed left-justified.  */
+  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));
+
+  return regs;
+}
+
 /* Handle the FUNCTION_ARG macro.
    Determine where to put an argument to a function.
    Value is zero to push the argument on the stack,
@@ -4899,12 +5578,8 @@ function_arg_record_value (type, mode, slotno, named, regbase)
    INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.  */
 
 rtx
-function_arg (cum, mode, type, named, incoming_p)
-     const CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
-     int incoming_p;
+function_arg (const struct sparc_args *cum, enum machine_mode mode,
+             tree type, int named, int incoming_p)
 {
   int regbase = (incoming_p
                 ? SPARC_INCOMING_INT_ARG_FIRST
@@ -4923,13 +5598,34 @@ function_arg (cum, mode, type, named, incoming_p)
       reg = gen_rtx_REG (mode, regno);
       return reg;
     }
+    
+  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 */
+
+      return function_arg_record_value (type, mode, slotno, named, regbase);
+    }
+  else if (type && TREE_CODE (type) == UNION_TYPE)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+
+      if (size > 16)
+       abort (); /* shouldn't get here */
 
+      return function_arg_union_value (size, mode, regno);
+    }
   /* v9 fp args in reg slots beyond the int reg slots get passed in regs
      but also have the slot allocated for them.
      If no prototype is in scope fp values in register slots get passed
      in two places, either fp regs and int regs or fp regs and memory.  */
-  if ((GET_MODE_CLASS (mode) == MODE_FLOAT
-       || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
+  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))
     {
       reg = gen_rtx_REG (mode, regno);
@@ -4958,7 +5654,7 @@ function_arg (cum, mode, type, named, incoming_p)
 
             This is due to locate_and_pad_parm being called in
             expand_call whenever reg_parm_stack_space > 0, which
-            while benefical to our example here, would seem to be
+            while beneficial to our example here, would seem to be
             in error from what had been intended.  Ho hum...  -- r~ */
 #endif
            return reg;
@@ -4993,27 +5689,6 @@ function_arg (cum, mode, type, named, incoming_p)
            }
        }
     }
-  else 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 */
-
-      return function_arg_record_value (type, mode, slotno, named, regbase);
-    }
-  else if (type && TREE_CODE (type) == UNION_TYPE)
-    {
-      enum machine_mode mode;
-      int bytes = int_size_in_bytes (type);
-
-      if (bytes > 16)
-       abort ();
-
-      mode = mode_for_size (bytes * BITS_PER_UNIT, MODE_INT, 0);
-      reg = gen_rtx_REG (mode, regno);
-    }
   else
     {
       /* Scalar or complex int.  */
@@ -5035,11 +5710,8 @@ function_arg (cum, mode, type, named, incoming_p)
    mode] will be split between that reg and memory.  */
 
 int
-function_arg_partial_nregs (cum, mode, type, named)
-     const CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
+function_arg_partial_nregs (const struct sparc_args *cum,
+                           enum machine_mode mode, tree type, int named)
 {
   int slotno, regno, padding;
 
@@ -5054,77 +5726,74 @@ function_arg_partial_nregs (cum, mode, type, named)
       if ((slotno + (mode == BLKmode
                     ? ROUND_ADVANCE (int_size_in_bytes (type))
                     : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
-         > NPARM_REGS (SImode))
-       return NPARM_REGS (SImode) - slotno;
-      return 0;
+         > SPARC_INT_ARG_MAX)
+       return SPARC_INT_ARG_MAX - slotno;
     }
   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.  */
+
       if (type && AGGREGATE_TYPE_P (type))
        {
          int size = int_size_in_bytes (type);
-         int align = TYPE_ALIGN (type);
 
-         if (align == 16)
-           slotno += slotno & 1;
-         if (size > 8 && size <= 16
+         if (size > UNITS_PER_WORD
              && slotno == SPARC_INT_ARG_MAX - 1)
            return 1;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
               || (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-                  && ! TARGET_FPU))
+                  && ! (TARGET_FPU && named)))
        {
-         if (GET_MODE_ALIGNMENT (mode) == 128)
-           {
-             slotno += slotno & 1;
-             if (slotno == SPARC_INT_ARG_MAX - 2)
-               return 1;
-           }
-         else
-           {
-             if (slotno == SPARC_INT_ARG_MAX - 1)
-               return 1;
-           }
+         /* The complex types are passed as packed types.  */
+         if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
+             && slotno == SPARC_INT_ARG_MAX - 1)
+           return 1;
        }
       else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
        {
-         if (GET_MODE_ALIGNMENT (mode) == 128)
-           slotno += slotno & 1;
          if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
              > SPARC_FP_ARG_MAX)
            return 1;
        }
-      return 0;
     }
+
+  return 0;
 }
 
-/* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
+/* 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.  */
 
-int
-function_arg_pass_by_reference (cum, mode, type, named)
-     const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
-     enum machine_mode mode;
-     tree type;
-     int named ATTRIBUTE_UNUSED;
+static bool
+sparc_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                        enum machine_mode mode, tree type,
+                        bool named ATTRIBUTE_UNUSED)
 {
   if (TARGET_ARCH32)
     {
       return ((type && AGGREGATE_TYPE_P (type))
-             || mode == TFmode || mode == TCmode);
+             /* 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);
     }
   else
     {
       return ((type && TREE_CODE (type) == ARRAY_TYPE)
-             /* Consider complex values as aggregates, so care for TCmode.  */
-             || GET_MODE_SIZE (mode) > 16
              || (type
                  && AGGREGATE_TYPE_P (type)
-                 && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16));
+                 && (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);
     }
 }
 
@@ -5134,11 +5803,8 @@ function_arg_pass_by_reference (cum, mode, type, named)
    TYPE is null for libcalls where that information may not be available.  */
 
 void
-function_arg_advance (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum;
-     enum machine_mode mode;
-     tree type;
-     int named;
+function_arg_advance (struct sparc_args *cum, enum machine_mode mode,
+                     tree type, int named)
 {
   int slotno, regno, padding;
 
@@ -5168,14 +5834,6 @@ function_arg_advance (cum, mode, type, named)
          else /* passed by reference */
            ++cum->words;
        }
-      else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT)
-       {
-         cum->words += 2;
-       }
-      else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
-       {
-         cum->words += GET_MODE_SIZE (mode) / UNITS_PER_WORD;
-       }
       else
        {
          cum->words += (mode != BLKmode
@@ -5190,37 +5848,79 @@ function_arg_advance (cum, mode, type, named)
    argument slot.  */
 
 enum direction
-function_arg_padding (mode, type)
-     enum machine_mode mode;
-     tree type;
+function_arg_padding (enum machine_mode mode, tree type)
 {
   if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
     return upward;
 
-  /* This is the default definition.  */
-  return (! BYTES_BIG_ENDIAN
-         ? upward
-         : ((mode == BLKmode
-             ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-                && int_size_in_bytes (type) < (PARM_BOUNDARY / BITS_PER_UNIT))
-             : GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
-            ? downward : upward));
+  /* Fall back to the default.  */
+  return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
+}
+
+/* Handle the TARGET_RETURN_IN_MEMORY target hook.
+   Specify whether to return the return value in memory.  */
+
+static bool
+sparc_return_in_memory (tree type, 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').  */
+    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));
+  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').  */
+    return ((TYPE_MODE (type) == BLKmode
+            && (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32)
+           || GET_MODE_SIZE (TYPE_MODE (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)
+{
+  if (TARGET_ARCH64)
+    return 0;
+  else
+    {
+      if (incoming)
+       return 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));
+    }
 }
 
 /* Handle FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, and LIBCALL_VALUE macros.
    For v9, function return values are subject to the same rules as arguments,
-   except that up to 32-bytes may be returned in registers.  */
+   except that up to 32 bytes may be returned in registers.  */
 
 rtx
-function_value (type, mode, incoming_p)
-     tree type;
-     enum machine_mode mode;
-     int incoming_p;
+function_value (tree type, enum machine_mode mode, int incoming_p)
 {
-  int regno;
+  /* Beware that the two values are swapped here wrt function_arg.  */
   int regbase = (incoming_p
                 ? SPARC_OUTGOING_INT_ARG_FIRST
                 : SPARC_INCOMING_INT_ARG_FIRST);
+  int regno;
 
   if (TARGET_ARCH64 && type)
     {
@@ -5234,6 +5934,15 @@ function_value (type, mode, incoming_p)
 
          return function_arg_record_value (type, mode, 0, 1, regbase);
        }
+      else if (TREE_CODE (type) == UNION_TYPE)
+       {
+         HOST_WIDE_INT size = int_size_in_bytes (type);
+
+         if (size > 32)
+           abort (); /* shouldn't get here */
+
+         return function_arg_union_value (size, mode, regbase);
+       }
       else if (AGGREGATE_TYPE_P (type))
        {
          /* All other aggregate types are passed in an integer register
@@ -5241,22 +5950,31 @@ function_value (type, mode, incoming_p)
          HOST_WIDE_INT bytes = int_size_in_bytes (type);
 
          if (bytes > 32)
-           abort ();
+           abort (); /* shouldn't get here */
 
          mode = mode_for_size (bytes * 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
+            required by the SCD though, while the former is not
+            specified, so we favored compatibility and efficiency.
+
+            Now we're stuck for aggregates larger than 16 bytes,
+            because OImode vanished in the meantime.  Let's not
+            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);
        }
+      else if (GET_MODE_CLASS (mode) == MODE_INT
+              && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
+       mode = word_mode;
     }
-    
-  if (TARGET_ARCH64
-      && GET_MODE_CLASS (mode) == MODE_INT 
-      && GET_MODE_SIZE (mode) < UNITS_PER_WORD
-      && type && ! AGGREGATE_TYPE_P (type))
-    mode = DImode;
 
-  if (incoming_p)
-    regno = BASE_RETURN_VALUE_REG (mode);
+  if (TARGET_FPU && (FLOAT_MODE_P (mode) || VECTOR_MODE_P (mode)))
+    regno = SPARC_FP_ARG_FIRST;
   else
-    regno = BASE_OUTGOING_VALUE_REG (mode);
+    regno = regbase;
 
   return gen_rtx_REG (mode, regno);
 }
@@ -5265,14 +5983,14 @@ function_value (type, mode, incoming_p)
    to determine if stdarg or varargs is used and return the address of
    the first unnamed parameter.  */
 
-rtx
-sparc_builtin_saveregs ()
+static rtx
+sparc_builtin_saveregs (void)
 {
   int first_reg = current_function_args_info.words;
   rtx address;
   int regno;
 
-  for (regno = first_reg; regno < NPARM_REGS (word_mode); regno++)
+  for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++)
     emit_move_insn (gen_rtx_MEM (word_mode,
                                 gen_rtx_PLUS (Pmode,
                                               frame_pointer_rtx,
@@ -5280,7 +5998,7 @@ sparc_builtin_saveregs ()
                                                        + (UNITS_PER_WORD
                                                           * regno)))),
                    gen_rtx_REG (word_mode,
-                                BASE_INCOMING_ARG_REG (word_mode) + regno));
+                                SPARC_INCOMING_INT_ARG_FIRST + regno));
 
   address = gen_rtx_PLUS (Pmode,
                          frame_pointer_rtx,
@@ -5290,151 +6008,184 @@ sparc_builtin_saveregs ()
   return address;
 }
 
-/* Implement `va_start' for varargs and stdarg.  */
+/* Implement `va_start' for stdarg.  */
 
 void
-sparc_va_start (valist, nextarg)
-     tree valist;
-     rtx nextarg;
+sparc_va_start (tree valist, rtx nextarg)
 {
   nextarg = expand_builtin_saveregs ();
   std_expand_builtin_va_start (valist, nextarg);
 }
 
-/* Implement `va_arg'.  */
+/* Implement `va_arg' for stdarg.  */
 
-rtx
-sparc_va_arg (valist, type)
-     tree valist, type;
+static tree
+sparc_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
 {
   HOST_WIDE_INT size, rsize, align;
   tree addr, incr;
-  rtx addr_rtx;
-  int indirect = 0;
-
-  /* Round up sizeof(type) to a word.  */
-  size = int_size_in_bytes (type);
-  rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-  align = 0;
+  bool indirect;
+  tree ptrtype = build_pointer_type (type);
 
-  if (TARGET_ARCH64)
+  if (pass_by_reference (NULL, TYPE_MODE (type), type, 0))
     {
-      if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
-       align = 2 * UNITS_PER_WORD;
-
-      if (AGGREGATE_TYPE_P (type))
-       {
-         if ((unsigned HOST_WIDE_INT) size > 16)
-           {
-             indirect = 1;
-             size = rsize = UNITS_PER_WORD;
-           }
-         /* SPARC v9 ABI states that structures up to 8 bytes in size are
-            given one 8 byte slot.  */
-         else if (size == 0)
-           size = rsize = UNITS_PER_WORD;
-         else
-           size = rsize;
-       }
+      indirect = true;
+      size = rsize = UNITS_PER_WORD;
+      align = 0;
     }
   else
     {
-      if (AGGREGATE_TYPE_P (type)
-         || TYPE_MODE (type) == TFmode
-         || TYPE_MODE (type) == TCmode)
+      indirect = false;
+      size = int_size_in_bytes (type);
+      rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
+      align = 0;
+    
+      if (TARGET_ARCH64)
        {
-         indirect = 1;
-         size = rsize = UNITS_PER_WORD;
+         /* For SPARC64, objects requiring 16-byte alignment get it.  */
+         if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
+           align = 2 * UNITS_PER_WORD;
+
+         /* SPARC-V9 ABI states that structures up to 16 bytes in size
+            are given whole slots as needed.  */
+         if (AGGREGATE_TYPE_P (type))
+           {
+             if (size == 0)
+               size = rsize = UNITS_PER_WORD;
+             else
+               size = rsize;
+           }
        }
     }
 
   incr = valist;
   if (align)
     {
-      incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                        build_int_2 (align - 1, 0)));
-      incr = fold (build (BIT_AND_EXPR, ptr_type_node, incr,
-                         build_int_2 (-align, -1)));
+      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)));
     }
 
-  addr = incr = save_expr (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)));
+
+  if (indirect)
     {
-      addr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                         build_int_2 (rsize - size, 0)));
+      addr = fold_convert (build_pointer_type (ptrtype), addr);
+      addr = build_fold_indirect_ref (addr);
     }
-  incr = fold (build (PLUS_EXPR, ptr_type_node, incr,
-                     build_int_2 (rsize, 0)));
-
-  incr = build (MODIFY_EXPR, ptr_type_node, valist, incr);
-  TREE_SIDE_EFFECTS (incr) = 1;
-  expand_expr (incr, const0_rtx, VOIDmode, EXPAND_NORMAL);
-
-  addr_rtx = expand_expr (addr, NULL, Pmode, EXPAND_NORMAL);
-
   /* If the address isn't aligned properly for the type,
      we may need to copy to a temporary.  
      FIXME: This is inefficient.  Usually we can do this
      in registers.  */
-  if (align == 0
-      && TYPE_ALIGN (type) > BITS_PER_WORD
-      && !indirect)
-    {
-      /* FIXME: We really need to specify that the temporary is live
-        for the whole function because expand_builtin_va_arg wants
-        the alias set to be get_varargs_alias_set (), but in this
-        case the alias set is that for TYPE and if the memory gets
-        reused it will be reused with alias set TYPE.  */
-      rtx tmp = assign_temp (type, 0, 1, 0);
-      rtx dest_addr;
-
-      addr_rtx = force_reg (Pmode, addr_rtx);
-      addr_rtx = gen_rtx_MEM (BLKmode, addr_rtx);
-      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
-      set_mem_align (addr_rtx, BITS_PER_WORD);
-      tmp = shallow_copy_rtx (tmp);
-      PUT_MODE (tmp, BLKmode);
-      set_mem_alias_set (tmp, 0);
-      
-      dest_addr = emit_block_move (tmp, addr_rtx, GEN_INT (rsize),
-                                  BLOCK_OP_NORMAL);
-      if (dest_addr != NULL_RTX)
-       addr_rtx = dest_addr;
-      else
-       addr_rtx = XCEXP (tmp, 0, MEM);
+  else if (align == 0
+          && TYPE_ALIGN (type) > BITS_PER_WORD)
+    {
+      tree tmp = create_tmp_var (type, "va_arg_tmp");
+      tree dest_addr = build_fold_addr_expr (tmp);
+
+      tree copy = build_function_call_expr
+       (implicit_built_in_decls[BUILT_IN_MEMCPY],
+        tree_cons (NULL_TREE, dest_addr,
+                   tree_cons (NULL_TREE, addr,
+                              tree_cons (NULL_TREE, size_int (rsize),
+                                         NULL_TREE))));
+
+      gimplify_and_add (copy, pre_p);
+      addr = dest_addr;
     }
+  else
+    addr = fold_convert (ptrtype, addr);
 
-  if (indirect)
+  incr = fold (build2 (PLUS_EXPR, ptr_type_node, incr, ssize_int (rsize)));
+  incr = build2 (MODIFY_EXPR, ptr_type_node, valist, incr);
+  gimplify_and_add (incr, post_p);
+
+  return build_fold_indirect_ref (addr);
+}
+\f
+/* Return the string to output an unconditional branch to LABEL, which is
+   the operand number of the label.
+
+   DEST is the destination insn (i.e. the label), INSN is the source.  */
+
+const char *
+output_ubranch (rtx dest, int label, rtx insn)
+{
+  static char string[64];
+  bool noop = 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))))
+    {
+      strcpy (string, "b\t");
+      noop = true;
+    }
+  else
     {
-      addr_rtx = force_reg (Pmode, addr_rtx);
-      addr_rtx = gen_rtx_MEM (Pmode, addr_rtx);
-      set_mem_alias_set (addr_rtx, get_varargs_alias_set ());
+      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");
     }
 
-  return addr_rtx;
+  p = strchr (string, '\0');
+  *p++ = '%';
+  *p++ = 'l';
+  *p++ = '0' + label;
+  *p++ = '%';
+  if (noop)
+    *p++ = '#';
+  else
+    *p++ = '(';
+  *p = '\0';
+
+  return string;
 }
-\f
+
 /* Return the string to output a conditional branch to LABEL, which is
    the operand number of the label.  OP is the conditional expression.
    XEXP (OP, 0) is assumed to be a condition code register (integer or
    floating point) and its mode specifies what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    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.
-
-   INSN, if set, is the insn.  */
+   NOOP is nonzero if we have to follow this branch by a noop.  */
 
-char *
-output_cbranch (op, dest, label, reversed, annul, noop, insn)
-     rtx op, dest;
-     int label;
-     int reversed, annul, noop;
-     rtx insn;
+const char *
+output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
+               int noop, rtx insn)
 {
-  static char string[50];
+  static char string[64];
   enum rtx_code code = GET_CODE (op);
   rtx cc_reg = XEXP (op, 0);
   enum machine_mode mode = GET_MODE (cc_reg);
@@ -5450,7 +6201,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
      to
 
      be,pn %xcc, .+12
-     nop
+      nop
      ba .LC30
 
      and
@@ -5460,10 +6211,10 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
      to
 
      fbe,pt %fcc2, .+16
-     nop
+      nop
      ba .LC29  */
 
-  far = get_attr_length (insn) >= 3;
+  far = TARGET_V9 && (get_attr_length (insn) >= 3);
   if (reversed ^ far)
     {
       /* Reversal of FP compares takes care -- an ordered compare
@@ -5593,9 +6344,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
       spaces -= 2;
     }
 
-  if (! TARGET_V9)
-    labelno = "";
-  else
+  if (TARGET_V9)
     {
       rtx note;
       int v8 = 0;
@@ -5645,6 +6394,9 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
          spaces -= 3;
        }
     }
+  else
+    labelno = "";
+
   if (spaces > 0)
     *p++ = '\t';
   else
@@ -5653,10 +6405,10 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
   p = strchr (p, '\0');
   if (far)
     {
-      strcpy (p, ".+12\n\tnop\n\tb\t");
+      strcpy (p, ".+12\n\t nop\n\tb\t");
       if (annul || noop)
         p[3] = '6';
-      p += 13;
+      p += 14;
     }
   *p++ = '%';
   *p++ = 'l';
@@ -5665,7 +6417,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
   *p++ = label + '0';
   *p = '\0';
   if (noop)
-    strcpy (p, "\n\tnop");
+    strcpy (p, "\n\t nop");
 
   return string;
 }
@@ -5676,9 +6428,7 @@ output_cbranch (op, dest, label, reversed, annul, noop, insn)
    values as arguments instead of the TFmode registers themselves,
    that's why we cannot call emit_float_lib_cmp.  */
 void
-sparc_emit_float_lib_cmp (x, y, comparison)
-     rtx x, y;
-     enum rtx_code comparison;
+sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
 {
   const char *qpfunc;
   rtx slot0, slot1, result, tem, tem2;
@@ -5815,15 +6565,12 @@ sparc_emit_float_lib_cmp (x, y, comparison)
    optabs would emit if we didn't have TFmode patterns.  */
 
 void
-sparc_emit_floatunsdi (operands)
-     rtx operands[2];
+sparc_emit_floatunsdi (rtx *operands, enum machine_mode mode)
 {
   rtx neglab, donelab, i0, i1, f0, in, out;
-  enum machine_mode mode;
 
   out = operands[0];
   in = force_reg (DImode, operands[1]);
-  mode = GET_MODE (out);
   neglab = gen_label_rtx ();
   donelab = gen_label_rtx ();
   i0 = gen_reg_rtx (DImode);
@@ -5847,25 +6594,65 @@ sparc_emit_floatunsdi (operands)
   emit_label (donelab);
 }
 
+/* Generate an FP to unsigned DImode conversion.  This is the same code
+   optabs would emit if we didn't have TFmode patterns.  */
+
+void
+sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
+{
+  rtx neglab, donelab, i0, i1, f0, in, out, limit;
+
+  out = operands[0];
+  in = force_reg (mode, operands[1]);
+  neglab = gen_label_rtx ();
+  donelab = gen_label_rtx ();
+  i0 = gen_reg_rtx (DImode);
+  i1 = gen_reg_rtx (DImode);
+  limit = gen_reg_rtx (mode);
+  f0 = gen_reg_rtx (mode);
+
+  emit_move_insn (limit,
+                 CONST_DOUBLE_FROM_REAL_VALUE (
+                   REAL_VALUE_ATOF ("9223372036854775808.0", mode), mode));
+  emit_cmp_and_jump_insns (in, limit, GE, NULL_RTX, mode, 0, neglab);
+
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         out,
+                         gen_rtx_FIX (DImode, gen_rtx_FIX (mode, in))));
+  emit_jump_insn (gen_jump (donelab));
+  emit_barrier ();
+
+  emit_label (neglab);
+
+  emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_MINUS (mode, in, limit)));
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         i0,
+                         gen_rtx_FIX (DImode, gen_rtx_FIX (mode, f0))));
+  emit_insn (gen_movdi (i1, const1_rtx));
+  emit_insn (gen_ashldi3 (i1, i1, GEN_INT (63)));
+  emit_insn (gen_xordi3 (out, i0, i1));
+
+  emit_label (donelab);
+}
+
 /* Return the string to output a conditional branch to LABEL, testing
    register REG.  LABEL is the operand number of the label; REG is the
    operand number of the reg.  OP is the conditional expression.  The mode
    of REG says what kind of comparison we made.
 
+   DEST is the destination insn (i.e. the label), INSN is the source.
+
    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.  */
 
-char *
-output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
-     rtx op, dest;
-     int reg, label;
-     int reversed, annul, noop;
-     rtx insn;
+const char *
+output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
+                int annul, int noop, rtx insn)
 {
-  static char string[50];
+  static char string[64];
   enum rtx_code code = GET_CODE (op);
   enum machine_mode mode = GET_MODE (XEXP (op, 0));
   rtx note;
@@ -5880,7 +6667,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
      to
      
      brz,pn %g1, .+12
-     nop
+      nop
      ba,pt %xcc, .LC30
      
      and
@@ -5890,7 +6677,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
      to
      
      brlz,pt %o1, .+16
-     nop
+      nop
      ba,pt %xcc, .LC29  */
 
   far = get_attr_length (insn) >= 3;
@@ -5971,10 +6758,10 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
            veryfar = 0;
        }
 
-      strcpy (p, ".+12\n\tnop\n\t");
+      strcpy (p, ".+12\n\t nop\n\t");
       if (annul || noop)
         p[3] = '6';
-      p += 11;
+      p += 12;
       if (veryfar)
        {
          strcpy (p, "b\t");
@@ -5992,7 +6779,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
   *p = '\0';
 
   if (noop)
-    strcpy (p, "\n\tnop");
+    strcpy (p, "\n\t nop");
 
   return string;
 }
@@ -6003,9 +6790,7 @@ output_v9branch (op, dest, reg, label, reversed, annul, noop, insn)
  */
 
 static int
-epilogue_renumber (where, test)
-     register rtx *where;
-     int test;
+epilogue_renumber (register rtx *where, int test)
 {
   register const char *fmt;
   register int i;
@@ -6022,7 +6807,7 @@ epilogue_renumber (where, test)
       if (REGNO (*where) >= 8 && REGNO (*where) < 24)      /* oX or lX */
        return 1;
       if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
-       *where = gen_rtx (REG, GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
+       *where = gen_rtx_REG (GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
     case SCRATCH:
     case CC0:
     case PC:
@@ -6089,7 +6874,7 @@ static const int *const reg_alloc_orders[] = {
   reg_nonleaf_alloc_order};
 
 void
-order_regs_for_local_alloc ()
+order_regs_for_local_alloc (void)
 {
   static int last_order_nonleaf = 1;
 
@@ -6106,9 +6891,7 @@ order_regs_for_local_alloc ()
    mem<-->reg splits to be run.  */
 
 int
-sparc_splitdi_legitimate (reg, mem)
-     rtx reg;
-     rtx mem;
+sparc_splitdi_legitimate (rtx reg, rtx mem)
 {
   /* Punt if we are here by mistake.  */
   if (! reload_completed)
@@ -6129,12 +6912,11 @@ sparc_splitdi_legitimate (reg, mem)
 }
 
 /* Return 1 if x and y are some kind of REG and they refer to
-   different hard registers.  This test is guarenteed to be
+   different hard registers.  This test is guaranteed to be
    run after reload.  */
 
 int
-sparc_absnegfloat_split_legitimate (x, y)
-     rtx x, y;
+sparc_absnegfloat_split_legitimate (rtx x, rtx y)
 {
   if (GET_CODE (x) != REG)
     return 0;
@@ -6151,8 +6933,7 @@ sparc_absnegfloat_split_legitimate (x, y)
    Note reg1 and reg2 *must* be hard registers.  */
 
 int
-registers_ok_for_ldd_peep (reg1, reg2)
-     rtx reg1, reg2;
+registers_ok_for_ldd_peep (rtx reg1, rtx reg2)
 {
   /* We might have been passed a SUBREG.  */
   if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG) 
@@ -6200,12 +6981,11 @@ registers_ok_for_ldd_peep (reg1, reg2)
    NULL_RTX.  */
 
 int
-mems_ok_for_ldd_peep (mem1, mem2, dependent_reg_rtx)
-      rtx mem1, mem2, dependent_reg_rtx;
+mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
 {
   rtx addr1, addr2;
   unsigned int reg1;
-  int offset1;
+  HOST_WIDE_INT offset1;
 
   /* The mems cannot be volatile.  */
   if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
@@ -6275,8 +7055,7 @@ mems_ok_for_ldd_peep (mem1, mem2, dependent_reg_rtx)
    ldd and std insns.  */
 
 int
-register_ok_for_ldd (reg)
-     rtx reg;
+register_ok_for_ldd (rtx reg)
 {
   /* We might have been passed a SUBREG.  */
   if (GET_CODE (reg) != REG) 
@@ -6293,10 +7072,7 @@ register_ok_for_ldd (reg)
    For `%' followed by punctuation, CODE is the punctuation and X is null.  */
 
 void
-print_operand (file, x, code)
-     FILE *file;
-     rtx x;
-     int code;
+print_operand (FILE *file, rtx x, int code)
 {
   switch (code)
     {
@@ -6331,7 +7107,12 @@ print_operand (file, x, code)
       /* 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+%d", frame_base_name, frame_base_offset);
+      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.  */
@@ -6581,10 +7362,7 @@ print_operand (file, x, code)
    special handling for aligned DI-mode objects.  */
 
 static bool
-sparc_assemble_integer (x, size, aligned_p)
-     rtx x;
-     unsigned int size;
-     int aligned_p;
+sparc_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
   /* ??? We only output .xword's for symbols and only then in environments
      where the assembler can handle them.  */
@@ -6639,8 +7417,7 @@ sparc_assemble_integer (x, size, aligned_p)
 #endif
 
 unsigned long
-sparc_type_code (type)
-     register tree type;
+sparc_type_code (register tree type)
 {
   register unsigned long qualifiers = 0;
   register unsigned shift;
@@ -6693,7 +7470,7 @@ sparc_type_code (type)
 
          /* Carefully distinguish all the standard types of C,
             without messing up if the language is not C.  We do this by
-            testing TYPE_PRECISION and TREE_UNSIGNED.  The old code used to
+            testing TYPE_PRECISION and TYPE_UNSIGNED.  The old code used to
             look at both the names and the above fields, but that's redundant.
             Any type whose size is between two C types will be considered
             to be the wider of the two types.  Also, we do not have a
@@ -6703,16 +7480,16 @@ sparc_type_code (type)
             size, but that's fine, since neither can the assembler.  */
 
          if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
-           return (qualifiers | (TREE_UNSIGNED (type) ? 12 : 2));
+           return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2));
   
          else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
-           return (qualifiers | (TREE_UNSIGNED (type) ? 13 : 3));
+           return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3));
   
          else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
-           return (qualifiers | (TREE_UNSIGNED (type) ? 14 : 4));
+           return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4));
   
          else
-           return (qualifiers | (TREE_UNSIGNED (type) ? 15 : 5));
+           return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5));
   
        case REAL_TYPE:
          /* If this is a range type, consider it to be the underlying
@@ -6735,6 +7512,7 @@ sparc_type_code (type)
             existing front-ends.  */
          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.  */
@@ -6764,10 +7542,9 @@ sparc_type_code (type)
    Emit enough FLUSH insns to synchronize the data and instruction caches.  */
 
 void
-sparc_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp, fnaddr, cxt;
+sparc_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 {
-  /* SPARC 32 bit trampoline:
+  /* SPARC 32-bit trampoline:
 
        sethi   %hi(fn), %g1
        sethi   %hi(static), %g2
@@ -6777,10 +7554,6 @@ sparc_initialize_trampoline (tramp, fnaddr, cxt)
     SETHI i,r  = 00rr rrr1 00ii iiii iiii iiii iiii iiii
     JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii
    */
-#ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
-#endif
 
   emit_move_insn
     (gen_rtx_MEM (SImode, plus_constant (tramp, 0)),
@@ -6819,22 +7592,25 @@ sparc_initialize_trampoline (tramp, fnaddr, cxt)
       && sparc_cpu != PROCESSOR_ULTRASPARC3)
     emit_insn (gen_flush (validize_mem (gen_rtx_MEM (SImode,
                                                     plus_constant (tramp, 8)))));
+
+  /* Call __enable_execute_stack after writing onto the stack to make sure
+     the stack address is accessible.  */
+#ifdef ENABLE_EXECUTE_STACK
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
+                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+#endif
+
 }
 
-/* The 64 bit version is simpler because it makes more sense to load the
+/* The 64-bit version is simpler because it makes more sense to load the
    values as "immediate" data out of the trampoline.  It's also easier since
    we can read the PC without clobbering a register.  */
 
 void
-sparc64_initialize_trampoline (tramp, fnaddr, cxt)
-     rtx tramp, fnaddr, cxt;
+sparc64_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
 {
-#ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx (SYMBOL_REF, Pmode, "__enable_execute_stack"),
-                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
-#endif
+  /* SPARC 64-bit trampoline:
 
-  /*
        rd      %pc, %g1
        ldx     [%g1+24], %g5
        jmp     %g5
@@ -6857,817 +7633,127 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt)
   if (sparc_cpu != PROCESSOR_ULTRASPARC
       && sparc_cpu != PROCESSOR_ULTRASPARC3)
     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
+     the stack address is accessible.  */
+#ifdef ENABLE_EXECUTE_STACK
+  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
+                     LCT_NORMAL, VOIDmode, 1, tramp, Pmode);
+#endif
 }
 \f
-/* Subroutines to support a flat (single) register window calling
-   convention.  */
-
-/* Single-register window sparc stack frames look like:
-
-             Before call                       After call
-        +-----------------------+      +-----------------------+
-   high |                      |       |                       |
-   mem  |  caller's temps.     |       |  caller's temps.      |
-       |                       |       |                       |
-        +-----------------------+      +-----------------------+
-       |                       |       |                       |
-        |  arguments on stack.  |      |  arguments on stack.  |
-       |                       |       |                       |
-        +-----------------------+FP+92->+-----------------------+
-       |  6 words to save      |       |  6 words to save      |
-       |  arguments passed     |       |  arguments passed     |
-       |  in registers, even   |       |  in registers, even   |
-               |  if not passed.       |       |  if not passed.       |
- SP+68->+-----------------------+FP+68->+-----------------------+
-        | 1 word struct addr   |       | 1 word struct addr    |
-        +-----------------------+FP+64->+-----------------------+
-        |                      |       |                       |
-        | 16 word reg save area        |       | 16 word reg save area |
-               |                       |       |                       |
-    SP->+-----------------------+   FP->+-----------------------+
-                                       | 4 word area for       |
-                                       | fp/alu reg moves      |
-                                FP-16->+-----------------------+
-                                       |                       |
-                                       |  local variables      |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  fp register save     |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  gp register save     |
-                                        |                      |
-                                       +-----------------------+
-                                       |                       |
-                                        |  alloca allocations   |
-                                       |                       |
-                                       +-----------------------+
-                                       |                       |
-                                        |  arguments on stack   |
-                                       |                       |
-                                SP+92->+-----------------------+
-                                        |  6 words to save      |
-                                       |  arguments passed     |
-                                        |  in registers, even   |
-   low                                         |  if not passed.       |
-   memory                       SP+68->+-----------------------+
-                                       | 1 word struct addr    |
-                                SP+64->+-----------------------+
-                                       |                       |
-                                       I 16 word reg save area |
-                                       |                       |
-                                   SP->+-----------------------+  */
-
-/* Structure to be filled in by sparc_flat_compute_frame_size with register
-   save masks, and offsets for the current function.  */
-
-struct sparc_frame_info
-{
-  unsigned long total_size;    /* # bytes that the entire frame takes up.  */
-  unsigned long var_size;      /* # bytes that variables take up.  */
-  unsigned long args_size;     /* # bytes that outgoing arguments take up.  */
-  unsigned long extra_size;    /* # bytes of extra gunk.  */
-  unsigned int  gp_reg_size;   /* # bytes needed to store gp regs.  */
-  unsigned int  fp_reg_size;   /* # bytes needed to store fp regs.  */
-  unsigned long gmask;         /* Mask of saved gp registers.  */
-  unsigned long fmask;         /* Mask of saved fp registers.  */
-  unsigned long reg_offset;    /* Offset from new sp to store regs.  */
-  int          initialized;    /* Nonzero if frame size already calculated.  */
-};
-
-/* Current frame information calculated by sparc_flat_compute_frame_size.  */
-struct sparc_frame_info current_frame_info;
+/* Adjust the cost of a scheduling dependency.  Return the new cost of
+   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
 
-/* Zero structure to initialize current_frame_info.  */
-struct sparc_frame_info zero_frame_info;
+static int
+supersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
+{
+  enum attr_type insn_type;
 
-/* Tell prologue and epilogue if register REGNO should be saved / restored.  */
+  if (! recog_memoized (insn))
+    return 0;
 
-#define RETURN_ADDR_REGNUM 15
-#define HARD_FRAME_POINTER_MASK (1 << (HARD_FRAME_POINTER_REGNUM))
-#define RETURN_ADDR_MASK (1 << (RETURN_ADDR_REGNUM))
+  insn_type = get_attr_type (insn);
 
-#define MUST_SAVE_REGISTER(regno) \
- ((regs_ever_live[regno] && !call_used_regs[regno])                    \
-  || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)      \
-  || (regno == RETURN_ADDR_REGNUM && regs_ever_live[RETURN_ADDR_REGNUM]))
+  if (REG_NOTE_KIND (link) == 0)
+    {
+      /* Data dependency; DEP_INSN writes a register that INSN reads some
+        cycles later.  */
 
-/* Return the bytes needed to compute the frame pointer from the current
-   stack pointer.  */
+      /* if a load, then the dependence must be on the memory address;
+        add an extra "cycle".  Note that the cost could be two cycles
+        if the reg was written late in an instruction group; we ca not tell
+        here.  */
+      if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD)
+       return cost + 3;
 
-unsigned long
-sparc_flat_compute_frame_size (size)
-     int size;                 /* # of var. bytes allocated.  */
-{
-  int regno;
-  unsigned long total_size;    /* # bytes that the entire frame takes up.  */
-  unsigned long var_size;      /* # bytes that variables take up.  */
-  unsigned long args_size;     /* # bytes that outgoing arguments take up.  */
-  unsigned long extra_size;    /* # extra bytes.  */
-  unsigned int  gp_reg_size;   /* # bytes needed to store gp regs.  */
-  unsigned int  fp_reg_size;   /* # bytes needed to store fp regs.  */
-  unsigned long gmask;         /* Mask of saved gp registers.  */
-  unsigned long fmask;         /* Mask of saved fp registers.  */
-  unsigned long reg_offset;    /* Offset to register save area.  */
-  int           need_aligned_p;        /* 1 if need the save area 8 byte aligned.  */
-
-  /* This is the size of the 16 word reg save area, 1 word struct addr
-     area, and 4 word fp/alu register copy area.  */
-  extra_size = -STARTING_FRAME_OFFSET + FIRST_PARM_OFFSET(0);
-  var_size = size;
-  gp_reg_size = 0;
-  fp_reg_size = 0;
-  gmask = 0;
-  fmask = 0;
-  reg_offset = 0;
-  need_aligned_p = 0;
-
-  args_size = 0;
-  if (!leaf_function_p ())
-    {
-      /* Also include the size needed for the 6 parameter registers.  */
-      args_size = current_function_outgoing_args_size + 24;
-    }
-  total_size = var_size + args_size;
-
-  /* Calculate space needed for gp registers.  */
-  for (regno = 1; regno <= 31; regno++)
-    {
-      if (MUST_SAVE_REGISTER (regno))
+      /* Get the delay only if the address of the store is the dependence.  */
+      if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE)
        {
-         /* If we need to save two regs in a row, ensure there's room to bump
-            up the address to align it to a doubleword boundary.  */
-         if ((regno & 0x1) == 0 && MUST_SAVE_REGISTER (regno+1))
-           {
-             if (gp_reg_size % 8 != 0)
-               gp_reg_size += 4;
-             gp_reg_size += 2 * UNITS_PER_WORD;
-             gmask |= 3 << regno;
-             regno++;
-             need_aligned_p = 1;
-           }
-         else
-           {
-             gp_reg_size += UNITS_PER_WORD;
-             gmask |= 1 << regno;
-           }
-       }
-    }
+         rtx pat = PATTERN(insn);
+         rtx dep_pat = PATTERN (dep_insn);
 
-  /* Calculate space needed for fp registers.  */
-  for (regno = 32; regno <= 63; regno++)
-    {
-      if (regs_ever_live[regno] && !call_used_regs[regno])
-       {
-         fp_reg_size += UNITS_PER_WORD;
-         fmask |= 1 << (regno - 32);
-       }
-    }
+         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+           return cost;  /* This should not happen!  */
 
-  if (gmask || fmask)
-    {
-      int n;
-      reg_offset = FIRST_PARM_OFFSET(0) + args_size;
-      /* Ensure save area is 8 byte aligned if we need it.  */
-      n = reg_offset % 8;
-      if (need_aligned_p && n != 0)
-       {
-         total_size += 8 - n;
-         reg_offset += 8 - n;
+         /* The dependency between the two instructions was on the data that
+            is being stored.  Assume that this implies that the address of the
+            store is not dependent.  */
+         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
+           return cost;
+
+         return cost + 3;  /* An approximation.  */
        }
-      total_size += gp_reg_size + fp_reg_size;
-    }
 
-  /* If we must allocate a stack frame at all, we must also allocate 
-     room for register window spillage, so as to be binary compatible
-     with libraries and operating systems that do not use -mflat.  */
-  if (total_size > 0)
-    total_size += extra_size;
+      /* A shift instruction cannot receive its data from an instruction
+        in the same cycle; add a one cycle penalty.  */
+      if (insn_type == TYPE_SHIFT)
+       return cost + 3;   /* Split before cascade into shift.  */
+    }
   else
-    extra_size = 0;
-
-  total_size = SPARC_STACK_ALIGN (total_size);
+    {
+      /* Anti- or output- dependency; DEP_INSN reads/writes a register that
+        INSN writes some cycles later.  */
 
-  /* Save other computed information.  */
-  current_frame_info.total_size  = total_size;
-  current_frame_info.var_size    = var_size;
-  current_frame_info.args_size   = args_size;
-  current_frame_info.extra_size  = extra_size;
-  current_frame_info.gp_reg_size = gp_reg_size;
-  current_frame_info.fp_reg_size = fp_reg_size;
-  current_frame_info.gmask      = gmask;
-  current_frame_info.fmask      = fmask;
-  current_frame_info.reg_offset         = reg_offset;
-  current_frame_info.initialized = reload_completed;
+      /* These are only significant for the fpu unit; writing a fp reg before
+         the fpu has finished with it stalls the processor.  */
 
-  /* Ok, we're done.  */
-  return total_size;
+      /* Reusing an integer register causes no problems.  */
+      if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
+       return 0;
+    }
+       
+  return cost;
 }
-\f
-/* Save/restore registers in GMASK and FMASK at register BASE_REG plus offset
-   OFFSET.
-
-   BASE_REG must be 8 byte aligned.  This allows us to test OFFSET for
-   appropriate alignment and use DOUBLEWORD_OP when we can.  We assume
-   [BASE_REG+OFFSET] will always be a valid address.
 
-   WORD_OP is either "st" for save, "ld" for restore.
-   DOUBLEWORD_OP is either "std" for save, "ldd" for restore.  */
-
-void
-sparc_flat_save_restore (file, base_reg, offset, gmask, fmask, word_op,
-                        doubleword_op, base_offset)
-     FILE *file;
-     const char *base_reg;
-     unsigned int offset;
-     unsigned long gmask;
-     unsigned long fmask;
-     const char *word_op;
-     const char *doubleword_op;
-     unsigned long base_offset;
+static int
+hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 {
-  int regno;
+  enum attr_type insn_type, dep_type;
+  rtx pat = PATTERN(insn);
+  rtx dep_pat = PATTERN (dep_insn);
 
-  if (gmask == 0 && fmask == 0)
-    return;
+  if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+    return cost;
 
-  /* Save registers starting from high to low.  We've already saved the
-     previous frame pointer and previous return address for the debugger's
-     sake.  The debugger allows us to not need a nop in the epilog if at least
-     one register is reloaded in addition to return address.  */
+  insn_type = get_attr_type (insn);
+  dep_type = get_attr_type (dep_insn);
 
-  if (gmask)
+  switch (REG_NOTE_KIND (link))
     {
-      for (regno = 1; regno <= 31; regno++)
-       {
-         if ((gmask & (1L << regno)) != 0)
-           {
-             if ((regno & 0x1) == 0 && ((gmask & (1L << (regno+1))) != 0))
-               {
-                 /* We can save two registers in a row.  If we're not at a
-                    double word boundary, move to one.
-                    sparc_flat_compute_frame_size ensures there's room to do
-                    this.  */
-                 if (offset % 8 != 0)
-                   offset += UNITS_PER_WORD;
-
-                 if (word_op[0] == 's')
-                   {
-                     fprintf (file, "\t%s\t%s, [%s+%d]\n",
-                              doubleword_op, reg_names[regno],
-                              base_reg, offset);
-                     if (dwarf2out_do_frame ())
-                       {
-                         char *l = dwarf2out_cfi_label ();
-                         dwarf2out_reg_save (l, regno, offset + base_offset);
-                         dwarf2out_reg_save
-                           (l, regno+1, offset+base_offset + UNITS_PER_WORD);
-                       }
-                   }
-                 else
-                   fprintf (file, "\t%s\t[%s+%d], %s\n",
-                            doubleword_op, base_reg, offset,
-                            reg_names[regno]);
+    case 0:
+      /* Data dependency; DEP_INSN writes a register that INSN reads some
+        cycles later.  */
 
-                 offset += 2 * UNITS_PER_WORD;
-                 regno++;
-               }
-             else
-               {
-                 if (word_op[0] == 's')
-                   {
-                     fprintf (file, "\t%s\t%s, [%s+%d]\n",
-                              word_op, reg_names[regno],
-                              base_reg, offset);
-                     if (dwarf2out_do_frame ())
-                       dwarf2out_reg_save ("", regno, offset + base_offset);
-                   }
-                 else
-                   fprintf (file, "\t%s\t[%s+%d], %s\n",
-                            word_op, base_reg, offset, reg_names[regno]);
+      switch (insn_type)
+       {
+       case TYPE_STORE:
+       case TYPE_FPSTORE:
+         /* Get the delay iff the address of the store is the dependence.  */
+         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
+           return cost;
 
-                 offset += UNITS_PER_WORD;
-               }
-           }
-       }
-    }
+         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
+           return cost;
+         return cost + 3;
 
-  if (fmask)
-    {
-      for (regno = 32; regno <= 63; regno++)
-       {
-         if ((fmask & (1L << (regno - 32))) != 0)
+       case TYPE_LOAD:
+       case TYPE_SLOAD:
+       case TYPE_FPLOAD:
+         /* If a load, then the dependence must be on the memory address.  If
+            the addresses aren't equal, then it might be a false dependency */
+         if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
            {
-             if (word_op[0] == 's')
-               {
-                 fprintf (file, "\t%s\t%s, [%s+%d]\n",
-                          word_op, reg_names[regno],
-                          base_reg, offset);
-                 if (dwarf2out_do_frame ())
-                   dwarf2out_reg_save ("", regno, offset + base_offset);
-               }
-             else
-               fprintf (file, "\t%s\t[%s+%d], %s\n",
-                        word_op, base_reg, offset, reg_names[regno]);
+             if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
+                 || GET_CODE (SET_DEST (dep_pat)) != MEM        
+                 || GET_CODE (SET_SRC (pat)) != MEM
+                 || ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
+                                   XEXP (SET_SRC (pat), 0)))
+               return cost + 2;
 
-             offset += UNITS_PER_WORD;
+             return cost + 8;        
            }
-       }
-    }
-}
-\f
-/* Set up the stack and frame (if desired) for the function.  */
-
-static void
-sparc_flat_function_prologue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
-{
-  const char *sp_str = reg_names[STACK_POINTER_REGNUM];
-  unsigned long gmask = current_frame_info.gmask;
-
-  sparc_output_scratch_registers (file);
-
-  /* This is only for the human reader.  */
-  fprintf (file, "\t%s#PROLOGUE# 0\n", ASM_COMMENT_START);
-  fprintf (file, "\t%s# vars= %ld, regs= %d/%d, args= %d, extra= %ld\n",
-          ASM_COMMENT_START,
-          current_frame_info.var_size,
-          current_frame_info.gp_reg_size / 4,
-          current_frame_info.fp_reg_size / 4,
-          current_function_outgoing_args_size,
-          current_frame_info.extra_size);
-
-  size = SPARC_STACK_ALIGN (size);
-  size = (! current_frame_info.initialized
-         ? sparc_flat_compute_frame_size (size)
-         : current_frame_info.total_size);
-
-  /* These cases shouldn't happen.  Catch them now.  */
-  if (size == 0 && (gmask || current_frame_info.fmask))
-    abort ();
-
-  /* Allocate our stack frame by decrementing %sp.
-     At present, the only algorithm gdb can use to determine if this is a
-     flat frame is if we always set %i7 if we set %sp.  This can be optimized
-     in the future by putting in some sort of debugging information that says
-     this is a `flat' function.  However, there is still the case of debugging
-     code without such debugging information (including cases where most fns
-     have such info, but there is one that doesn't).  So, always do this now
-     so we don't get a lot of code out there that gdb can't handle.
-     If the frame pointer isn't needn't then that's ok - gdb won't be able to
-     distinguish us from a non-flat function but there won't (and shouldn't)
-     be any differences anyway.  The return pc is saved (if necessary) right
-     after %i7 so gdb won't have to look too far to find it.  */
-  if (size > 0)
-    {
-      unsigned int reg_offset = current_frame_info.reg_offset;
-      const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
-      static const char *const t1_str = "%g1";
-
-      /* Things get a little tricky if local variables take up more than ~4096
-        bytes and outgoing arguments take up more than ~4096 bytes.  When that
-        happens, the register save area can't be accessed from either end of
-        the frame.  Handle this by decrementing %sp to the start of the gp
-        register save area, save the regs, update %i7, and then set %sp to its
-        final value.  Given that we only have one scratch register to play
-        with it is the cheapest solution, and it helps gdb out as it won't
-        slow down recognition of flat functions.
-        Don't change the order of insns emitted here without checking with
-        the gdb folk first.  */
-
-      /* Is the entire register save area offsettable from %sp?  */
-      if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
-       {
-         if (size <= 4096)
-           {
-             fprintf (file, "\tadd\t%s, %d, %s\n",
-                      sp_str, (int) -size, sp_str);
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n",
-                          fp_str, sp_str, reg_offset);
-                 fprintf (file, "\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
-                          sp_str, (int) -size, fp_str, ASM_COMMENT_START);
-                 reg_offset += 4;
-               }
-           }
-         else
-           {
-             fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC
-                      ", %s\n\tsub\t%s, %s, %s\n",
-                      size, t1_str, sp_str, t1_str, sp_str);
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n",
-                          fp_str, sp_str, reg_offset);
-                 fprintf (file, "\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
-                          sp_str, t1_str, fp_str, ASM_COMMENT_START);
-                 reg_offset += 4;
-               }
-           }
-         if (dwarf2out_do_frame ())
-           {
-             char *l = dwarf2out_cfi_label ();
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
-                                     reg_offset - 4 - size);
-                 dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
-               }
-             else
-               dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size);
-           }
-         if (gmask & RETURN_ADDR_MASK)
-           {
-             fprintf (file, "\tst\t%s, [%s+%d]\n",
-                      reg_names[RETURN_ADDR_REGNUM], sp_str, reg_offset);
-             if (dwarf2out_do_frame ())
-               dwarf2out_return_save ("", reg_offset - size);
-             reg_offset += 4;
-           }
-         sparc_flat_save_restore (file, sp_str, reg_offset,
-                                  gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
-                                  current_frame_info.fmask,
-                                  "st", "std", -size);
-       }
-      else
-       {
-         /* Subtract %sp in two steps, but make sure there is always a
-            64 byte register save area, and %sp is properly aligned.  */
-         /* Amount to decrement %sp by, the first time.  */
-         unsigned HOST_WIDE_INT size1 = ((size - reg_offset + 64) + 15) & -16;
-         /* Offset to register save area from %sp.  */
-         unsigned HOST_WIDE_INT offset = size1 - (size - reg_offset);
-         
-         if (size1 <= 4096)
-           {
-             fprintf (file, "\tadd\t%s, %d, %s\n",
-                      sp_str, (int) -size1, sp_str);
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n\tsub\t%s, %d, %s\t%s# set up frame pointer\n",
-                          fp_str, sp_str, (int) offset, sp_str, (int) -size1,
-                          fp_str, ASM_COMMENT_START);
-                 offset += 4;
-               }
-           }
-         else
-           {
-             fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC
-                      ", %s\n\tsub\t%s, %s, %s\n",
-                      size1, t1_str, sp_str, t1_str, sp_str);
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 fprintf (file, "\tst\t%s, [%s+%d]\n\tadd\t%s, %s, %s\t%s# set up frame pointer\n",
-                          fp_str, sp_str, (int) offset, sp_str, t1_str,
-                          fp_str, ASM_COMMENT_START);
-                 offset += 4;
-               }
-           }
-         if (dwarf2out_do_frame ())
-           {
-             char *l = dwarf2out_cfi_label ();
-             if (gmask & HARD_FRAME_POINTER_MASK)
-               {
-                 dwarf2out_reg_save (l, HARD_FRAME_POINTER_REGNUM,
-                                     offset - 4 - size1);
-                 dwarf2out_def_cfa (l, HARD_FRAME_POINTER_REGNUM, 0);
-               }
-             else
-               dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, size1);
-           }
-         if (gmask & RETURN_ADDR_MASK)
-           {
-             fprintf (file, "\tst\t%s, [%s+%d]\n",
-                      reg_names[RETURN_ADDR_REGNUM], sp_str, (int) offset);
-             if (dwarf2out_do_frame ())
-               /* offset - size1 == reg_offset - size
-                  if reg_offset were updated above like offset.  */
-               dwarf2out_return_save ("", offset - size1);
-             offset += 4;
-           }
-         sparc_flat_save_restore (file, sp_str, offset,
-                                  gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
-                                  current_frame_info.fmask,
-                                  "st", "std", -size1);
-         fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC
-                  ", %s\n\tsub\t%s, %s, %s\n",
-                  size - size1, t1_str, sp_str, t1_str, sp_str);
-         if (dwarf2out_do_frame ())
-           if (! (gmask & HARD_FRAME_POINTER_MASK))
-             dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, size);
-       }
-    }
-
-  fprintf (file, "\t%s#PROLOGUE# 1\n", ASM_COMMENT_START);
-}
-\f
-/* Do any necessary cleanup after a function to restore stack, frame,
-   and regs.  */
-
-static void
-sparc_flat_function_epilogue (file, size)
-     FILE *file;
-     HOST_WIDE_INT size;
-{
-  rtx epilogue_delay = current_function_epilogue_delay_list;
-  int noepilogue = FALSE;
-
-  /* This is only for the human reader.  */
-  fprintf (file, "\t%s#EPILOGUE#\n", ASM_COMMENT_START);
-
-  /* The epilogue does not depend on any registers, but the stack
-     registers, so we assume that if we have 1 pending nop, it can be
-     ignored, and 2 it must be filled (2 nops occur for integer
-     multiply and divide).  */
-
-  size = SPARC_STACK_ALIGN (size);
-  size = (!current_frame_info.initialized
-          ? sparc_flat_compute_frame_size (size)
-          : current_frame_info.total_size);
-
-  if (size == 0 && epilogue_delay == 0)
-    {
-      rtx insn = get_last_insn ();
-
-      /* If the last insn was a BARRIER, we don't have to write any code
-        because a jump (aka return) was put there.  */
-      if (GET_CODE (insn) == NOTE)
-       insn = prev_nonnote_insn (insn);
-      if (insn && GET_CODE (insn) == BARRIER)
-       noepilogue = TRUE;
-    }
-
-  if (!noepilogue)
-    {
-      unsigned HOST_WIDE_INT reg_offset = current_frame_info.reg_offset;
-      unsigned HOST_WIDE_INT size1;
-      const char *const sp_str = reg_names[STACK_POINTER_REGNUM];
-      const char *const fp_str = reg_names[HARD_FRAME_POINTER_REGNUM];
-      static const char *const t1_str = "%g1";
-
-      /* In the reload sequence, we don't need to fill the load delay
-        slots for most of the loads, also see if we can fill the final
-        delay slot if not otherwise filled by the reload sequence.  */
-
-      if (size > 4095)
-       fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC ", %s\n",
-                size, t1_str);
-
-      if (frame_pointer_needed)
-       {
-         if (size > 4095)
-           fprintf (file,"\tsub\t%s, %s, %s\t\t%s# sp not trusted here\n",
-                    fp_str, t1_str, sp_str, ASM_COMMENT_START);
-         else
-           fprintf (file,"\tsub\t%s, %d, %s\t\t%s# sp not trusted here\n",
-                    fp_str, (int) size, sp_str, ASM_COMMENT_START);
-       }
-
-      /* Is the entire register save area offsettable from %sp?  */
-      if (reg_offset < 4096 - 64 * (unsigned) UNITS_PER_WORD)
-       {
-         size1 = 0;
-       }
-      else
-       {
-         /* Restore %sp in two steps, but make sure there is always a
-            64 byte register save area, and %sp is properly aligned.  */
-         /* Amount to increment %sp by, the first time.  */
-         size1 = ((reg_offset - 64 - 16) + 15) & -16;
-         /* Offset to register save area from %sp.  */
-         reg_offset = size1 - reg_offset;
-
-         fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC
-                  ", %s\n\tadd\t%s, %s, %s\n",
-                  size1, t1_str, sp_str, t1_str, sp_str);
-       }
-
-      /* We must restore the frame pointer and return address reg first
-        because they are treated specially by the prologue output code.  */
-      if (current_frame_info.gmask & HARD_FRAME_POINTER_MASK)
-       {
-         fprintf (file, "\tld\t[%s+%d], %s\n",
-                  sp_str, (int) reg_offset, fp_str);
-         reg_offset += 4;
-       }
-      if (current_frame_info.gmask & RETURN_ADDR_MASK)
-       {
-         fprintf (file, "\tld\t[%s+%d], %s\n",
-                  sp_str, (int) reg_offset, reg_names[RETURN_ADDR_REGNUM]);
-         reg_offset += 4;
-       }
-
-      /* Restore any remaining saved registers.  */
-      sparc_flat_save_restore (file, sp_str, reg_offset,
-                              current_frame_info.gmask & ~(HARD_FRAME_POINTER_MASK | RETURN_ADDR_MASK),
-                              current_frame_info.fmask,
-                              "ld", "ldd", 0);
-
-      /* If we had to increment %sp in two steps, record it so the second
-        restoration in the epilogue finishes up.  */
-      if (size1 > 0)
-       {
-         size -= size1;
-         if (size > 4095)
-           fprintf (file, "\tset\t" HOST_WIDE_INT_PRINT_DEC ", %s\n",
-                    size, t1_str);
-       }
-
-      if (current_function_returns_struct)
-       fprintf (file, "\tjmp\t%%o7+12\n");
-      else
-       fprintf (file, "\tretl\n");
-
-      /* If the only register saved is the return address, we need a
-        nop, unless we have an instruction to put into it.  Otherwise
-        we don't since reloading multiple registers doesn't reference
-        the register being loaded.  */
-
-      if (epilogue_delay)
-       {
-         if (size)
-           abort ();
-         final_scan_insn (XEXP (epilogue_delay, 0), file, 1, -2, 1);
-       }
-
-      else if (size > 4095)
-       fprintf (file, "\tadd\t%s, %s, %s\n", sp_str, t1_str, sp_str);
-
-      else if (size > 0)
-       fprintf (file, "\tadd\t%s, %d, %s\n", sp_str, (int) size, sp_str);
-
-      else
-       fprintf (file, "\tnop\n");
-    }
-
-  /* Reset state info for each function.  */
-  current_frame_info = zero_frame_info;
-
-  sparc_output_deferred_case_vectors ();
-}
-\f
-/* Define the number of delay slots needed for the function epilogue.
-
-   On the sparc, we need a slot if either no stack has been allocated,
-   or the only register saved is the return register.  */
-
-int
-sparc_flat_epilogue_delay_slots ()
-{
-  if (!current_frame_info.initialized)
-    (void) sparc_flat_compute_frame_size (get_frame_size ());
-
-  if (current_frame_info.total_size == 0)
-    return 1;
-
-  return 0;
-}
-
-/* Return true if TRIAL is a valid insn for the epilogue delay slot.
-   Any single length instruction which doesn't reference the stack or frame
-   pointer is OK.  */
-
-int
-sparc_flat_eligible_for_epilogue_delay (trial, slot)
-     rtx trial;
-     int slot ATTRIBUTE_UNUSED;
-{
-  rtx pat = PATTERN (trial);
-
-  if (get_attr_length (trial) != 1)
-    return 0;
-
-  if (! reg_mentioned_p (stack_pointer_rtx, pat)
-      && ! reg_mentioned_p (frame_pointer_rtx, pat))
-    return 1;
-
-  return 0;
-}
-\f
-/* Adjust the cost of a scheduling dependency.  Return the new cost of
-   a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
-
-static int
-supersparc_adjust_cost (insn, link, dep_insn, cost)
-     rtx insn;
-     rtx link;
-     rtx dep_insn;
-     int cost;
-{
-  enum attr_type insn_type;
-
-  if (! recog_memoized (insn))
-    return 0;
-
-  insn_type = get_attr_type (insn);
-
-  if (REG_NOTE_KIND (link) == 0)
-    {
-      /* Data dependency; DEP_INSN writes a register that INSN reads some
-        cycles later.  */
-
-      /* if a load, then the dependence must be on the memory address;
-        add an extra "cycle".  Note that the cost could be two cycles
-        if the reg was written late in an instruction group; we ca not tell
-        here.  */
-      if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD)
-       return cost + 3;
-
-      /* Get the delay only if the address of the store is the dependence.  */
-      if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE)
-       {
-         rtx pat = PATTERN(insn);
-         rtx dep_pat = PATTERN (dep_insn);
-
-         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
-           return cost;  /* This should not happen!  */
-
-         /* The dependency between the two instructions was on the data that
-            is being stored.  Assume that this implies that the address of the
-            store is not dependent.  */
-         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
-           return cost;
-
-         return cost + 3;  /* An approximation.  */
-       }
-
-      /* A shift instruction cannot receive its data from an instruction
-        in the same cycle; add a one cycle penalty.  */
-      if (insn_type == TYPE_SHIFT)
-       return cost + 3;   /* Split before cascade into shift.  */
-    }
-  else
-    {
-      /* Anti- or output- dependency; DEP_INSN reads/writes a register that
-        INSN writes some cycles later.  */
-
-      /* These are only significant for the fpu unit; writing a fp reg before
-         the fpu has finished with it stalls the processor.  */
-
-      /* Reusing an integer register causes no problems.  */
-      if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
-       return 0;
-    }
-       
-  return cost;
-}
-
-static int
-hypersparc_adjust_cost (insn, link, dep_insn, cost)
-     rtx insn;
-     rtx link;
-     rtx dep_insn;
-     int cost;
-{
-  enum attr_type insn_type, dep_type;
-  rtx pat = PATTERN(insn);
-  rtx dep_pat = PATTERN (dep_insn);
-
-  if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
-    return cost;
-
-  insn_type = get_attr_type (insn);
-  dep_type = get_attr_type (dep_insn);
-
-  switch (REG_NOTE_KIND (link))
-    {
-    case 0:
-      /* Data dependency; DEP_INSN writes a register that INSN reads some
-        cycles later.  */
-
-      switch (insn_type)
-       {
-       case TYPE_STORE:
-       case TYPE_FPSTORE:
-         /* Get the delay iff the address of the store is the dependence.  */
-         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
-           return cost;
-
-         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
-           return cost;
-         return cost + 3;
-
-       case TYPE_LOAD:
-       case TYPE_SLOAD:
-       case TYPE_FPLOAD:
-         /* If a load, then the dependence must be on the memory address.  If
-            the addresses aren't equal, then it might be a false dependency */
-         if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
-           {
-             if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
-                 || GET_CODE (SET_DEST (dep_pat)) != MEM        
-                 || GET_CODE (SET_SRC (pat)) != MEM
-                 || ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
-                                   XEXP (SET_SRC (pat), 0)))
-               return cost + 2;
-
-             return cost + 8;        
-           }
-         break;
+         break;
 
        case TYPE_BRANCH:
          /* Compare to branch latency is 0.  There is no benefit from
@@ -7698,11 +7784,7 @@ hypersparc_adjust_cost (insn, link, dep_insn, cost)
 }
 
 static int
-sparc_adjust_cost(insn, link, dep, cost)
-     rtx insn;
-     rtx link;
-     rtx dep;
-     int cost;
+sparc_adjust_cost(rtx insn, rtx link, rtx dep, int cost)
 {
   switch (sparc_cpu)
     {
@@ -7720,27 +7802,14 @@ sparc_adjust_cost(insn, link, dep, cost)
 }
 
 static void
-sparc_sched_init (dump, sched_verbose, max_ready)
-     FILE *dump ATTRIBUTE_UNUSED;
-     int sched_verbose ATTRIBUTE_UNUSED;
-     int max_ready ATTRIBUTE_UNUSED;
+sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
+                 int sched_verbose ATTRIBUTE_UNUSED,
+                 int max_ready ATTRIBUTE_UNUSED)
 {
 }
   
 static int
-sparc_use_dfa_pipeline_interface ()
-{
-  if ((1 << sparc_cpu) &
-      ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
-       (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
-       (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
-       (1 << PROCESSOR_ULTRASPARC3)))
-    return 1;
-  return 0;
-}
-
-static int
-sparc_use_sched_lookahead ()
+sparc_use_sched_lookahead (void)
 {
   if (sparc_cpu == PROCESSOR_ULTRASPARC
       || sparc_cpu == PROCESSOR_ULTRASPARC3)
@@ -7753,7 +7822,7 @@ sparc_use_sched_lookahead ()
 }
 
 static int
-sparc_issue_rate ()
+sparc_issue_rate (void)
 {
   switch (sparc_cpu)
     {
@@ -7774,8 +7843,7 @@ sparc_issue_rate ()
 }
 
 static int
-set_extends (insn)
-     rtx insn;
+set_extends (rtx insn)
 {
   register rtx pat = PATTERN (insn);
 
@@ -7842,9 +7910,7 @@ static GTY(()) rtx sparc_addr_diff_list;
 static GTY(()) rtx sparc_addr_list;
 
 void
-sparc_defer_case_vector (lab, vec, diff)
-     rtx lab, vec;
-     int diff;
+sparc_defer_case_vector (rtx lab, rtx vec, int diff)
 {
   vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
   if (diff)
@@ -7855,8 +7921,7 @@ sparc_defer_case_vector (lab, vec, diff)
 }
 
 static void 
-sparc_output_addr_vec (vec)
-     rtx vec;
+sparc_output_addr_vec (rtx vec)
 {
   rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
   int idx, vlen = XVECLEN (body, 0);
@@ -7884,8 +7949,7 @@ sparc_output_addr_vec (vec)
 }
 
 static void 
-sparc_output_addr_diff_vec (vec)
-     rtx vec;
+sparc_output_addr_diff_vec (rtx vec)
 {
   rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
   rtx base = XEXP (XEXP (body, 0), 0);
@@ -7917,7 +7981,7 @@ sparc_output_addr_diff_vec (vec)
 }
 
 static void
-sparc_output_deferred_case_vectors ()
+sparc_output_deferred_case_vectors (void)
 {
   rtx t;
   int align;
@@ -7945,8 +8009,7 @@ sparc_output_deferred_case_vectors ()
    unknown.  Return 1 if the high bits are zero, -1 if the register is
    sign extended.  */
 int
-sparc_check_64 (x, insn)
-     rtx x, insn;
+sparc_check_64 (rtx x, rtx insn)
 {
   /* If a register is set only once it is safe to ignore insns this
      code does not know how to handle.  The loop will either recognize
@@ -8005,11 +8068,8 @@ sparc_check_64 (x, insn)
 
 /* Returns assembly code to perform a DImode shift using
    a 64-bit global or out register on SPARC-V8+.  */
-char *
-sparc_v8plus_shift (operands, insn, opcode)
-     rtx *operands;
-     rtx insn;
-     const char *opcode;
+const char *
+output_v8plus_shift (rtx *operands, rtx insn, const char *opcode)
 {
   static char asm_code[60];
 
@@ -8018,6 +8078,10 @@ sparc_v8plus_shift (operands, insn, opcode)
   if (which_alternative != 2)
     operands[3] = operands[0];
 
+  /* We can only shift by constants <= 63. */
+  if (GET_CODE (operands[2]) == CONST_INT)
+    operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
+
   if (GET_CODE (operands[1]) == CONST_INT)
     {
       output_asm_insn ("mov\t%1, %3", operands);
@@ -8042,8 +8106,7 @@ sparc_v8plus_shift (operands, insn, opcode)
    for profiling a function entry.  */
 
 void
-sparc_profile_hook (labelno)
-     int labelno;
+sparc_profile_hook (int labelno)
 {
   char buf[32];
   rtx lab, fun;
@@ -8057,9 +8120,7 @@ sparc_profile_hook (labelno)
 \f
 #ifdef OBJECT_FORMAT_ELF
 static void
-sparc_elf_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+sparc_elf_asm_named_section (const char *name, unsigned int flags)
 {
   if (flags & SECTION_MERGE)
     {
@@ -8075,6 +8136,8 @@ sparc_elf_asm_named_section (name, flags)
     fputs (",#alloc", asm_out_file);
   if (flags & SECTION_WRITE)
     fputs (",#write", asm_out_file);
+  if (flags & SECTION_TLS)
+    fputs (",#tls", asm_out_file);
   if (flags & SECTION_CODE)
     fputs (",#execinstr", asm_out_file);
 
@@ -8084,10 +8147,12 @@ sparc_elf_asm_named_section (name, flags)
 }
 #endif /* OBJECT_FORMAT_ELF */
 
-/* We do not allow sibling calls if -mflat, nor
-   we do not allow indirect calls to be optimized into sibling calls.
-   
-   Also, on sparc 32-bit we cannot emit a sibling call when the
+/* We do not allow indirect calls to be optimized into sibling calls.
+
+   We cannot use sibling calls when delayed branches are disabled
+   because they will likely require the call delay slot to be filled.
+
+   Also, on SPARC 32-bit we cannot emit a sibling call when the
    current function returns a structure.  This is because the "unimp
    after call" convention would cause the callee to return to the
    wrong place.  The generic code already disallows cases where the
@@ -8096,55 +8161,117 @@ sparc_elf_asm_named_section (name, flags)
    It may seem strange how this last case could occur.  Usually there
    is code after the call which jumps to epilogue code which dumps the
    return value into the struct return area.  That ought to invalidate
-   the sibling call right?  Well, in the c++ case we can end up passing
+   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.  */
 static bool
-sparc_function_ok_for_sibcall (decl, exp)
-     tree decl;
-     tree exp ATTRIBUTE_UNUSED;
+sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   return (decl
-         && ! TARGET_FLAT
+         && flag_delayed_branch
          && (TARGET_ARCH64 || ! current_function_returns_struct));
 }
-
-/* ??? Similar to the standard section selection, but force reloc-y-ness
-   if SUNOS4_SHARED_LIBRARIES.  Unclear why this helps (as opposed to
-   pretending PIC always on), but that's what the old code did.  */
+\f
+/* libfunc renaming.  */
+#include "config/gofast.h"
 
 static void
-sparc_aout_select_section (t, reloc, align)
-     tree t;
-     int reloc;
-     unsigned HOST_WIDE_INT align;
+sparc_init_libfuncs (void)
 {
-  default_select_section (t, reloc | SUNOS4_SHARED_LIBRARIES, align);
-}
+  if (TARGET_ARCH32)
+    {
+      /* Use the subroutines that Sun's library provides for integer
+        multiply and divide.  The `*' prevents an underscore from
+        being prepended by the compiler. .umul is a little faster
+        than .mul.  */
+      set_optab_libfunc (smul_optab, SImode, "*.umul");
+      set_optab_libfunc (sdiv_optab, SImode, "*.div");
+      set_optab_libfunc (udiv_optab, SImode, "*.udiv");
+      set_optab_libfunc (smod_optab, SImode, "*.rem");
+      set_optab_libfunc (umod_optab, SImode, "*.urem");
+
+      /* TFmode arithmetic.  These names are part of the SPARC 32bit ABI.  */
+      set_optab_libfunc (add_optab, TFmode, "_Q_add");
+      set_optab_libfunc (sub_optab, TFmode, "_Q_sub");
+      set_optab_libfunc (neg_optab, TFmode, "_Q_neg");
+      set_optab_libfunc (smul_optab, TFmode, "_Q_mul");
+      set_optab_libfunc (sdiv_optab, TFmode, "_Q_div");
+
+      /* We can define the TFmode sqrt optab only if TARGET_FPU.  This
+        is because with soft-float, the SFmode and DFmode sqrt
+        instructions will be absent, and the compiler will notice and
+        try to use the TFmode sqrt instruction for calls to the
+        builtin function sqrt, but this fails.  */
+      if (TARGET_FPU)
+       set_optab_libfunc (sqrt_optab, TFmode, "_Q_sqrt");
+
+      set_optab_libfunc (eq_optab, TFmode, "_Q_feq");
+      set_optab_libfunc (ne_optab, TFmode, "_Q_fne");
+      set_optab_libfunc (gt_optab, TFmode, "_Q_fgt");
+      set_optab_libfunc (ge_optab, TFmode, "_Q_fge");
+      set_optab_libfunc (lt_optab, TFmode, "_Q_flt");
+      set_optab_libfunc (le_optab, TFmode, "_Q_fle");
+
+      set_conv_libfunc (sext_optab,   TFmode, SFmode, "_Q_stoq");
+      set_conv_libfunc (sext_optab,   TFmode, DFmode, "_Q_dtoq");
+      set_conv_libfunc (trunc_optab,  SFmode, TFmode, "_Q_qtos");
+      set_conv_libfunc (trunc_optab,  DFmode, TFmode, "_Q_qtod");
+
+      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");
+
+      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");
+       }
+
+      if (SUN_CONVERSION_LIBFUNCS)
+       {
+         set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftoll");
+         set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoull");
+         set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtoll");
+         set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoull");
+       }
+    }
+  if (TARGET_ARCH64)
+    {
+      /* In the SPARC 64bit ABI, SImode multiply and divide functions
+        do not exist in the library.  Make sure the compiler does not
+        emit calls to them by accident.  (It should always use the
+         hardware instructions.)  */
+      set_optab_libfunc (smul_optab, SImode, 0);
+      set_optab_libfunc (sdiv_optab, SImode, 0);
+      set_optab_libfunc (udiv_optab, SImode, 0);
+      set_optab_libfunc (smod_optab, SImode, 0);
+      set_optab_libfunc (umod_optab, SImode, 0);
 
-/* Use text section for a constant unless we need more alignment than
-   that offers.  */
+      if (SUN_INTEGER_MULTIPLY_64)
+       {
+         set_optab_libfunc (smul_optab, DImode, "__mul64");
+         set_optab_libfunc (sdiv_optab, DImode, "__div64");
+         set_optab_libfunc (udiv_optab, DImode, "__udiv64");
+         set_optab_libfunc (smod_optab, DImode, "__rem64");
+         set_optab_libfunc (umod_optab, DImode, "__urem64");
+       }
 
-static void
-sparc_aout_select_rtx_section (mode, x, align)
-     enum machine_mode mode;
-     rtx x;
-     unsigned HOST_WIDE_INT align;
-{
-  if (align <= MAX_TEXT_ALIGN
-      && ! (flag_pic && (symbolic_operand (x, mode)
-                        || SUNOS4_SHARED_LIBRARIES)))
-    readonly_data_section ();
-  else
-    data_section ();
-}
+      if (SUN_CONVERSION_LIBFUNCS)
+       {
+         set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftol");
+         set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoul");
+         set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtol");
+         set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoul");
+       }
+    }
 
+  gofast_maybe_init_libfuncs ();
+}
+\f
 int
-sparc_extra_constraint_check (op, c, strict)
-     rtx op;
-     int c;
-     int strict;
+sparc_extra_constraint_check (rtx op, int c, int strict)
 {
   int reload_ok_mem;
 
@@ -8207,397 +8334,252 @@ sparc_extra_constraint_check (op, c, strict)
    ??? the latencies and then CSE will just use that.  */
 
 static bool
-sparc_rtx_costs (x, code, outer_code, total)
-     rtx x;
-     int code, outer_code, *total;
+sparc_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
+  enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
+
   switch (code)
     {
-    case PLUS: case MINUS: case ABS: case NEG:
-    case FLOAT: case UNSIGNED_FLOAT:
-    case FIX: case UNSIGNED_FIX:
-    case FLOAT_EXTEND: case FLOAT_TRUNCATE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (4);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (5);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-           default:
-             *total = COSTS_N_INSNS (1);
-             return true;
-           }
-       }
-
-      *total = COSTS_N_INSNS (1);
-      return true;
-
-    case SQRT:
-      switch (sparc_cpu)
+    case CONST_INT:
+      if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
        {
-       case PROCESSOR_ULTRASPARC:
-         if (GET_MODE (x) == SFmode)
-           *total = COSTS_N_INSNS (13);
-         else
-           *total = COSTS_N_INSNS (23);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (GET_MODE (x) == SFmode)
-           *total = COSTS_N_INSNS (20);
-         else
-           *total = COSTS_N_INSNS (29);
-         return true;
-
-       case PROCESSOR_SUPERSPARC:
-         *total = COSTS_N_INSNS (12);
-         return true;
-
-       case PROCESSOR_CYPRESS:
-         *total = COSTS_N_INSNS (63);
-         return true;
-
-       case PROCESSOR_HYPERSPARC:
-       case PROCESSOR_SPARCLITE86X:
-         *total = COSTS_N_INSNS (17);
-         return true;
-
-       default:
-         *total = COSTS_N_INSNS (30);
+         *total = 0;
          return true;
        }
+      /* FALLTHRU */
 
-    case COMPARE:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (1);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (5);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-           default:
-             *total = COSTS_N_INSNS (1);
-             return true;
-           }
-       }
+    case HIGH:
+      *total = 2;
+      return true;
 
-      /* ??? Maybe mark integer compares as zero cost on
-        ??? all UltraSPARC processors because the result
-        ??? can be bypassed to a branch in the same group.  */
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+      *total = 4;
+      return true;
 
-      *total = COSTS_N_INSNS (1);
+    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)))
+       *total = 0;
+      else
+       *total = 8;
       return true;
 
-    case MULT:
-      if (FLOAT_MODE_P (GET_MODE (x)))
+    case MEM:
+      /* If outer-code was a sign or zero extension, a cost
+        of COSTS_N_INSNS (1) was already added in.  This is
+        why we are subtracting it back out.  */
+      if (outer_code == ZERO_EXTEND)
        {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-           case PROCESSOR_ULTRASPARC3:
-             *total = COSTS_N_INSNS (4);
-             return true;
-
-           case PROCESSOR_SUPERSPARC:
-             *total = COSTS_N_INSNS (3);
-             return true;
-
-           case PROCESSOR_CYPRESS:
-             *total = COSTS_N_INSNS (7);
-             return true;
-
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-             *total = COSTS_N_INSNS (1);
-             return true;
-
-           default:
-             *total = COSTS_N_INSNS (5);
-             return true;
-           }
+         *total = sparc_costs->int_zload - COSTS_N_INSNS (1);
        }
-
-      /* The latency is actually variable for Ultra-I/II
-        And if one of the inputs have a known constant
-        value, we could calculate this precisely.
-
-        However, for that to be useful we would need to
-        add some machine description changes which would
-        make sure small constants ended up in rs1 of the
-        multiply instruction.  This is because the multiply
-        latency is determined by the number of clear (or
-        set if the value is negative) bits starting from
-        the most significant bit of the first input.
-
-        The algorithm for computing num_cycles of a multiply
-        on Ultra-I/II is:
-
-               if (rs1 < 0)
-                       highest_bit = highest_clear_bit(rs1);
-               else
-                       highest_bit = highest_set_bit(rs1);
-               if (num_bits < 3)
-                       highest_bit = 3;
-               num_cycles = 4 + ((highest_bit - 3) / 2);
-
-        If we did that we would have to also consider register
-        allocation issues that would result from forcing such
-        a value into a register.
-
-        There are other similar tricks we could play if we
-        knew, for example, that one input was an array index.
-
-        Since we do not play any such tricks currently the
-        safest thing to do is report the worst case latency.  */
-      if (sparc_cpu == PROCESSOR_ULTRASPARC)
+      else if (outer_code == SIGN_EXTEND)
        {
-         *total = (GET_MODE (x) == DImode
-                   ? COSTS_N_INSNS (34) : COSTS_N_INSNS (19));
-         return true;
+         *total = sparc_costs->int_sload - COSTS_N_INSNS (1);
        }
-
-      /* Multiply latency on Ultra-III, fortunately, is constant.  */
-      if (sparc_cpu == PROCESSOR_ULTRASPARC3)
+      else if (float_mode_p)
        {
-         *total = COSTS_N_INSNS (6);
-         return true;
+         *total = sparc_costs->float_load;
        }
-
-      if (sparc_cpu == PROCESSOR_HYPERSPARC
-         || sparc_cpu == PROCESSOR_SPARCLITE86X)
+      else
        {
-         *total = COSTS_N_INSNS (17);
-         return true;
+         *total = sparc_costs->int_load;
        }
 
-      *total = (TARGET_HARD_MUL ? COSTS_N_INSNS (5) : COSTS_N_INSNS (25));
       return true;
 
-    case DIV:
-    case UDIV:
-    case MOD:
-    case UMOD:
-      if (FLOAT_MODE_P (GET_MODE (x)))
-       {
-         switch (sparc_cpu)
-           {
-           case PROCESSOR_ULTRASPARC:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (13);
-             else
-               *total = COSTS_N_INSNS (23);
-             return true;
+    case PLUS:
+    case MINUS:
+      if (float_mode_p)
+       *total = sparc_costs->float_plusminus;
+      else
+       *total = COSTS_N_INSNS (1);
+      return false;
 
-           case PROCESSOR_ULTRASPARC3:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (17);
-             else
-               *total = COSTS_N_INSNS (20);
-             return true;
+    case MULT:
+      if (float_mode_p)
+       *total = sparc_costs->float_mul;
+      else if (! TARGET_HARD_MUL)
+       *total = COSTS_N_INSNS (25);
+      else
+       {
+         int bit_cost;
 
-           case PROCESSOR_SUPERSPARC:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (6);
-             else
-               *total = COSTS_N_INSNS (9);
-             return true;
+         bit_cost = 0;
+         if (sparc_costs->int_mul_bit_factor)
+           {
+             int nbits;
 
-           case PROCESSOR_HYPERSPARC:
-           case PROCESSOR_SPARCLITE86X:
-             if (GET_MODE (x) == SFmode)
-               *total = COSTS_N_INSNS (8);
+             if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+               {
+                 unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
+                 for (nbits = 0; value != 0; value &= value - 1)
+                   nbits++;
+               }
+             else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
+                      && GET_MODE (XEXP (x, 1)) == DImode)
+               {
+                 rtx x1 = XEXP (x, 1);
+                 unsigned HOST_WIDE_INT value1 = XINT (x1, 2);
+                 unsigned HOST_WIDE_INT value2 = XINT (x1, 3);
+
+                 for (nbits = 0; value1 != 0; value1 &= value1 - 1)
+                   nbits++;
+                 for (; value2 != 0; value2 &= value2 - 1)
+                   nbits++;
+               }
              else
-               *total = COSTS_N_INSNS (12);
-             return true;
+               nbits = 7;
 
-           default:
-             *total = COSTS_N_INSNS (7);
-             return true;
+             if (nbits < 3)
+               nbits = 3;
+             bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
+             bit_cost = COSTS_N_INSNS (bit_cost);
            }
+
+         if (mode == DImode)
+           *total = sparc_costs->int_mulX + bit_cost;
+         else
+           *total = sparc_costs->int_mul + bit_cost;
        }
+      return false;
 
-      if (sparc_cpu == PROCESSOR_ULTRASPARC)
-       *total = (GET_MODE (x) == DImode
-                 ? COSTS_N_INSNS (68) : COSTS_N_INSNS (37));
-      else if (sparc_cpu == PROCESSOR_ULTRASPARC3)
-       *total = (GET_MODE (x) == DImode
-                 ? COSTS_N_INSNS (71) : COSTS_N_INSNS (40));
-      else
-       *total = COSTS_N_INSNS (25);
-      return true;
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+      *total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty;
+      return false;
 
-    case IF_THEN_ELSE:
-      /* Conditional moves. */
-      switch (sparc_cpu)
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      if (float_mode_p)
        {
-       case PROCESSOR_ULTRASPARC:
-         *total = COSTS_N_INSNS (2);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (FLOAT_MODE_P (GET_MODE (x)))
-           *total = COSTS_N_INSNS (3);
+         if (mode == DFmode)
+           *total = sparc_costs->float_div_df;
          else
-           *total = COSTS_N_INSNS (2);
-         return true;
-
-       default:
-         *total = COSTS_N_INSNS (1);
-         return true;
+           *total = sparc_costs->float_div_sf;
        }
-
-    case MEM:
-      /* If outer-code is SIGN/ZERO extension we have to subtract
-        out COSTS_N_INSNS (1) from whatever we return in determining
-        the cost.  */
-      switch (sparc_cpu)
+      else
        {
-       case PROCESSOR_ULTRASPARC:
-         if (outer_code == ZERO_EXTEND)
-           *total = COSTS_N_INSNS (1);
+         if (mode == DImode)
+           *total = sparc_costs->int_divX;
          else
-           *total = COSTS_N_INSNS (2);
-         return true;
-
-       case PROCESSOR_ULTRASPARC3:
-         if (outer_code == ZERO_EXTEND)
-           {
-             if (GET_MODE (x) == QImode
-                 || GET_MODE (x) == HImode
-                 || outer_code == SIGN_EXTEND)
-               *total = COSTS_N_INSNS (2);
-             else
-               *total = COSTS_N_INSNS (1);
-           }
-         else
-           {
-             /* This handles sign extension (3 cycles)
-                and everything else (2 cycles).  */
-             *total = COSTS_N_INSNS (2);
-           }
-         return true;
-
-       case PROCESSOR_SUPERSPARC:
-         if (FLOAT_MODE_P (GET_MODE (x))
-             || outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (0);
-         else
-           *total = COSTS_N_INSNS (1);
-         return true;
-
-       case PROCESSOR_TSC701:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (2);
-         else
-           *total = COSTS_N_INSNS (3);
-         return true;
-         
-       case PROCESSOR_CYPRESS:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (1);
-         else
-           *total = COSTS_N_INSNS (2);
-         return true;
-         
-       case PROCESSOR_HYPERSPARC:
-       case PROCESSOR_SPARCLITE86X:
-       default:
-         if (outer_code == ZERO_EXTEND
-             || outer_code == SIGN_EXTEND)
-           *total = COSTS_N_INSNS (0);
-         else
-           *total = COSTS_N_INSNS (1);
-         return true;
+           *total = sparc_costs->int_div;
        }
+      return false;
 
-    case CONST_INT:
-      if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
+    case NEG:
+      if (! float_mode_p)
        {
-         *total = 0;
-         return true;
+         *total = COSTS_N_INSNS (1);
+         return false;
        }
       /* FALLTHRU */
 
-    case HIGH:
-      *total = 2;
-      return true;
+    case ABS:
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+      *total = sparc_costs->float_move;
+      return false;
 
-    case CONST:
-    case LABEL_REF:
-    case SYMBOL_REF:
-      *total = 4;
-      return true;
+    case SQRT:
+      if (mode == DFmode)
+       *total = sparc_costs->float_sqrt_df;
+      else
+       *total = sparc_costs->float_sqrt_sf;
+      return false;
 
-    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)))
-       *total = 0;
+    case COMPARE:
+      if (float_mode_p)
+       *total = sparc_costs->float_cmp;
       else
-       *total = 8;
-      return true;
+       *total = COSTS_N_INSNS (1);
+      return false;
+
+    case IF_THEN_ELSE:
+      if (float_mode_p)
+       *total = sparc_costs->float_cmove;
+      else
+       *total = sparc_costs->int_cmove;
+      return false;
 
     default:
       return false;
     }
 }
 
+/* Emit the sequence of insns SEQ while preserving the register REG.  */
+
+static void
+emit_and_preserve (rtx seq, rtx reg)
+{
+  rtx slot = gen_rtx_MEM (word_mode,
+                         plus_constant (stack_pointer_rtx, SPARC_STACK_BIAS));
+
+  emit_stack_pointer_decrement (GEN_INT (UNITS_PER_WORD));
+  emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
+  emit_insn (seq);
+  emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
+  emit_stack_pointer_increment (GEN_INT (UNITS_PER_WORD));
+}
+
 /* Output code to add DELTA to the first argument, and then jump to FUNCTION.
    Used for C++ multiple inheritance.  */
 
 static void
-sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
-     FILE *file;
-     tree thunk_fndecl ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT delta;
-     HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED;
-     tree function;
+sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
+                      HOST_WIDE_INT delta,
+                      HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                      tree function)
 {
-  rtx this, insn, funexp, delta_rtx, tmp;
+  rtx this, insn, funexp, delta_rtx;
+  unsigned int int_arg_first;
 
   reload_completed = 1;
+  epilogue_completed = 1;
   no_new_pseudos = 1;
-  current_function_uses_only_leaf_regs = 1;
+  reset_block_changes ();
+
+  emit_note (NOTE_INSN_PROLOGUE_END);
+
+  if (flag_delayed_branch)
+    {
+      /* 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;
+
+      /* This will cause final.c to invoke leaf_renumber_regs so we
+        must behave as if we were in a not-yet-leafified function.  */
+      int_arg_first = SPARC_INCOMING_INT_ARG_FIRST;
+    }
+  else
+    {
+      /* We will emit the sibcall manually below, so we will need to
+        manually spill non-leaf registers.  */
+      current_function_uses_only_leaf_regs = 0;
 
-  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+      /* We really are in a leaf function.  */
+      int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
+    }
 
   /* Find the "this" pointer.  Normally in %o0, but in ARCH64 if the function
      returns a structure, the structure return pointer is there instead.  */
-  if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
-    this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST + 1);
+  if (TARGET_ARCH64 && aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
+    this = gen_rtx_REG (Pmode, int_arg_first + 1);
   else
-    this = gen_rtx_REG (Pmode, SPARC_INCOMING_INT_ARG_FIRST);
+    this = gen_rtx_REG (Pmode, int_arg_first);
 
   /* Add DELTA.  When possible use a plain add, otherwise load it into
      a register first.  */
@@ -8605,15 +8587,23 @@ sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
   if (!SPARC_SIMM13_P (delta))
     {
       rtx scratch = gen_rtx_REG (Pmode, 1);
-      if (TARGET_ARCH64)
-       sparc_emit_set_const64 (scratch, delta_rtx);
+
+      if (input_operand (delta_rtx, GET_MODE (scratch)))
+       emit_insn (gen_rtx_SET (VOIDmode, scratch, delta_rtx));
       else
-       sparc_emit_set_const32 (scratch, delta_rtx);
+       {
+         if (TARGET_ARCH64)
+           sparc_emit_set_const64 (scratch, delta_rtx);
+         else
+           sparc_emit_set_const32 (scratch, delta_rtx);
+       }
+
       delta_rtx = scratch;
     }
 
-  tmp = gen_rtx_PLUS (Pmode, this, delta_rtx);
-  emit_insn (gen_rtx_SET (VOIDmode, this, tmp));
+  emit_insn (gen_rtx_SET (VOIDmode,
+                         this,
+                         gen_rtx_PLUS (Pmode, this, delta_rtx)));
 
   /* Generate a tail call to the target function.  */
   if (! TREE_USED (function))
@@ -8622,9 +8612,67 @@ sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
       TREE_USED (function) = 1;
     }
   funexp = XEXP (DECL_RTL (function), 0);
-  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
-  insn = emit_call_insn (gen_sibcall (funexp));
-  SIBLING_CALL_P (insn) = 1;
+
+  if (flag_delayed_branch)
+    {
+      funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+      insn = emit_call_insn (gen_sibcall (funexp));
+      SIBLING_CALL_P (insn) = 1;
+    }
+  else
+    {
+      /* 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);
+
+      if (flag_pic)
+        {
+         spill_reg = gen_rtx_REG (word_mode, 15);  /* %o7 */
+         start_sequence ();
+         load_pic_register ();  /* clobbers %o7 */
+         scratch = legitimize_pic_address (funexp, Pmode, scratch);
+         seq = get_insns ();
+         end_sequence ();
+         emit_and_preserve (seq, spill_reg);
+       }
+      else if (TARGET_ARCH32)
+       {
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 scratch,
+                                 gen_rtx_HIGH (SImode, funexp)));
+         emit_insn (gen_rtx_SET (VOIDmode,
+                                 scratch,
+                                 gen_rtx_LO_SUM (SImode, scratch, funexp)));
+       }
+      else  /* TARGET_ARCH64 */
+        {
+         switch (sparc_cmodel)
+           {
+           case CM_MEDLOW:
+           case CM_MEDMID:
+             /* The destination can serve as a temporary.  */
+             sparc_emit_set_symbolic_const64 (scratch, funexp, scratch);
+             break;
+
+           case CM_MEDANY:
+           case CM_EMBMEDANY:
+             /* The destination cannot serve as a temporary.  */
+             spill_reg = gen_rtx_REG (DImode, 15);  /* %o7 */
+             start_sequence ();
+             sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
+             seq = get_insns ();
+             end_sequence ();
+             emit_and_preserve (seq, spill_reg);
+             break;
+
+           default:
+             abort();
+           }
+       }
+
+      emit_jump_insn (gen_indirect_jump (scratch));
+    }
+
   emit_barrier ();
 
   /* Run just enough of rest_of_compilation to get the insns emitted.
@@ -8632,13 +8680,79 @@ sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function)
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
+  insn_locators_initialize ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1, 0);
   final_end_function ();
 
   reload_completed = 0;
+  epilogue_completed = 0;
   no_new_pseudos = 0;
 }
 
+/* How to allocate a 'struct machine_function'.  */
+
+static struct machine_function *
+sparc_init_machine_status (void)
+{
+  return ggc_alloc_cleared (sizeof (struct machine_function));
+}
+
+/* Locate some local-dynamic symbol still in use by this function
+   so that we can print its name in local-dynamic base patterns.  */
+
+static const char *
+get_some_local_dynamic_name (void)
+{
+  rtx insn;
+
+  if (cfun->machine->some_ld_name)
+    return cfun->machine->some_ld_name;
+
+  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+      return cfun->machine->some_ld_name;
+
+  abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x = *px;
+
+  if (x
+      && GET_CODE (x) == SYMBOL_REF
+      && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
+    {
+      cfun->machine->some_ld_name = XSTR (x, 0);
+      return 1;
+    }
+
+  return 0;
+}
+
+/* This is called from dwarf2out.c via ASM_OUTPUT_DWARF_DTPREL.
+   We need to emit DTP-relative relocations.  */
+
+void
+sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
+{
+  switch (size)
+    {
+    case 4:
+      fputs ("\t.word\t%r_tls_dtpoff32(", file);
+      break;
+    case 8:
+      fputs ("\t.xword\t%r_tls_dtpoff64(", file);
+      break;
+    default:
+      abort ();
+    }
+  output_addr_const (file, x);
+  fputs (")", file);
+}
+
 #include "gt-sparc.h"